feat: 添加vscode编辑器

This commit is contained in:
dhx
2022-09-29 16:48:09 +08:00
parent a93bdac4ff
commit 150898ec1e
1126 changed files with 933348 additions and 0 deletions
@@ -0,0 +1,237 @@
/*---------------------------------------------------------------------------------------------
* 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); }
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { toErrorMessage } from '../../../base/common/errorMessage.js';
import { isCancellationError } from '../../../base/common/errors.js';
import { matchesContiguousSubString, matchesPrefix, matchesWords, or } from '../../../base/common/filters.js';
import { Disposable } from '../../../base/common/lifecycle.js';
import { LRUCache } from '../../../base/common/map.js';
import Severity from '../../../base/common/severity.js';
import { withNullAsUndefined } from '../../../base/common/types.js';
import { localize } from '../../../nls.js';
import { ICommandService } from '../../commands/common/commands.js';
import { IConfigurationService } from '../../configuration/common/configuration.js';
import { IDialogService } from '../../dialogs/common/dialogs.js';
import { IInstantiationService } from '../../instantiation/common/instantiation.js';
import { IKeybindingService } from '../../keybinding/common/keybinding.js';
import { PickerQuickAccessProvider } from './pickerQuickAccess.js';
import { IStorageService } from '../../storage/common/storage.js';
import { ITelemetryService } from '../../telemetry/common/telemetry.js';
let AbstractCommandsQuickAccessProvider = class AbstractCommandsQuickAccessProvider extends PickerQuickAccessProvider {
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.commandsHistory = this._register(this.instantiationService.createInstance(CommandsHistory));
this.options = options;
}
_getPicks(filter, disposables, token) {
return __awaiter(this, void 0, void 0, function* () {
// Ask subclass for all command picks
const allCommandPicks = yield this.getCommandPicks(disposables, 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(Object.assign(Object.assign({}, commandPick), { ariaLabel, detail: this.options.showAlias && commandPick.commandAlias !== commandPick.label ? commandPick.commandAlias : undefined, keybinding, accept: () => __awaiter(this, void 0, void 0, function* () {
// Add to history
this.commandsHistory.push(commandPick.commandId);
// Telementry
this.telemetryService.publicLog2('workbenchActionExecuted', {
id: commandPick.commandId,
from: 'quick open'
});
// Run
try {
yield 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.PREFIX = '>';
AbstractCommandsQuickAccessProvider.WORD_FILTER = or(matchesPrefix, matchesWords, matchesContiguousSubString);
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 {
constructor(storageService, configurationService) {
super();
this.storageService = storageService;
this.configurationService = configurationService;
this.configuredCommandsHistoryLength = 0;
this.updateConfiguration();
this.load();
this.registerListeners();
}
registerListeners() {
this._register(this.configurationService.onDidChangeConfiguration(() => this.updateConfiguration()));
}
updateConfiguration() {
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) {
var _a;
return (_a = CommandsHistory.cache) === null || _a === void 0 ? void 0 : _a.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) {
var _a, _b;
const config = configurationService.getValue();
const configuredCommandHistoryLength = (_b = (_a = config.workbench) === null || _a === void 0 ? void 0 : _a.commandPalette) === null || _b === void 0 ? void 0 : _b.history;
if (typeof configuredCommandHistoryLength === 'number') {
return configuredCommandHistoryLength;
}
return CommandsHistory.DEFAULT_COMMANDS_HISTORY_LENGTH;
}
};
CommandsHistory.DEFAULT_COMMANDS_HISTORY_LENGTH = 50;
CommandsHistory.PREF_KEY_CACHE = 'commandPalette.mru.cache';
CommandsHistory.PREF_KEY_COUNTER = 'commandPalette.mru.counter';
CommandsHistory.counter = 1;
CommandsHistory = __decorate([
__param(0, IStorageService),
__param(1, IConfigurationService)
], CommandsHistory);
export { CommandsHistory };
@@ -0,0 +1,73 @@
/*---------------------------------------------------------------------------------------------
* 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 { localize } from '../../../nls.js';
import { Registry } from '../../registry/common/platform.js';
import { DisposableStore } from '../../../base/common/lifecycle.js';
import { IKeybindingService } from '../../keybinding/common/keybinding.js';
import { Extensions } from '../common/quickAccess.js';
import { IQuickInputService } from '../common/quickInput.js';
let HelpQuickAccessProvider = class HelpQuickAccessProvider {
constructor(quickInputService, keybindingService) {
this.quickInputService = quickInputService;
this.keybindingService = keybindingService;
this.registry = Registry.as(Extensions.Quickaccess);
}
provide(picker) {
const disposables = new DisposableStore();
// Open a picker with the selected value if picked
disposables.add(picker.onDidAccept(() => {
const [item] = picker.selectedItems;
if (item) {
this.quickInputService.quickAccess.show(item.prefix, { preserveValue: true });
}
}));
// Also open a picker when we detect the user typed the exact
// name of a provider (e.g. `?term` for terminals)
disposables.add(picker.onDidChangeValue(value => {
const providerDescriptor = this.registry.getQuickAccessProvider(value.substr(HelpQuickAccessProvider.PREFIX.length));
if (providerDescriptor && providerDescriptor.prefix && providerDescriptor.prefix !== HelpQuickAccessProvider.PREFIX) {
this.quickInputService.quickAccess.show(providerDescriptor.prefix, { preserveValue: true });
}
}));
// Fill in all providers
picker.items = this.getQuickAccessProviders();
return disposables;
}
getQuickAccessProviders() {
const providers = [];
for (const provider of this.registry.getQuickAccessProviders().sort((providerA, providerB) => providerA.prefix.localeCompare(providerB.prefix))) {
if (provider.prefix === HelpQuickAccessProvider.PREFIX) {
continue; // exclude help which is already active
}
for (const helpEntry of provider.helpEntries) {
const prefix = helpEntry.prefix || provider.prefix;
const label = prefix || '\u2026' /* ... */;
providers.push({
prefix,
label,
keybinding: helpEntry.commandId ? this.keybindingService.lookupKeybinding(helpEntry.commandId) : undefined,
ariaLabel: localize('helpPickAriaLabel', "{0}, {1}", label, helpEntry.description),
description: helpEntry.description
});
}
}
return providers;
}
};
HelpQuickAccessProvider.PREFIX = '?';
HelpQuickAccessProvider = __decorate([
__param(0, IQuickInputService),
__param(1, IKeybindingService)
], HelpQuickAccessProvider);
export { HelpQuickAccessProvider };
@@ -0,0 +1,251 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { timeout } from '../../../base/common/async.js';
import { CancellationTokenSource } from '../../../base/common/cancellation.js';
import { Disposable, DisposableStore, MutableDisposable } from '../../../base/common/lifecycle.js';
export var TriggerAction;
(function (TriggerAction) {
/**
* Do nothing after the button was clicked.
*/
TriggerAction[TriggerAction["NO_ACTION"] = 0] = "NO_ACTION";
/**
* Close the picker.
*/
TriggerAction[TriggerAction["CLOSE_PICKER"] = 1] = "CLOSE_PICKER";
/**
* Update the results of the picker.
*/
TriggerAction[TriggerAction["REFRESH_PICKER"] = 2] = "REFRESH_PICKER";
/**
* Remove the item from the picker.
*/
TriggerAction[TriggerAction["REMOVE_ITEM"] = 3] = "REMOVE_ITEM";
})(TriggerAction || (TriggerAction = {}));
function isPicksWithActive(obj) {
const candidate = obj;
return Array.isArray(candidate.items);
}
function isFastAndSlowPicks(obj) {
const candidate = obj;
return !!candidate.picks && candidate.additionalPicks instanceof Promise;
}
export class PickerQuickAccessProvider extends Disposable {
constructor(prefix, options) {
super();
this.prefix = prefix;
this.options = options;
}
provide(picker, token) {
var _a;
const disposables = new DisposableStore();
// Apply options if any
picker.canAcceptInBackground = !!((_a = this.options) === null || _a === void 0 ? void 0 : _a.canAcceptInBackground);
// Disable filtering & sorting, we control the results
picker.matchOnLabel = picker.matchOnDescription = picker.matchOnDetail = picker.sortByLabel = false;
// Set initial picks and update on type
let picksCts = undefined;
const picksDisposable = disposables.add(new MutableDisposable());
const updatePickerItems = () => __awaiter(this, void 0, void 0, function* () {
const picksDisposables = picksDisposable.value = new DisposableStore();
// Cancel any previous ask for picks and busy
picksCts === null || picksCts === void 0 ? void 0 : picksCts.dispose(true);
picker.busy = false;
// Create new cancellation source for this run
picksCts = new CancellationTokenSource(token);
// Collect picks and support both long running and short or combined
const picksToken = picksCts.token;
const picksFilter = picker.value.substr(this.prefix.length).trim();
const providedPicks = this._getPicks(picksFilter, picksDisposables, picksToken);
const applyPicks = (picks, skipEmpty) => {
var _a;
let items;
let activeItem = undefined;
if (isPicksWithActive(picks)) {
items = picks.items;
activeItem = picks.active;
}
else {
items = picks;
}
if (items.length === 0) {
if (skipEmpty) {
return false;
}
if (picksFilter.length > 0 && ((_a = this.options) === null || _a === void 0 ? void 0 : _a.noResultsPick)) {
items = [this.options.noResultsPick];
}
}
picker.items = items;
if (activeItem) {
picker.activeItems = [activeItem];
}
return true;
};
// No Picks
if (providedPicks === null) {
// Ignore
}
// Fast and Slow Picks
else if (isFastAndSlowPicks(providedPicks)) {
let fastPicksApplied = false;
let slowPicksApplied = false;
yield Promise.all([
// Fast Picks: to reduce amount of flicker, we race against
// the slow picks over 500ms and then set the fast picks.
// If the slow picks are faster, we reduce the flicker by
// only setting the items once.
(() => __awaiter(this, void 0, void 0, function* () {
yield timeout(PickerQuickAccessProvider.FAST_PICKS_RACE_DELAY);
if (picksToken.isCancellationRequested) {
return;
}
if (!slowPicksApplied) {
fastPicksApplied = applyPicks(providedPicks.picks, true /* skip over empty to reduce flicker */);
}
}))(),
// Slow Picks: we await the slow picks and then set them at
// once together with the fast picks, but only if we actually
// have additional results.
(() => __awaiter(this, void 0, void 0, function* () {
picker.busy = true;
try {
const awaitedAdditionalPicks = yield providedPicks.additionalPicks;
if (picksToken.isCancellationRequested) {
return;
}
let picks;
let activePick = undefined;
if (isPicksWithActive(providedPicks.picks)) {
picks = providedPicks.picks.items;
activePick = providedPicks.picks.active;
}
else {
picks = providedPicks.picks;
}
let additionalPicks;
let additionalActivePick = undefined;
if (isPicksWithActive(awaitedAdditionalPicks)) {
additionalPicks = awaitedAdditionalPicks.items;
additionalActivePick = awaitedAdditionalPicks.active;
}
else {
additionalPicks = awaitedAdditionalPicks;
}
if (additionalPicks.length > 0 || !fastPicksApplied) {
// If we do not have any activePick or additionalActivePick
// we try to preserve the currently active pick from the
// fast results. This fixes an issue where the user might
// have made a pick active before the additional results
// kick in.
// See https://github.com/microsoft/vscode/issues/102480
let fallbackActivePick = undefined;
if (!activePick && !additionalActivePick) {
const fallbackActivePickCandidate = picker.activeItems[0];
if (fallbackActivePickCandidate && picks.indexOf(fallbackActivePickCandidate) !== -1) {
fallbackActivePick = fallbackActivePickCandidate;
}
}
applyPicks({
items: [...picks, ...additionalPicks],
active: activePick || additionalActivePick || fallbackActivePick
});
}
}
finally {
if (!picksToken.isCancellationRequested) {
picker.busy = false;
}
slowPicksApplied = true;
}
}))()
]);
}
// Fast Picks
else if (!(providedPicks instanceof Promise)) {
applyPicks(providedPicks);
}
// Slow Picks
else {
picker.busy = true;
try {
const awaitedPicks = yield providedPicks;
if (picksToken.isCancellationRequested) {
return;
}
applyPicks(awaitedPicks);
}
finally {
if (!picksToken.isCancellationRequested) {
picker.busy = false;
}
}
}
});
disposables.add(picker.onDidChangeValue(() => updatePickerItems()));
updatePickerItems();
// Accept the pick on accept and hide picker
disposables.add(picker.onDidAccept(event => {
const [item] = picker.selectedItems;
if (typeof (item === null || item === void 0 ? void 0 : item.accept) === 'function') {
if (!event.inBackground) {
picker.hide(); // hide picker unless we accept in background
}
item.accept(picker.keyMods, event);
}
}));
// Trigger the pick with button index if button triggered
disposables.add(picker.onDidTriggerItemButton(({ button, item }) => __awaiter(this, void 0, void 0, function* () {
var _b, _c;
if (typeof item.trigger === 'function') {
const buttonIndex = (_c = (_b = item.buttons) === null || _b === void 0 ? void 0 : _b.indexOf(button)) !== null && _c !== void 0 ? _c : -1;
if (buttonIndex >= 0) {
const result = item.trigger(buttonIndex, picker.keyMods);
const action = (typeof result === 'number') ? result : yield result;
if (token.isCancellationRequested) {
return;
}
switch (action) {
case TriggerAction.NO_ACTION:
break;
case TriggerAction.CLOSE_PICKER:
picker.hide();
break;
case TriggerAction.REFRESH_PICKER:
updatePickerItems();
break;
case TriggerAction.REMOVE_ITEM: {
const index = picker.items.indexOf(item);
if (index !== -1) {
const items = picker.items.slice();
const removed = items.splice(index, 1);
const activeItems = picker.activeItems.filter(activeItem => activeItem !== removed[0]);
const keepScrollPositionBefore = picker.keepScrollPosition;
picker.keepScrollPosition = true;
picker.items = items;
if (activeItems) {
picker.activeItems = activeItems;
}
picker.keepScrollPosition = keepScrollPositionBefore;
}
break;
}
}
}
}
})));
return disposables;
}
}
PickerQuickAccessProvider.FAST_PICKS_RACE_DELAY = 200; // timeout before we accept fast results before slow results are present
@@ -0,0 +1,191 @@
/*---------------------------------------------------------------------------------------------
* 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 { DeferredPromise } from '../../../base/common/async.js';
import { CancellationTokenSource } from '../../../base/common/cancellation.js';
import { once } from '../../../base/common/functional.js';
import { Disposable, DisposableStore, toDisposable } from '../../../base/common/lifecycle.js';
import { IInstantiationService } from '../../instantiation/common/instantiation.js';
import { DefaultQuickAccessFilterValue, Extensions } from '../common/quickAccess.js';
import { IQuickInputService, ItemActivation } from '../common/quickInput.js';
import { Registry } from '../../registry/common/platform.js';
let QuickAccessController = class QuickAccessController extends Disposable {
constructor(quickInputService, instantiationService) {
super();
this.quickInputService = quickInputService;
this.instantiationService = instantiationService;
this.registry = Registry.as(Extensions.Quickaccess);
this.mapProviderToDescriptor = new Map();
this.lastAcceptedPickerValues = new Map();
this.visibleQuickAccess = undefined;
}
show(value = '', options) {
this.doShowOrPick(value, false, options);
}
doShowOrPick(value, pick, options) {
var _a;
// Find provider for the value to show
const [provider, descriptor] = this.getOrInstantiateProvider(value);
// Return early if quick access is already showing on that same prefix
const visibleQuickAccess = this.visibleQuickAccess;
const visibleDescriptor = visibleQuickAccess === null || visibleQuickAccess === void 0 ? void 0 : visibleQuickAccess.descriptor;
if (visibleQuickAccess && descriptor && visibleDescriptor === descriptor) {
// Apply value only if it is more specific than the prefix
// from the provider and we are not instructed to preserve
if (value !== descriptor.prefix && !(options === null || options === void 0 ? void 0 : options.preserveValue)) {
visibleQuickAccess.picker.value = value;
}
// Always adjust selection
this.adjustValueSelection(visibleQuickAccess.picker, descriptor, options);
return;
}
// Rewrite the filter value based on certain rules unless disabled
if (descriptor && !(options === null || options === void 0 ? void 0 : options.preserveValue)) {
let newValue = undefined;
// If we have a visible provider with a value, take it's filter value but
// rewrite to new provider prefix in case they differ
if (visibleQuickAccess && visibleDescriptor && visibleDescriptor !== descriptor) {
const newValueCandidateWithoutPrefix = visibleQuickAccess.value.substr(visibleDescriptor.prefix.length);
if (newValueCandidateWithoutPrefix) {
newValue = `${descriptor.prefix}${newValueCandidateWithoutPrefix}`;
}
}
// Otherwise, take a default value as instructed
if (!newValue) {
const defaultFilterValue = provider === null || provider === void 0 ? void 0 : provider.defaultFilterValue;
if (defaultFilterValue === DefaultQuickAccessFilterValue.LAST) {
newValue = this.lastAcceptedPickerValues.get(descriptor);
}
else if (typeof defaultFilterValue === 'string') {
newValue = `${descriptor.prefix}${defaultFilterValue}`;
}
}
if (typeof newValue === 'string') {
value = newValue;
}
}
// Create a picker for the provider to use with the initial value
// and adjust the filtering to exclude the prefix from filtering
const disposables = new DisposableStore();
const picker = disposables.add(this.quickInputService.createQuickPick());
picker.value = value;
this.adjustValueSelection(picker, descriptor, options);
picker.placeholder = descriptor === null || descriptor === void 0 ? void 0 : descriptor.placeholder;
picker.quickNavigate = options === null || options === void 0 ? void 0 : options.quickNavigateConfiguration;
picker.hideInput = !!picker.quickNavigate && !visibleQuickAccess; // only hide input if there was no picker opened already
if (typeof (options === null || options === void 0 ? void 0 : options.itemActivation) === 'number' || (options === null || options === void 0 ? void 0 : options.quickNavigateConfiguration)) {
picker.itemActivation = (_a = options === null || options === void 0 ? void 0 : options.itemActivation) !== null && _a !== void 0 ? _a : ItemActivation.SECOND /* quick nav is always second */;
}
picker.contextKey = descriptor === null || descriptor === void 0 ? void 0 : descriptor.contextKey;
picker.filterValue = (value) => value.substring(descriptor ? descriptor.prefix.length : 0);
if (descriptor === null || descriptor === void 0 ? void 0 : descriptor.placeholder) {
picker.ariaLabel = descriptor === null || descriptor === void 0 ? void 0 : descriptor.placeholder;
}
// Pick mode: setup a promise that can be resolved
// with the selected items and prevent execution
let pickPromise = undefined;
if (pick) {
pickPromise = new DeferredPromise();
disposables.add(once(picker.onWillAccept)(e => {
e.veto();
picker.hide();
}));
}
// Register listeners
disposables.add(this.registerPickerListeners(picker, provider, descriptor, value));
// Ask provider to fill the picker as needed if we have one
// and pass over a cancellation token that will indicate when
// the picker is hiding without a pick being made.
const cts = disposables.add(new CancellationTokenSource());
if (provider) {
disposables.add(provider.provide(picker, cts.token));
}
// Finally, trigger disposal and cancellation when the picker
// hides depending on items selected or not.
once(picker.onDidHide)(() => {
if (picker.selectedItems.length === 0) {
cts.cancel();
}
// Start to dispose once picker hides
disposables.dispose();
// Resolve pick promise with selected items
pickPromise === null || pickPromise === void 0 ? void 0 : pickPromise.complete(picker.selectedItems.slice(0));
});
// Finally, show the picker. This is important because a provider
// may not call this and then our disposables would leak that rely
// on the onDidHide event.
picker.show();
// Pick mode: return with promise
if (pick) {
return pickPromise === null || pickPromise === void 0 ? void 0 : pickPromise.p;
}
}
adjustValueSelection(picker, descriptor, options) {
var _a;
let valueSelection;
// Preserve: just always put the cursor at the end
if (options === null || options === void 0 ? void 0 : options.preserveValue) {
valueSelection = [picker.value.length, picker.value.length];
}
// Otherwise: select the value up until the prefix
else {
valueSelection = [(_a = descriptor === null || descriptor === void 0 ? void 0 : descriptor.prefix.length) !== null && _a !== void 0 ? _a : 0, picker.value.length];
}
picker.valueSelection = valueSelection;
}
registerPickerListeners(picker, provider, descriptor, value) {
const disposables = new DisposableStore();
// Remember as last visible picker and clean up once picker get's disposed
const visibleQuickAccess = this.visibleQuickAccess = { picker, descriptor, value };
disposables.add(toDisposable(() => {
if (visibleQuickAccess === this.visibleQuickAccess) {
this.visibleQuickAccess = undefined;
}
}));
// Whenever the value changes, check if the provider has
// changed and if so - re-create the picker from the beginning
disposables.add(picker.onDidChangeValue(value => {
const [providerForValue] = this.getOrInstantiateProvider(value);
if (providerForValue !== provider) {
this.show(value, { preserveValue: true } /* do not rewrite value from user typing! */);
}
else {
visibleQuickAccess.value = value; // remember the value in our visible one
}
}));
// Remember picker input for future use when accepting
if (descriptor) {
disposables.add(picker.onDidAccept(() => {
this.lastAcceptedPickerValues.set(descriptor, picker.value);
}));
}
return disposables;
}
getOrInstantiateProvider(value) {
const providerDescriptor = this.registry.getQuickAccessProvider(value);
if (!providerDescriptor) {
return [undefined, undefined];
}
let provider = this.mapProviderToDescriptor.get(providerDescriptor);
if (!provider) {
provider = this.instantiationService.createInstance(providerDescriptor.ctor);
this.mapProviderToDescriptor.set(providerDescriptor, provider);
}
return [provider, providerDescriptor];
}
};
QuickAccessController = __decorate([
__param(0, IQuickInputService),
__param(1, IInstantiationService)
], QuickAccessController);
export { QuickAccessController };
@@ -0,0 +1,164 @@
/*---------------------------------------------------------------------------------------------
* 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 { CancellationToken } from '../../../base/common/cancellation.js';
import { QuickInputController } from '../../../base/parts/quickinput/browser/quickInput.js';
import { IAccessibilityService } from '../../accessibility/common/accessibility.js';
import { IContextKeyService, RawContextKey } from '../../contextkey/common/contextkey.js';
import { IInstantiationService } from '../../instantiation/common/instantiation.js';
import { ILayoutService } from '../../layout/browser/layoutService.js';
import { WorkbenchList } from '../../list/browser/listService.js';
import { QuickAccessController } from './quickAccess.js';
import { activeContrastBorder, badgeBackground, badgeForeground, buttonBackground, buttonForeground, buttonHoverBackground, contrastBorder, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, keybindingLabelBackground, keybindingLabelBorder, keybindingLabelBottomBorder, keybindingLabelForeground, pickerGroupBorder, pickerGroupForeground, progressBarBackground, quickInputBackground, quickInputForeground, quickInputListFocusBackground, quickInputListFocusForeground, quickInputListFocusIconForeground, quickInputTitleBackground, widgetShadow } from '../../theme/common/colorRegistry.js';
import { computeStyles } from '../../theme/common/styler.js';
import { IThemeService, Themable } from '../../theme/common/themeService.js';
let QuickInputService = class QuickInputService extends Themable {
constructor(instantiationService, contextKeyService, themeService, accessibilityService, layoutService) {
super(themeService);
this.instantiationService = instantiationService;
this.contextKeyService = contextKeyService;
this.accessibilityService = accessibilityService;
this.layoutService = layoutService;
this.contexts = new Map();
}
get controller() {
if (!this._controller) {
this._controller = this._register(this.createController());
}
return this._controller;
}
get quickAccess() {
if (!this._quickAccess) {
this._quickAccess = this._register(this.instantiationService.createInstance(QuickAccessController));
}
return this._quickAccess;
}
createController(host = this.layoutService, options) {
const defaultOptions = {
idPrefix: 'quickInput_',
container: host.container,
ignoreFocusOut: () => false,
isScreenReaderOptimized: () => this.accessibilityService.isScreenReaderOptimized(),
backKeybindingLabel: () => undefined,
setContextKey: (id) => this.setContextKey(id),
returnFocus: () => host.focus(),
createList: (user, container, delegate, renderers, options) => this.instantiationService.createInstance(WorkbenchList, user, container, delegate, renderers, options),
styles: this.computeStyles()
};
const controller = this._register(new QuickInputController(Object.assign(Object.assign({}, defaultOptions), options)));
controller.layout(host.dimension, host.offset.quickPickTop);
// Layout changes
this._register(host.onDidLayout(dimension => controller.layout(dimension, host.offset.quickPickTop)));
// Context keys
this._register(controller.onShow(() => this.resetContextKeys()));
this._register(controller.onHide(() => this.resetContextKeys()));
return controller;
}
setContextKey(id) {
let key;
if (id) {
key = this.contexts.get(id);
if (!key) {
key = new RawContextKey(id, false)
.bindTo(this.contextKeyService);
this.contexts.set(id, key);
}
}
if (key && key.get()) {
return; // already active context
}
this.resetContextKeys();
key === null || key === void 0 ? void 0 : key.set(true);
}
resetContextKeys() {
this.contexts.forEach(context => {
if (context.get()) {
context.reset();
}
});
}
pick(picks, options = {}, token = CancellationToken.None) {
return this.controller.pick(picks, options, token);
}
createQuickPick() {
return this.controller.createQuickPick();
}
updateStyles() {
this.controller.applyStyles(this.computeStyles());
}
computeStyles() {
return {
widget: Object.assign({}, computeStyles(this.theme, {
quickInputBackground,
quickInputForeground,
quickInputTitleBackground,
contrastBorder,
widgetShadow
})),
inputBox: computeStyles(this.theme, {
inputForeground,
inputBackground,
inputBorder,
inputValidationInfoBackground,
inputValidationInfoForeground,
inputValidationInfoBorder,
inputValidationWarningBackground,
inputValidationWarningForeground,
inputValidationWarningBorder,
inputValidationErrorBackground,
inputValidationErrorForeground,
inputValidationErrorBorder
}),
countBadge: computeStyles(this.theme, {
badgeBackground,
badgeForeground,
badgeBorder: contrastBorder
}),
button: computeStyles(this.theme, {
buttonForeground,
buttonBackground,
buttonHoverBackground,
buttonBorder: contrastBorder
}),
progressBar: computeStyles(this.theme, {
progressBarBackground
}),
keybindingLabel: computeStyles(this.theme, {
keybindingLabelBackground,
keybindingLabelForeground,
keybindingLabelBorder,
keybindingLabelBottomBorder,
keybindingLabelShadow: widgetShadow
}),
list: computeStyles(this.theme, {
listBackground: quickInputBackground,
// Look like focused when inactive.
listInactiveFocusForeground: quickInputListFocusForeground,
listInactiveSelectionIconForeground: quickInputListFocusIconForeground,
listInactiveFocusBackground: quickInputListFocusBackground,
listFocusOutline: activeContrastBorder,
listInactiveFocusOutline: activeContrastBorder,
pickerGroupBorder,
pickerGroupForeground
})
};
}
};
QuickInputService = __decorate([
__param(0, IInstantiationService),
__param(1, IContextKeyService),
__param(2, IThemeService),
__param(3, IAccessibilityService),
__param(4, ILayoutService)
], QuickInputService);
export { QuickInputService };