feat: 添加vscode编辑器
This commit is contained in:
@@ -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 };
|
||||
Reference in New Issue
Block a user