Merge branch 'main' into merogge/select

This commit is contained in:
Megan Rogge
2023-04-04 15:03:51 -07:00
committed by GitHub
34 changed files with 560 additions and 473 deletions
+5 -5
View File
@@ -21,16 +21,16 @@ fsevents/test/**
@vscode/sqlite3/src/**
!@vscode/sqlite3/build/Release/*.node
@vscode/windows-mutex/binding.gyp
@vscode/windows-mutex/build/**
@vscode/windows-mutex/src/**
!@vscode/windows-mutex/**/*.node
@vscode/windows-registry/binding.gyp
@vscode/windows-registry/src/**
@vscode/windows-registry/build/**
!@vscode/windows-registry/build/Release/*.node
windows-mutex/binding.gyp
windows-mutex/build/**
windows-mutex/src/**
!windows-mutex/**/*.node
native-keymap/binding.gyp
native-keymap/build/**
native-keymap/src/**
+4 -4
View File
@@ -96,7 +96,7 @@ jobs:
- job: Windowsx64UnitTests
displayName: Windows (Unit Tests)
pool: 1es-oss-windows-2022-x64
pool: 1es-oss-windows-2019-x64
timeoutInMinutes: 30
variables:
VSCODE_ARCH: x64
@@ -112,7 +112,7 @@ jobs:
- job: Windowsx64IntegrationTests
displayName: Windows (Integration Tests)
pool: 1es-oss-windows-2022-x64
pool: 1es-oss-windows-2019-x64
timeoutInMinutes: 30
variables:
VSCODE_ARCH: x64
@@ -128,7 +128,7 @@ jobs:
# - job: Windowsx64SmokeTests
# displayName: Windows (Smoke Tests)
# pool: 1es-oss-windows-2022-x64
# pool: 1es-oss-windows-2019-x64
# timeoutInMinutes: 30
# variables:
# VSCODE_ARCH: x64
@@ -153,7 +153,7 @@ jobs:
- job: Windowsx64MaintainNodeModulesCache
displayName: Windows (Maintain node_modules cache)
pool: 1es-oss-windows-2022-x64
pool: 1es-oss-windows-2019-x64
timeoutInMinutes: 30
variables:
VSCODE_ARCH: x64
+1 -2
View File
@@ -5,7 +5,6 @@
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Manage Built-in Extensions</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="browser-main.js"></script>
@@ -43,4 +42,4 @@
<div id="extensions"></div>
</body>
</html>
</html>
+6 -1
View File
@@ -2360,7 +2360,12 @@ export class Repository implements Disposable {
private updateBranchProtectionMatcher(): void {
const scopedConfig = workspace.getConfiguration('git', Uri.file(this.repository.root));
const branchProtectionGlobs = scopedConfig.get<string[]>('branchProtection')!.map(bp => bp.trim()).filter(bp => bp !== '');
const branchProtectionConfig = scopedConfig.get<unknown>('branchProtection') ?? [];
const branchProtectionValues = Array.isArray(branchProtectionConfig) ? branchProtectionConfig : [branchProtectionConfig];
const branchProtectionGlobs = branchProtectionValues
.map(bp => typeof bp === 'string' ? bp.trim() : '')
.filter(bp => bp !== '');
if (branchProtectionGlobs.length === 0) {
this.isBranchProtectedMatcher = undefined;
-1
View File
@@ -27,7 +27,6 @@
},
"enabledApiProposals": [
"contribShareMenu",
"contribEditorLineNumberMenu",
"contribEditSessions"
],
"contributes": {
+1 -1
View File
@@ -17,7 +17,7 @@ async function copyVscodeDevLink(gitAPI: GitAPI, useSelection: boolean, context:
try {
const permalink = getLink(gitAPI, useSelection, getVscodeDevHost(), 'headlink', context, includeRange);
if (permalink) {
return vscode.env.clipboard.writeText(permalink);
return vscode.env.clipboard.writeText(encodeURI(permalink));
}
} catch (err) {
vscode.window.showErrorMessage(err.message);
+1 -2
View File
@@ -120,7 +120,6 @@
"@types/webpack": "^5.28.1",
"@types/wicg-file-system-access": "^2020.9.5",
"@types/windows-foreground-love": "^0.3.0",
"@types/windows-mutex": "^0.4.0",
"@types/windows-process-tree": "^0.2.0",
"@types/winreg": "^1.2.30",
"@types/yauzl": "^2.9.1",
@@ -230,9 +229,9 @@
"url": "https://github.com/microsoft/vscode/issues"
},
"optionalDependencies": {
"@vscode/windows-mutex": "0.4.2",
"@vscode/windows-registry": "1.0.6",
"windows-foreground-love": "0.5.0",
"windows-mutex": "0.4.1",
"windows-process-tree": "0.4.0"
},
"resolutions": {
@@ -3,6 +3,12 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// empty placeholder declaration for the `editor/lineNumber/context` menu contribution point
declare module '@vscode/windows-mutex' {
export class Mutex {
constructor(name: string);
isActive(): boolean;
release(): void;
}
// https://github.com/microsoft/vscode/issues/175945 @joyceerhl
export function isActive(name: string): boolean;
}
@@ -1,7 +1,6 @@
<!DOCTYPE html>
<html>
<head id='headID'>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Strada </title>
<link href="site.css" rel="stylesheet" type="text/css" />
<script src="jquery-1.4.1.js"></script>
+1 -1
View File
@@ -1221,7 +1221,7 @@ export class CodeApplication extends Disposable {
const win32MutexName = this.productService.win32MutexName;
if (isWindows && win32MutexName) {
try {
const WindowsMutex = await import('windows-mutex');
const WindowsMutex = await import('@vscode/windows-mutex');
const mutex = new WindowsMutex.Mutex(win32MutexName);
once(this.lifecycleMainService.onWillShutdown)(() => mutex.release());
} catch (error) {
+2 -1
View File
@@ -30,6 +30,7 @@ import { MarkerHoverParticipant } from 'vs/editor/contrib/hover/browser/markerHo
import 'vs/css!./hover';
import { InlineSuggestionHintsContentWidget } from 'vs/editor/contrib/inlineCompletions/browser/inlineSuggestionHintsWidget';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver';
export class ModesHoverController implements IEditorContribution {
@@ -205,7 +206,7 @@ export class ModesHoverController implements IEditorContribution {
const resolvedKeyboardEvent = this._keybindingService.softDispatch(e, this._editor.getDomNode());
// If the beginning of a multi-chord keybinding is pressed, or the command aims to focus the hover, set the variable to true, otherwise false
const mightTriggerFocus = (resolvedKeyboardEvent?.enterMultiChord || (resolvedKeyboardEvent?.commandId === 'editor.action.showHover' && this._contentWidget?.isVisible()));
const mightTriggerFocus = (resolvedKeyboardEvent?.kind === ResultKind.MoreChordsNeeded || (resolvedKeyboardEvent && resolvedKeyboardEvent.kind === ResultKind.KbFound && resolvedKeyboardEvent.commandId === 'editor.action.showHover' && this._contentWidget?.isVisible()));
if (e.keyCode !== KeyCode.Ctrl && e.keyCode !== KeyCode.Alt && e.keyCode !== KeyCode.Meta && e.keyCode !== KeyCode.Shift
&& !mightTriggerFocus) {
@@ -109,10 +109,10 @@ flakySuite('Native Modules (all platforms)', () => {
(!isWindows ? suite.skip : suite)('Native Modules (Windows)', () => {
(process.type === 'renderer' ? test.skip /* TODO@electron module is not context aware yet and thus cannot load in Electron renderer used by tests */ : test)('windows-mutex', async () => {
const mutex = await import('windows-mutex');
assert.ok(mutex && typeof mutex.isActive === 'function', testErrorMessage('windows-mutex'));
assert.ok(typeof mutex.isActive === 'function', testErrorMessage('windows-mutex'));
(process.type === 'renderer' ? test.skip /* TODO@electron module is not context aware yet and thus cannot load in Electron renderer used by tests */ : test)('@vscode/windows-mutex', async () => {
const mutex = await import('@vscode/windows-mutex');
assert.ok(mutex && typeof mutex.isActive === 'function', testErrorMessage('@vscode/windows-mutex'));
assert.ok(typeof mutex.isActive === 'function', testErrorMessage('@vscode/windows-mutex'));
});
test('windows-foreground-love', async () => {
@@ -1,7 +1,6 @@
<!DOCTYPE html>
<html>
<head id='headID'>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Strada </title>
<link href="site.css" rel="stylesheet" type="text/css" />
<script src="jquery-1.4.1.js"></script>
@@ -1,7 +1,6 @@
<!DOCTYPE html>
<html>
<head id='headID'>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Strada </title>
<link href="site.css" rel="stylesheet" type="text/css" />
<script src="jquery-1.4.1.js"></script>
@@ -6,6 +6,7 @@
import { WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions';
import * as arrays from 'vs/base/common/arrays';
import { IntervalTimer, TimeoutTimer } from 'vs/base/common/async';
import { illegalState } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { IME } from 'vs/base/common/ime';
import { KeyCode } from 'vs/base/common/keyCodes';
@@ -16,7 +17,7 @@ import * as nls from 'vs/nls';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';
import { IKeybindingService, IKeyboardEvent, KeybindingsSchemaContribution } from 'vs/platform/keybinding/common/keybinding';
import { IResolveResult, KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';
import { ResolutionResult, KeybindingResolver, ResultKind } from 'vs/platform/keybinding/common/keybindingResolver';
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
import { ILogService } from 'vs/platform/log/common/log';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -30,6 +31,7 @@ interface CurrentChord {
const HIGH_FREQ_COMMANDS = /^(cursor|delete|undo|redo|tab|editor\.action\.clipboard)/;
export abstract class AbstractKeybindingService extends Disposable implements IKeybindingService {
public _serviceBrand: undefined;
protected readonly _onDidUpdateKeybindings: Emitter<void> = this._register(new Emitter<void>());
@@ -44,7 +46,7 @@ export abstract class AbstractKeybindingService extends Disposable implements IK
* "cmd+k" would be stored in this array, when on pressing "cmd+i", the service
* would invoke the command bound by the keybinding
*/
private _currentChords: CurrentChord[] | null;
private _currentChords: CurrentChord[];
private _currentChordChecker: IntervalTimer;
private _currentChordStatusMessage: IDisposable | null;
@@ -55,7 +57,7 @@ export abstract class AbstractKeybindingService extends Disposable implements IK
protected _logging: boolean;
public get inChordMode(): boolean {
return !!this._currentChords;
return this._currentChords.length > 0;
}
constructor(
@@ -67,7 +69,7 @@ export abstract class AbstractKeybindingService extends Disposable implements IK
) {
super();
this._currentChords = null;
this._currentChords = [];
this._currentChordChecker = new IntervalTimer();
this._currentChordStatusMessage = null;
this._ignoreSingleModifiers = KeybindingModifierSet.EMPTY;
@@ -134,7 +136,9 @@ export abstract class AbstractKeybindingService extends Disposable implements IK
return this._dispatch(e, target);
}
public softDispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): IResolveResult | null {
// TODO@ulugbekna: update namings to align with `_doDispatch`
// TODO@ulugbekna: this fn doesn't seem to take into account single-modifier keybindings, eg `shift shift`
public softDispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): ResolutionResult | null {
this._log(`/ Soft dispatching keyboard event`);
const keybinding = this.resolveKeyboardEvent(e);
if (keybinding.hasMultipleChords()) {
@@ -149,7 +153,7 @@ export abstract class AbstractKeybindingService extends Disposable implements IK
}
const contextValue = this._contextKeyService.getContext(target);
const currentChords = this._currentChords ? this._currentChords.map((({ keypress }) => keypress)) : null;
const currentChords = this._currentChords.map((({ keypress }) => keypress));
return this._getResolver().resolve(contextValue, currentChords, firstChord);
}
@@ -171,25 +175,28 @@ export abstract class AbstractKeybindingService extends Disposable implements IK
}, 500);
}
private _enterMultiChordMode(firstChord: string, keypressLabel: string | null): void {
this._currentChords = [{
keypress: firstChord,
label: keypressLabel
}];
this._currentChordStatusMessage = this._notificationService.status(nls.localize('first.chord', "({0}) was pressed. Waiting for second key of chord...", keypressLabel));
this._scheduleLeaveChordMode();
IME.disable();
}
private _expectAnotherChord(firstChord: string, keypressLabel: string | null): void {
this._currentChords.push({ keypress: firstChord, label: keypressLabel });
switch (this._currentChords.length) {
case 0:
throw illegalState('impossible');
case 1:
// TODO@ulugbekna: revise this message and the one below (at least, fix terminology)
this._currentChordStatusMessage = this._notificationService.status(nls.localize('first.chord', "({0}) was pressed. Waiting for second key of chord...", keypressLabel));
break;
default: {
const fullKeypressLabel = this._currentChords.map(({ label }) => label).join(', ');
this._currentChordStatusMessage = this._notificationService.status(nls.localize('next.chord', "({0}) was pressed. Waiting for next key of chord...", fullKeypressLabel));
}
}
private _continueMultiChordMode(nextChord: string, keypressLabel: string | null): void {
this._currentChords = this._currentChords ? this._currentChords : [];
this._currentChords.push({
keypress: nextChord,
label: keypressLabel
});
const fullKeypressLabel = this._currentChords.map(({ label }) => label).join(', ');
this._currentChordStatusMessage = this._notificationService.status(nls.localize('next.chord', "({0}) was pressed. Waiting for next key of chord...", fullKeypressLabel));
this._scheduleLeaveChordMode();
if (IME.enabled) {
IME.disable();
}
}
private _leaveChordMode(): void {
@@ -198,7 +205,7 @@ export abstract class AbstractKeybindingService extends Disposable implements IK
this._currentChordStatusMessage = null;
}
this._currentChordChecker.cancel();
this._currentChords = null;
this._currentChords = [];
IME.enable();
}
@@ -287,10 +294,10 @@ export abstract class AbstractKeybindingService extends Disposable implements IK
// hence we disregard `_currentChord` and use the same modifier instead.
const [dispatchKeyname,] = userKeypress.getSingleModifierDispatchChords();
userPressedChord = dispatchKeyname;
currentChords = dispatchKeyname ? [dispatchKeyname] : [];
currentChords = dispatchKeyname ? [dispatchKeyname] : []; // TODO@ulugbekna: in the `else` case we assign an empty array - make sure `resolve` can handle an empty array well
} else {
[userPressedChord,] = userKeypress.getDispatchChords();
currentChords = this._currentChords ? this._currentChords.map(({ keypress }) => keypress) : null;
currentChords = this._currentChords.map(({ keypress }) => keypress);
}
if (userPressedChord === null) {
@@ -304,47 +311,72 @@ export abstract class AbstractKeybindingService extends Disposable implements IK
const resolveResult = this._getResolver().resolve(contextValue, currentChords, userPressedChord);
this._logService.trace('KeybindingService#dispatch', keypressLabel, resolveResult?.commandId);
switch (resolveResult.kind) {
if (resolveResult && resolveResult.enterMultiChord) {
shouldPreventDefault = true;
this._enterMultiChordMode(userPressedChord, keypressLabel);
this._log(`+ Entering chord mode...`);
return shouldPreventDefault;
}
case ResultKind.NoMatchingKb: {
if (this._currentChords) {
if (resolveResult && !resolveResult.leaveMultiChord) {
shouldPreventDefault = true;
this._continueMultiChordMode(userPressedChord, keypressLabel);
this._log(`+ Continuing chord mode...`);
this._logService.trace('KeybindingService#dispatch', keypressLabel, `[ No matching keybinding ]`);
if (this.inChordMode) {
const currentChordsLabel = this._currentChords.map(({ label }) => label).join(', ');
this._log(`+ Leaving multi-chord mode: Nothing bound to "${currentChordsLabel}, ${keypressLabel}".`);
this._notificationService.status(nls.localize('missing.chord', "The key combination ({0}, {1}) is not a command.", currentChordsLabel, keypressLabel), { hideAfter: 10 * 1000 /* 10s */ });
this._leaveChordMode();
shouldPreventDefault = true;
}
return shouldPreventDefault;
} else if (!resolveResult || !resolveResult.commandId) {
const currentChordsLabel = this._currentChords.map(({ label }) => label).join(', ');
this._log(`+ Leaving chord mode: Nothing bound to "${currentChordsLabel}, ${keypressLabel}".`);
this._notificationService.status(nls.localize('missing.chord', "The key combination ({0}, {1}) is not a command.", currentChordsLabel, keypressLabel), { hideAfter: 10 * 1000 /* 10s */ });
}
case ResultKind.MoreChordsNeeded: {
this._logService.trace('KeybindingService#dispatch', keypressLabel, `[ Several keybindings match - more chords needed ]`);
shouldPreventDefault = true;
this._expectAnotherChord(userPressedChord, keypressLabel);
this._log(this._currentChords.length === 1 ? `+ Entering multi-chord mode...` : `+ Continuing multi-chord mode...`);
return shouldPreventDefault;
}
case ResultKind.KbFound: {
this._logService.trace('KeybindingService#dispatch', keypressLabel, `[ Will dispatch command ${resolveResult.commandId} ]`);
if (resolveResult.commandId === null) {
if (this.inChordMode) {
const currentChordsLabel = this._currentChords.map(({ label }) => label).join(', ');
this._log(`+ Leaving chord mode: Nothing bound to "${currentChordsLabel}, ${keypressLabel}".`);
this._notificationService.status(nls.localize('missing.chord', "The key combination ({0}, {1}) is not a command.", currentChordsLabel, keypressLabel), { hideAfter: 10 * 1000 /* 10s */ });
this._leaveChordMode();
}
shouldPreventDefault = true;
} else {
if (this.inChordMode) {
this._leaveChordMode();
}
if (!resolveResult.isBubble) {
shouldPreventDefault = true;
}
this._log(`+ Invoking command ${resolveResult.commandId}.`);
if (typeof resolveResult.commandArgs === 'undefined') {
this._commandService.executeCommand(resolveResult.commandId).then(undefined, err => this._notificationService.warn(err));
} else {
this._commandService.executeCommand(resolveResult.commandId, resolveResult.commandArgs).then(undefined, err => this._notificationService.warn(err));
}
if (!HIGH_FREQ_COMMANDS.test(resolveResult.commandId)) {
this._telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id: resolveResult.commandId, from: 'keybinding', detail: userKeypress.getUserSettingsLabel() ?? undefined });
}
}
return shouldPreventDefault;
}
}
this._leaveChordMode();
if (resolveResult && resolveResult.commandId) {
if (!resolveResult.bubble) {
shouldPreventDefault = true;
}
this._log(`+ Invoking command ${resolveResult.commandId}.`);
if (typeof resolveResult.commandArgs === 'undefined') {
this._commandService.executeCommand(resolveResult.commandId).then(undefined, err => this._notificationService.warn(err));
} else {
this._commandService.executeCommand(resolveResult.commandId, resolveResult.commandArgs).then(undefined, err => this._notificationService.warn(err));
}
if (!HIGH_FREQ_COMMANDS.test(resolveResult.commandId)) {
this._telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id: resolveResult.commandId, from: 'keybinding', detail: userKeypress.getUserSettingsLabel() ?? undefined });
}
}
return shouldPreventDefault;
}
mightProducePrintableCharacter(event: IKeyboardEvent): boolean {
@@ -9,7 +9,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
import { ResolvedKeybinding, Keybinding } from 'vs/base/common/keybindings';
import { IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IResolveResult } from 'vs/platform/keybinding/common/keybindingResolver';
import { ResolutionResult } from 'vs/platform/keybinding/common/keybindingResolver';
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
export interface IUserFriendlyKeybinding {
@@ -63,7 +63,7 @@ export interface IKeybindingService {
/**
* Resolve and dispatch `keyboardEvent`, but do not invoke the command or change inner state.
*/
softDispatch(keyboardEvent: IKeyboardEvent, target: IContextKeyServiceTarget): IResolveResult | null;
softDispatch(keyboardEvent: IKeyboardEvent, target: IContextKeyServiceTarget): ResolutionResult | null;
dispatchByUserSettingsLabel(userSettingsLabel: string, target: IContextKeyServiceTarget): void;
@@ -6,16 +6,35 @@
import { implies, ContextKeyExpression, ContextKeyExprType, IContext, IContextKeyService, expressionsAreEqualWithConstantSubstitution } from 'vs/platform/contextkey/common/contextkey';
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
export interface IResolveResult {
/** Whether the resolved keybinding is entering a multi chord */
enterMultiChord: boolean;
/** Whether the resolved keybinding is leaving (and executing) a multi chord keybinding */
leaveMultiChord: boolean;
commandId: string | null;
commandArgs: any;
bubble: boolean;
//#region resolution-result
export const enum ResultKind {
/** No keybinding found this sequence of chords */
NoMatchingKb,
/** There're several keybindings that have the given sequence of chords as a prefix */
MoreChordsNeeded,
/** A single keybinding found to be dispatched/invoked */
KbFound
}
export type ResolutionResult =
| { kind: ResultKind.NoMatchingKb }
| { kind: ResultKind.MoreChordsNeeded }
| { kind: ResultKind.KbFound; commandId: string | null; commandArgs: any; isBubble: boolean };
// util definitions to make working with the above types easier within this module:
const NoMatchingKb: ResolutionResult = { kind: ResultKind.NoMatchingKb };
const MoreChordsNeeded: ResolutionResult = { kind: ResultKind.MoreChordsNeeded };
function KbFound(commandId: string | null, commandArgs: any, isBubble: boolean): ResolutionResult {
return { kind: ResultKind.KbFound, commandId, commandArgs, isBubble };
}
//#endregion
/**
* Stores mappings from keybindings to commands and from commands to keybindings.
* Given a sequence of chords, `resolve`s which keybinding it matches
@@ -281,82 +300,70 @@ export class KeybindingResolver {
return items[items.length - 1];
}
public resolve(context: IContext, currentChords: string[] | null, keypress: string): IResolveResult | null {
this._log(`| Resolving ${keypress}${currentChords ? ` chorded from ${currentChords}` : ``}`);
/**
* Looks up a keybinding trigged as a result of pressing a sequence of chords - `[...currentChords, keypress]`
*
* Example: resolving 3 chords pressed sequentially - `cmd+k cmd+p cmd+i`:
* `currentChords = [ 'cmd+k' , 'cmd+p' ]` and `keypress = `cmd+i` - last pressed chord
*/
public resolve(context: IContext, currentChords: string[], keypress: string): ResolutionResult {
const pressedChords = [...currentChords, keypress];
this._log(`| Resolving ${pressedChords}`);
const kbCandidates = this._map.get(pressedChords[0]);
if (kbCandidates === undefined) {
// No bindings with such 0-th chord
this._log(`\\ No keybinding entries.`);
return NoMatchingKb;
}
let lookupMap: ResolvedKeybindingItem[] | null = null;
if (currentChords !== null) {
if (pressedChords.length < 2) {
lookupMap = kbCandidates;
} else {
// Fetch all chord bindings for `currentChords`
const candidates = this._map.get(currentChords[0]);
if (typeof candidates === 'undefined') {
// No chords starting with `currentChords`
this._log(`\\ No keybinding entries.`);
return null;
}
lookupMap = [];
for (let i = 0, len = candidates.length; i < len; i++) {
const candidate = candidates[i];
if (candidate.chords.length <= currentChords.length) {
for (let i = 0, len = kbCandidates.length; i < len; i++) {
const candidate = kbCandidates[i];
if (pressedChords.length > candidate.chords.length) { // # of pressed chords can't be less than # of chords in a keybinding to invoke
continue;
}
let prefixMatches = true;
for (let i = 1; i < currentChords.length; i++) {
if (candidate.chords[i] !== currentChords[i]) {
for (let i = 1; i < pressedChords.length; i++) {
if (candidate.chords[i] !== pressedChords[i]) {
prefixMatches = false;
break;
}
}
if (prefixMatches && candidate.chords[currentChords.length] === keypress) {
if (prefixMatches) {
lookupMap.push(candidate);
}
}
} else {
const candidates = this._map.get(keypress);
if (typeof candidates === 'undefined') {
// No bindings with `keypress`
this._log(`\\ No keybinding entries.`);
return null;
}
lookupMap = candidates;
}
// check there's a keybinding with a matching when clause
const result = this._findCommand(context, lookupMap);
if (!result) {
this._log(`\\ From ${lookupMap.length} keybinding entries, no when clauses matched the context.`);
return null;
return NoMatchingKb;
}
if (currentChords === null && result.chords.length > 1 && result.chords[1] !== null) {
this._log(`\\ From ${lookupMap.length} keybinding entries, matched chord, when: ${printWhenExplanation(result.when)}, source: ${printSourceExplanation(result)}.`);
return {
enterMultiChord: true,
leaveMultiChord: false,
commandId: null,
commandArgs: null,
bubble: false
};
} else if (currentChords !== null && currentChords.length + 1 < result.chords.length) {
this._log(`\\ From ${lookupMap.length} keybinding entries, continued chord, when: ${printWhenExplanation(result.when)}, source: ${printSourceExplanation(result)}.`);
return {
enterMultiChord: false,
leaveMultiChord: false,
commandId: null,
commandArgs: null,
bubble: false
};
// check we got all chords necessary to be sure a particular keybinding needs to be invoked
if (pressedChords.length < result.chords.length) {
// The chord sequence is not complete
this._log(`\\ From ${lookupMap.length} keybinding entries, awaiting ${result.chords.length - pressedChords.length} more chord(s), when: ${printWhenExplanation(result.when)}, source: ${printSourceExplanation(result)}.`);
return MoreChordsNeeded;
}
this._log(`\\ From ${lookupMap.length} keybinding entries, matched ${result.command}, when: ${printWhenExplanation(result.when)}, source: ${printSourceExplanation(result)}.`);
return {
enterMultiChord: false,
leaveMultiChord: result.chords.length > 1,
commandId: result.command,
commandArgs: result.commandArgs,
bubble: result.bubble
};
return KbFound(result.command, result.commandArgs, result.bubble);
}
private _findCommand(context: IContext, matches: ResolvedKeybindingItem[]): ResolvedKeybindingItem | null {
@@ -8,7 +8,7 @@ import { decodeKeybinding, createSimpleKeybinding, KeyCodeChord } from 'vs/base/
import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { OS } from 'vs/base/common/platform';
import { ContextKeyExpr, ContextKeyExpression, IContext } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver';
import { KeybindingResolver, ResultKind } from 'vs/platform/keybinding/common/keybindingResolver';
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding';
import { createUSLayoutResolvedKeybinding } from 'vs/platform/keybinding/test/common/keybindingsTestUtils';
@@ -50,8 +50,13 @@ suite('KeybindingResolver', () => {
assert.strictEqual(contextRules.evaluate(createContext({ bar: 'bz' })), false);
const resolver = new KeybindingResolver([keybindingItem], [], () => { });
assert.strictEqual(resolver.resolve(createContext({ bar: 'baz' }), null, getDispatchStr(runtimeKeybinding))!.commandId, 'yes');
assert.strictEqual(resolver.resolve(createContext({ bar: 'bz' }), null, getDispatchStr(runtimeKeybinding)), null);
const r1 = resolver.resolve(createContext({ bar: 'baz' }), [], getDispatchStr(runtimeKeybinding));
assert.ok(r1.kind === ResultKind.KbFound);
assert.strictEqual(r1.commandId, 'yes');
const r2 = resolver.resolve(createContext({ bar: 'bz' }), [], getDispatchStr(runtimeKeybinding));
assert.strictEqual(r2.kind, ResultKind.NoMatchingKb);
});
test('resolve key with arguments', () => {
@@ -62,247 +67,253 @@ suite('KeybindingResolver', () => {
const keybindingItem = kbItem(keybinding, 'yes', commandArgs, contextRules, true);
const resolver = new KeybindingResolver([keybindingItem], [], () => { });
assert.strictEqual(resolver.resolve(createContext({ bar: 'baz' }), null, getDispatchStr(runtimeKeybinding))!.commandArgs, commandArgs);
const r = resolver.resolve(createContext({ bar: 'baz' }), [], getDispatchStr(runtimeKeybinding));
assert.ok(r.kind === ResultKind.KbFound);
assert.strictEqual(r.commandArgs, commandArgs);
});
test('KeybindingResolver.handleRemovals simple 1', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true)
];
const overrides = [
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), false),
]);
suite('handle keybinding removals', () => {
test('simple 1', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true)
];
const overrides = [
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), false),
]);
});
test('simple 2', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(KeyCode.KeyC, 'yes3', null, ContextKeyExpr.equals('3', 'c'), false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true),
kbItem(KeyCode.KeyC, 'yes3', null, ContextKeyExpr.equals('3', 'c'), false),
]);
});
test('removal with not matching when', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(KeyCode.KeyA, '-yes1', null, ContextKeyExpr.equals('1', 'b'), false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('removal with not matching keybinding', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(KeyCode.KeyB, '-yes1', null, ContextKeyExpr.equals('1', 'a'), false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('removal with matching keybinding and when', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(KeyCode.KeyA, '-yes1', null, ContextKeyExpr.equals('1', 'a'), false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('removal with unspecified keybinding', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(0, '-yes1', null, ContextKeyExpr.equals('1', 'a'), false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('removal with unspecified when', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(KeyCode.KeyA, '-yes1', null, undefined, false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('removal with unspecified when and unspecified keybinding', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(0, '-yes1', null, undefined, false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('issue #138997 - removal in default list', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, undefined, true),
kbItem(KeyCode.KeyB, 'yes2', null, undefined, true),
kbItem(0, '-yes1', null, undefined, false)
];
const overrides: ResolvedKeybindingItem[] = [];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyB, 'yes2', null, undefined, true)
]);
});
test('issue #612#issuecomment-222109084 cannot remove keybindings for commands with ^', () => {
const defaults = [
kbItem(KeyCode.KeyA, '^yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(KeyCode.KeyA, '-yes1', null, undefined, false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('issue #140884 Unable to reassign F1 as keybinding for Show All Commands', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'command1', null, undefined, true),
];
const overrides = [
kbItem(KeyCode.KeyA, '-command1', null, undefined, false),
kbItem(KeyCode.KeyA, 'command1', null, undefined, false),
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyA, 'command1', null, undefined, false)
]);
});
test('issue #141638: Keyboard Shortcuts: Change When Expression might actually remove keybinding in Insiders', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'command1', null, undefined, true),
];
const overrides = [
kbItem(KeyCode.KeyA, 'command1', null, ContextKeyExpr.equals('a', '1'), false),
kbItem(KeyCode.KeyA, '-command1', null, undefined, false),
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyA, 'command1', null, ContextKeyExpr.equals('a', '1'), false)
]);
});
test('issue #157751: Auto-quoting of context keys prevents removal of keybindings via UI', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'command1', null, ContextKeyExpr.deserialize(`editorTextFocus && activeEditor != workbench.editor.notebook && editorLangId in julia.supportedLanguageIds`), true),
];
const overrides = [
kbItem(KeyCode.KeyA, '-command1', null, ContextKeyExpr.deserialize(`editorTextFocus && activeEditor != 'workbench.editor.notebook' && editorLangId in 'julia.supportedLanguageIds'`), false),
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, []);
});
test('issue #160604: Remove keybindings with when clause does not work', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'command1', null, undefined, true),
];
const overrides = [
kbItem(KeyCode.KeyA, '-command1', null, ContextKeyExpr.true(), false),
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, []);
});
test('contextIsEntirelyIncluded', () => {
const toContextKeyExpression = (expr: ContextKeyExpression | string | null) => {
if (typeof expr === 'string' || !expr) {
return ContextKeyExpr.deserialize(expr);
}
return expr;
};
const assertIsIncluded = (a: ContextKeyExpression | string | null, b: ContextKeyExpression | string | null) => {
assert.strictEqual(KeybindingResolver.whenIsEntirelyIncluded(toContextKeyExpression(a), toContextKeyExpression(b)), true);
};
const assertIsNotIncluded = (a: ContextKeyExpression | string | null, b: ContextKeyExpression | string | null) => {
assert.strictEqual(KeybindingResolver.whenIsEntirelyIncluded(toContextKeyExpression(a), toContextKeyExpression(b)), false);
};
assertIsIncluded(null, null);
assertIsIncluded(null, ContextKeyExpr.true());
assertIsIncluded(ContextKeyExpr.true(), null);
assertIsIncluded(ContextKeyExpr.true(), ContextKeyExpr.true());
assertIsIncluded('key1', null);
assertIsIncluded('key1', '');
assertIsIncluded('key1', 'key1');
assertIsIncluded('key1', ContextKeyExpr.true());
assertIsIncluded('!key1', '');
assertIsIncluded('!key1', '!key1');
assertIsIncluded('key2', '');
assertIsIncluded('key2', 'key2');
assertIsIncluded('key1 && key1 && key2 && key2', 'key2');
assertIsIncluded('key1 && key2', 'key2');
assertIsIncluded('key1 && key2', 'key1');
assertIsIncluded('key1 && key2', '');
assertIsIncluded('key1', 'key1 || key2');
assertIsIncluded('key1 || !key1', 'key2 || !key2');
assertIsIncluded('key1', 'key1 || key2 && key3');
assertIsNotIncluded('key1', '!key1');
assertIsNotIncluded('!key1', 'key1');
assertIsNotIncluded('key1 && key2', 'key3');
assertIsNotIncluded('key1 && key2', 'key4');
assertIsNotIncluded('key1', 'key2');
assertIsNotIncluded('key1 || key2', 'key2');
assertIsNotIncluded('', 'key2');
assertIsNotIncluded(null, 'key2');
});
});
test('KeybindingResolver.handleRemovals simple 2', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(KeyCode.KeyC, 'yes3', null, ContextKeyExpr.equals('3', 'c'), false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true),
kbItem(KeyCode.KeyC, 'yes3', null, ContextKeyExpr.equals('3', 'c'), false),
]);
});
test('KeybindingResolver.handleRemovals removal with not matching when', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(KeyCode.KeyA, '-yes1', null, ContextKeyExpr.equals('1', 'b'), false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('KeybindingResolver.handleRemovals removal with not matching keybinding', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(KeyCode.KeyB, '-yes1', null, ContextKeyExpr.equals('1', 'a'), false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('KeybindingResolver.handleRemovals removal with matching keybinding and when', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(KeyCode.KeyA, '-yes1', null, ContextKeyExpr.equals('1', 'a'), false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('KeybindingResolver.handleRemovals removal with unspecified keybinding', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(0, '-yes1', null, ContextKeyExpr.equals('1', 'a'), false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('KeybindingResolver.handleRemovals removal with unspecified when', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(KeyCode.KeyA, '-yes1', null, undefined, false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('KeybindingResolver.handleRemovals removal with unspecified when and unspecified keybinding', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(0, '-yes1', null, undefined, false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('issue #138997 KeybindingResolver.handleRemovals removal in default list', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'yes1', null, undefined, true),
kbItem(KeyCode.KeyB, 'yes2', null, undefined, true),
kbItem(0, '-yes1', null, undefined, false)
];
const overrides: ResolvedKeybindingItem[] = [];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyB, 'yes2', null, undefined, true)
]);
});
test('issue #612#issuecomment-222109084 cannot remove keybindings for commands with ^', () => {
const defaults = [
kbItem(KeyCode.KeyA, '^yes1', null, ContextKeyExpr.equals('1', 'a'), true),
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
];
const overrides = [
kbItem(KeyCode.KeyA, '-yes1', null, undefined, false)
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyB, 'yes2', null, ContextKeyExpr.equals('2', 'b'), true)
]);
});
test('issue #140884 Unable to reassign F1 as keybinding for Show All Commands', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'command1', null, undefined, true),
];
const overrides = [
kbItem(KeyCode.KeyA, '-command1', null, undefined, false),
kbItem(KeyCode.KeyA, 'command1', null, undefined, false),
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyA, 'command1', null, undefined, false)
]);
});
test('issue #141638: Keyboard Shortcuts: Change When Expression might actually remove keybinding in Insiders', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'command1', null, undefined, true),
];
const overrides = [
kbItem(KeyCode.KeyA, 'command1', null, ContextKeyExpr.equals('a', '1'), false),
kbItem(KeyCode.KeyA, '-command1', null, undefined, false),
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, [
kbItem(KeyCode.KeyA, 'command1', null, ContextKeyExpr.equals('a', '1'), false)
]);
});
test('issue #157751: Auto-quoting of context keys prevents removal of keybindings via UI', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'command1', null, ContextKeyExpr.deserialize(`editorTextFocus && activeEditor != workbench.editor.notebook && editorLangId in julia.supportedLanguageIds`), true),
];
const overrides = [
kbItem(KeyCode.KeyA, '-command1', null, ContextKeyExpr.deserialize(`editorTextFocus && activeEditor != 'workbench.editor.notebook' && editorLangId in 'julia.supportedLanguageIds'`), false),
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, []);
});
test('issue #160604: Remove keybindings with when clause does not work', () => {
const defaults = [
kbItem(KeyCode.KeyA, 'command1', null, undefined, true),
];
const overrides = [
kbItem(KeyCode.KeyA, '-command1', null, ContextKeyExpr.true(), false),
];
const actual = KeybindingResolver.handleRemovals([...defaults, ...overrides]);
assert.deepStrictEqual(actual, []);
});
test('contextIsEntirelyIncluded', () => {
const toContextKeyExpression = (expr: ContextKeyExpression | string | null) => {
if (typeof expr === 'string' || !expr) {
return ContextKeyExpr.deserialize(expr);
}
return expr;
};
const assertIsIncluded = (a: ContextKeyExpression | string | null, b: ContextKeyExpression | string | null) => {
assert.strictEqual(KeybindingResolver.whenIsEntirelyIncluded(toContextKeyExpression(a), toContextKeyExpression(b)), true);
};
const assertIsNotIncluded = (a: ContextKeyExpression | string | null, b: ContextKeyExpression | string | null) => {
assert.strictEqual(KeybindingResolver.whenIsEntirelyIncluded(toContextKeyExpression(a), toContextKeyExpression(b)), false);
};
assertIsIncluded(null, null);
assertIsIncluded(null, ContextKeyExpr.true());
assertIsIncluded(ContextKeyExpr.true(), null);
assertIsIncluded(ContextKeyExpr.true(), ContextKeyExpr.true());
assertIsIncluded('key1', null);
assertIsIncluded('key1', '');
assertIsIncluded('key1', 'key1');
assertIsIncluded('key1', ContextKeyExpr.true());
assertIsIncluded('!key1', '');
assertIsIncluded('!key1', '!key1');
assertIsIncluded('key2', '');
assertIsIncluded('key2', 'key2');
assertIsIncluded('key1 && key1 && key2 && key2', 'key2');
assertIsIncluded('key1 && key2', 'key2');
assertIsIncluded('key1 && key2', 'key1');
assertIsIncluded('key1 && key2', '');
assertIsIncluded('key1', 'key1 || key2');
assertIsIncluded('key1 || !key1', 'key2 || !key2');
assertIsIncluded('key1', 'key1 || key2 && key3');
assertIsNotIncluded('key1', '!key1');
assertIsNotIncluded('!key1', 'key1');
assertIsNotIncluded('key1 && key2', 'key3');
assertIsNotIncluded('key1 && key2', 'key4');
assertIsNotIncluded('key1', 'key2');
assertIsNotIncluded('key1 || key2', 'key2');
assertIsNotIncluded('', 'key2');
assertIsNotIncluded(null, 'key2');
});
test('resolve command', () => {
suite('resolve command', () => {
function _kbItem(keybinding: number | number[], command: string, when: ContextKeyExpression | undefined): ResolvedKeybindingItem {
return kbItem(keybinding, command, null, when, true);
@@ -370,30 +381,40 @@ suite('KeybindingResolver', () => {
undefined
),
_kbItem(
KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC),
KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC), // cmd+k cmd+c
'comment lines',
undefined
),
_kbItem(
KeyChord(KeyMod.CtrlCmd | KeyCode.KeyG, KeyMod.CtrlCmd | KeyCode.KeyC),
KeyChord(KeyMod.CtrlCmd | KeyCode.KeyG, KeyMod.CtrlCmd | KeyCode.KeyC), // cmd+g cmd+c
'unreachablechord',
undefined
),
_kbItem(
KeyMod.CtrlCmd | KeyCode.KeyG,
KeyMod.CtrlCmd | KeyCode.KeyG, // cmd+g
'eleven',
undefined
),
_kbItem(
[KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyA, KeyCode.KeyB],
[KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyA, KeyCode.KeyB], // cmd+k a b
'long multi chord',
undefined
),
_kbItem(
[KeyMod.CtrlCmd | KeyCode.KeyB, KeyMod.CtrlCmd | KeyCode.KeyC], // cmd+b cmd+c
'shadowed by long-multi-chord-2',
undefined
),
_kbItem(
[KeyMod.CtrlCmd | KeyCode.KeyB, KeyMod.CtrlCmd | KeyCode.KeyC, KeyCode.KeyI], // cmd+b cmd+c i
'long-multi-chord-2',
undefined
)
];
const resolver = new KeybindingResolver(items, [], () => { });
const testKey = (commandId: string, expectedKeys: number[] | number[][]) => {
const testKbLookupByCommand = (commandId: string, expectedKeys: number[] | number[][]) => {
// Test lookup
const lookupResult = resolver.lookupKeybindings(commandId);
assert.strictEqual(lookupResult.length, expectedKeys.length, 'Length mismatch @ commandId ' + commandId);
@@ -407,68 +428,93 @@ suite('KeybindingResolver', () => {
const testResolve = (ctx: IContext, _expectedKey: number | number[], commandId: string) => {
const expectedKeybinding = decodeKeybinding(_expectedKey, OS)!;
let previousChord: string[] | null = null;
const previousChord: string[] = [];
for (let i = 0, len = expectedKeybinding.chords.length; i < len; i++) {
const chord = getDispatchStr(<KeyCodeChord>expectedKeybinding.chords[i]);
const result = resolver.resolve(ctx, previousChord, chord);
if (i === len - 1) {
// if it's the final chord, then we should find a valid command,
// and there should not be a chord.
assert.ok(result !== null, `Enters multi chord for ${commandId} at chord ${i}`);
assert.strictEqual(result!.commandId, commandId, `Enters multi chord for ${commandId} at chord ${i}`);
assert.strictEqual(result!.enterMultiChord, false, `Enters multi chord for ${commandId} at chord ${i}`);
assert.ok(result.kind === ResultKind.KbFound, `Enters multi chord for ${commandId} at chord ${i}`);
assert.strictEqual(result.commandId, commandId, `Enters multi chord for ${commandId} at chord ${i}`);
} else if (i > 0) {
// if this is an intermediate chord, we should not find a valid command,
// and there should be an open chord we continue.
assert.ok(result !== null, `Continues multi chord for ${commandId} at chord ${i}`);
assert.strictEqual(result!.commandId, null, `Continues multi chord for ${commandId} at chord ${i}`);
assert.strictEqual(result!.enterMultiChord, false, `Is already in multi chord for ${commandId} at chord ${i}`);
assert.strictEqual(result!.leaveMultiChord, false, `Does not leave multi chord for ${commandId} at chord ${i}`);
assert.ok(result.kind === ResultKind.MoreChordsNeeded, `Continues multi chord for ${commandId} at chord ${i}`);
} else {
// if it's not the final chord and not an intermediate, then we should not
// find a valid command, and we should enter a chord.
assert.ok(result !== null, `Enters multi chord for ${commandId} at chord ${i}`);
assert.strictEqual(result!.commandId, null, `Enters multi chord for ${commandId} at chord ${i}`);
assert.strictEqual(result!.enterMultiChord, true, `Enters multi chord for ${commandId} at chord ${i}`);
}
if (previousChord === null) {
previousChord = [];
assert.ok(result.kind === ResultKind.MoreChordsNeeded, `Enters multi chord for ${commandId} at chord ${i}`);
}
previousChord.push(chord);
}
};
testKey('first', []);
test('resolve command - 1', () => {
testKbLookupByCommand('first', []);
});
testKey('second', [KeyCode.KeyZ, KeyCode.KeyX]);
testResolve(createContext({ key2: true }), KeyCode.KeyX, 'second');
testResolve(createContext({}), KeyCode.KeyZ, 'second');
test('resolve command - 2', () => {
testKbLookupByCommand('second', [KeyCode.KeyZ, KeyCode.KeyX]);
testResolve(createContext({ key2: true }), KeyCode.KeyX, 'second');
testResolve(createContext({}), KeyCode.KeyZ, 'second');
});
testKey('third', [KeyCode.KeyX]);
testResolve(createContext({ key3: true }), KeyCode.KeyX, 'third');
test('resolve command - 3', () => {
testKbLookupByCommand('third', [KeyCode.KeyX]);
testResolve(createContext({ key3: true }), KeyCode.KeyX, 'third');
});
testKey('fourth', []);
test('resolve command - 4', () => {
testKbLookupByCommand('fourth', []);
});
testKey('fifth', [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyY, KeyCode.KeyZ)]);
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KeyY, KeyCode.KeyZ), 'fifth');
test('resolve command - 5', () => {
testKbLookupByCommand('fifth', [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyY, KeyCode.KeyZ)]);
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KeyY, KeyCode.KeyZ), 'fifth');
});
testKey('seventh', [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyK)]);
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyK), 'seventh');
test('resolve command - 6', () => {
testKbLookupByCommand('seventh', [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyK)]);
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyK), 'seventh');
});
testKey('uncomment lines', [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyU)]);
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyU), 'uncomment lines');
test('resolve command - 7', () => {
testKbLookupByCommand('uncomment lines', [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyU)]);
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyU), 'uncomment lines');
});
testKey('comment lines', [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC)]);
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC), 'comment lines');
test('resolve command - 8', () => {
testKbLookupByCommand('comment lines', [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC)]);
testResolve(createContext({}), KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC), 'comment lines');
});
testKey('unreachablechord', []);
test('resolve command - 9', () => {
testKbLookupByCommand('unreachablechord', []);
});
testKey('eleven', [KeyMod.CtrlCmd | KeyCode.KeyG]);
testResolve(createContext({}), KeyMod.CtrlCmd | KeyCode.KeyG, 'eleven');
test('resolve command - 10', () => {
testKbLookupByCommand('eleven', [KeyMod.CtrlCmd | KeyCode.KeyG]);
testResolve(createContext({}), KeyMod.CtrlCmd | KeyCode.KeyG, 'eleven');
});
testKey('sixth', []);
test('resolve command - 11', () => {
testKbLookupByCommand('sixth', []);
});
testKey('long multi chord', [[KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyA, KeyCode.KeyB]]);
testResolve(createContext({}), [KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyA, KeyCode.KeyB], 'long multi chord');
test('resolve command - 12', () => {
testKbLookupByCommand('long multi chord', [[KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyA, KeyCode.KeyB]]);
testResolve(createContext({}), [KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyA, KeyCode.KeyB], 'long multi chord');
});
const emptyContext = createContext({});
test('KBs having common prefix - the one defined later is returned', () => {
testResolve(emptyContext, [KeyMod.CtrlCmd | KeyCode.KeyB, KeyMod.CtrlCmd | KeyCode.KeyC, KeyCode.KeyI], 'long-multi-chord-2');
});
});
});
@@ -8,7 +8,7 @@ import { ResolvedKeybinding, KeyCodeChord, Keybinding } from 'vs/base/common/key
import { OS } from 'vs/base/common/platform';
import { ContextKeyExpression, ContextKeyValue, IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget, IScopedContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IKeybindingService, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';
import { IResolveResult } from 'vs/platform/keybinding/common/keybindingResolver';
import { ResolutionResult } from 'vs/platform/keybinding/common/keybindingResolver';
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding';
@@ -135,7 +135,7 @@ export class MockKeybindingService implements IKeybindingService {
return 0;
}
public softDispatch(keybinding: IKeyboardEvent, target: IContextKeyServiceTarget): IResolveResult | null {
public softDispatch(keybinding: IKeyboardEvent, target: IContextKeyServiceTarget): ResolutionResult | null {
return null;
}
+2 -1
View File
@@ -26,6 +26,7 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView
import { IEditorOptions } from 'vs/platform/editor/common/editor';
import { createDecorator, IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver';
import { Registry } from 'vs/platform/registry/common/platform';
import { IStyleOverride, defaultFindWidgetStyles, defaultListStyles, getListStyles } from 'vs/platform/theme/browser/defaultStyles';
@@ -809,7 +810,7 @@ function createKeyboardNavigationEventFilter(keybindingService: IKeybindingServi
const result = keybindingService.softDispatch(event, event.target);
if (result?.enterMultiChord) {
if (result?.kind === ResultKind.MoreChordsNeeded) {
inMultiChord = true;
return false;
}
@@ -224,7 +224,7 @@ export class Win32UpdateService extends AbstractUpdateService {
});
const readyMutexName = `${this.productService.win32MutexName}-ready`;
const mutex = await import('windows-mutex');
const mutex = await import('@vscode/windows-mutex');
// poll for mutex-ready
pollUntil(() => mutex.isActive(readyMutexName))
@@ -29,6 +29,7 @@ import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/wo
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { Categories } from 'vs/platform/action/common/actionCommonCategories';
import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup';
import { ResolutionResult, ResultKind } from 'vs/platform/keybinding/common/keybindingResolver';
class InspectContextKeysAction extends Action2 {
@@ -259,7 +260,7 @@ class ToggleScreencastModeAction extends Action2 {
const shortcut = keybindingService.softDispatch(event, event.target);
// Hide the single arrow key pressed
if (shortcut?.commandId && configurationService.getValue('screencastMode.hideSingleEditorCursorMoves') && (
if (shortcut && shortcut.kind === ResultKind.KbFound && shortcut.commandId && configurationService.getValue('screencastMode.hideSingleEditorCursorMoves') && (
['cursorLeft', 'cursorRight', 'cursorUp', 'cursorDown'].includes(shortcut.commandId))
) {
return;
@@ -278,7 +279,7 @@ class ToggleScreencastModeAction extends Action2 {
const format = configurationService.getValue<'keys' | 'command' | 'commandWithGroup' | 'commandAndKeys' | 'commandWithGroupAndKeys'>('screencastMode.keyboardShortcutsFormat');
const keybinding = keybindingService.resolveKeyboardEvent(event);
const command = shortcut?.commandId ? MenuRegistry.getCommand(shortcut.commandId) : null;
const command = (this._isKbFound(shortcut) && shortcut.commandId) ? MenuRegistry.getCommand(shortcut.commandId) : null;
let titleLabel = '';
let keyLabel: string | undefined | null = keybinding.getLabel();
@@ -290,7 +291,7 @@ class ToggleScreencastModeAction extends Action2 {
titleLabel = `${typeof command.category === 'string' ? command.category : command.category.value}: ${titleLabel} `;
}
if (shortcut?.commandId) {
if (this._isKbFound(shortcut) && shortcut.commandId) {
const keybindings = keybindingService.lookupKeybindings(shortcut.commandId)
.filter(k => k.getLabel()?.endsWith(keyLabel ?? ''));
@@ -306,7 +307,7 @@ class ToggleScreencastModeAction extends Action2 {
append(keyboardMarker, $('span.title', {}, `${titleLabel} `));
}
if (onlyKeyboardShortcuts || !titleLabel || shortcut?.commandId && (format === 'keys' || format === 'commandAndKeys' || format === 'commandWithGroupAndKeys')) {
if (onlyKeyboardShortcuts || !titleLabel || (this._isKbFound(shortcut) && shortcut.commandId) && (format === 'keys' || format === 'commandAndKeys' || format === 'commandWithGroupAndKeys')) {
// Fix label for arrow keys
keyLabel = keyLabel?.replace('UpArrow', '↑')
?.replace('DownArrow', '↓')
@@ -322,6 +323,10 @@ class ToggleScreencastModeAction extends Action2 {
ToggleScreencastModeAction.disposable = disposables;
}
private _isKbFound(resolutionResult: ResolutionResult | null): resolutionResult is { kind: ResultKind.KbFound; commandId: string | null; commandArgs: any; isBubble: boolean } {
return resolutionResult !== null && resolutionResult.kind === ResultKind.KbFound;
}
}
class LogStorageAction extends Action2 {
@@ -19,6 +19,7 @@ import { fromNow } from 'vs/base/common/date';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { MarkdownRenderer } from 'vs/editor/contrib/markdownRenderer/browser/markdownRenderer';
import { defaultButtonStyles, defaultCheckboxStyles, defaultDialogStyles, defaultInputBoxStyles } from 'vs/platform/theme/browser/defaultStyles';
import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver';
export class BrowserDialogHandler extends AbstractDialogHandler {
@@ -127,7 +128,7 @@ export class BrowserDialogHandler extends AbstractDialogHandler {
type: this.getDialogType(type),
keyEventProcessor: (event: StandardKeyboardEvent) => {
const resolved = this.keybindingService.softDispatch(event, this.layoutService.container);
if (resolved?.commandId) {
if (resolved && resolved.kind === ResultKind.KbFound && resolved.commandId) {
if (BrowserDialogHandler.ALLOWABLE_COMMANDS.indexOf(resolved.commandId) === -1) {
EventHelper.stop(event, true);
}
@@ -88,6 +88,7 @@ import { editorBackground } from 'vs/platform/theme/common/colorRegistry';
import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import { TerminalExtensionsRegistry } from 'vs/workbench/contrib/terminal/browser/terminalExtensions';
import { ResolvedKeybinding } from 'vs/base/common/keybindings';
import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver';
const enum Constants {
/**
@@ -941,7 +942,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
// Respect chords if the allowChords setting is set and it's not Escape. Escape is
// handled specially for Zen Mode's Escape, Escape chord, plus it's important in
// terminals generally
const isValidChord = resolveResult?.enterMultiChord && this._configHelper.config.allowChords && event.key !== 'Escape';
const isValidChord = resolveResult?.kind === ResultKind.MoreChordsNeeded && this._configHelper.config.allowChords && event.key !== 'Escape';
if (this._keybindingService.inChordMode || isValidChord) {
event.preventDefault();
return false;
@@ -961,7 +962,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
// for keyboard events that resolve to commands described
// within commandsToSkipShell, either alert or skip processing by xterm.js
if (resolveResult && resolveResult.commandId && this._skipTerminalCommands.some(k => k === resolveResult.commandId) && !this._configHelper.config.sendKeybindingsToShell) {
if (resolveResult && resolveResult.kind === ResultKind.KbFound && resolveResult.commandId && this._skipTerminalCommands.some(k => k === resolveResult.commandId) && !this._configHelper.config.sendKeybindingsToShell) {
// don't alert when terminal is opened or closed
if (this._storageService.getBoolean(SHOW_TERMINAL_CONFIG_PROMPT_KEY, StorageScope.APPLICATION, true) &&
this._hasHadInput &&
@@ -3,7 +3,6 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Fake</title>
</head>
<body>
@@ -7,8 +7,6 @@
<!-- Disable pinch zooming -->
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
</head>
<body style="margin: 0; overflow: hidden; width: 100%; height: 100%" role="document">
@@ -10,8 +10,6 @@
<!-- Disable pinch zooming -->
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
</head>
<body style="margin: 0; overflow: hidden; width: 100%; height: 100%" role="document">
@@ -311,8 +311,7 @@ const apiMenus: IAPIMenu[] = [
{
key: 'editor/lineNumber/context',
id: MenuId.EditorLineNumberContext,
description: localize('editorLineNumberContext', "The contributed editor line number context menu"),
proposed: 'contribEditorLineNumberMenu'
description: localize('editorLineNumberContext', "The contributed editor line number context menu")
},
{
key: 'mergeEditor/result/title',
@@ -14,7 +14,6 @@ export const allApiProposals = Object.freeze({
contribCommentThreadAdditionalMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribCommentThreadAdditionalMenu.d.ts',
contribEditSessions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribEditSessions.d.ts',
contribEditorContentMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribEditorContentMenu.d.ts',
contribEditorLineNumberMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribEditorLineNumberMenu.d.ts',
contribLabelFormatterWorkspaceTooltip: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribLabelFormatterWorkspaceTooltip.d.ts',
contribMenuBarHome: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribMenuBarHome.d.ts',
contribMergeEditorMenus: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribMergeEditorMenus.d.ts',
@@ -25,6 +25,7 @@ import { IViewsService, IViewDescriptorService, ViewContainerLocation } from 'vs
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
import { stripIcons } from 'vs/base/common/iconLabels';
import { defaultButtonStyles, defaultCheckboxStyles, defaultDialogStyles, defaultInputBoxStyles } from 'vs/platform/theme/browser/defaultStyles';
import { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver';
export class ProgressService extends Disposable implements IProgressService {
@@ -556,7 +557,7 @@ export class ProgressService extends Disposable implements IProgressService {
disableDefaultAction: options.sticky,
keyEventProcessor: (event: StandardKeyboardEvent) => {
const resolved = this.keybindingService.softDispatch(event, this.layoutService.container);
if (resolved?.commandId) {
if (resolved && resolved.kind === ResultKind.KbFound && resolved.commandId) {
if (!allowableCommands.includes(resolved.commandId)) {
EventHelper.stop(event, true);
}
@@ -1,7 +1,6 @@
<!DOCTYPE html>
<html>
<head id='headID'>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Strada </title>
<link href="site.css" rel="stylesheet" type="text/css" />
<script src="jquery-1.4.1.js"></script>
@@ -157,7 +157,7 @@ flakySuite('TextSearch-integration', function () {
contentPattern: { pattern: 'e' }
};
return doSearchTest(config, 788);
return doSearchTest(config, 781);
});
test('Text: e (with excludes)', () => {
@@ -167,7 +167,7 @@ flakySuite('TextSearch-integration', function () {
excludePattern: { '**/examples': true }
};
return doSearchTest(config, 394);
return doSearchTest(config, 387);
});
test('Text: e (with includes)', () => {
@@ -344,12 +344,12 @@ flakySuite('TextSearch-integration', function () {
return doSearchTest(config, 4).then(results => {
assert.strictEqual(results.length, 4);
assert.strictEqual((<ITextSearchContext>results[0].results![0]).lineNumber, 25);
assert.strictEqual((<ITextSearchContext>results[0].results![0]).lineNumber, 24);
assert.strictEqual((<ITextSearchContext>results[0].results![0]).text, ' compiler.addUnit(prog,"input.ts");');
// assert.strictEqual((<ITextSearchMatch>results[1].results[0]).preview.text, ' compiler.typeCheck();\n'); // See https://github.com/BurntSushi/ripgrep/issues/1095
assert.strictEqual((<ITextSearchContext>results[2].results![0]).lineNumber, 27);
assert.strictEqual((<ITextSearchContext>results[2].results![0]).lineNumber, 26);
assert.strictEqual((<ITextSearchContext>results[2].results![0]).text, ' compiler.emit();');
assert.strictEqual((<ITextSearchContext>results[3].results![0]).lineNumber, 28);
assert.strictEqual((<ITextSearchContext>results[3].results![0]).lineNumber, 27);
assert.strictEqual((<ITextSearchContext>results[3].results![0]).text, '');
});
});
+5 -5
View File
@@ -6499,7 +6499,7 @@ declare module 'vscode' {
/**
* Outputs the given trace message to the channel. Use this method to log verbose information.
*
* The message is only loggeed if the channel is configured to display {@link LogLevel.Trace trace} log level.
* The message is only logged if the channel is configured to display {@link LogLevel.Trace trace} log level.
*
* @param message trace message to log
*/
@@ -6508,7 +6508,7 @@ declare module 'vscode' {
/**
* Outputs the given debug message to the channel.
*
* The message is only loggeed if the channel is configured to display {@link LogLevel.Debug debug} log level or lower.
* The message is only logged if the channel is configured to display {@link LogLevel.Debug debug} log level or lower.
*
* @param message debug message to log
*/
@@ -6517,7 +6517,7 @@ declare module 'vscode' {
/**
* Outputs the given information message to the channel.
*
* The message is only loggeed if the channel is configured to display {@link LogLevel.Info info} log level or lower.
* The message is only logged if the channel is configured to display {@link LogLevel.Info info} log level or lower.
*
* @param message info message to log
*/
@@ -6526,7 +6526,7 @@ declare module 'vscode' {
/**
* Outputs the given warning message to the channel.
*
* The message is only loggeed if the channel is configured to display {@link LogLevel.Warning warning} log level or lower.
* The message is only logged if the channel is configured to display {@link LogLevel.Warning warning} log level or lower.
*
* @param message warning message to log
*/
@@ -6535,7 +6535,7 @@ declare module 'vscode' {
/**
* Outputs the given error or error message to the channel.
*
* The message is only loggeed if the channel is configured to display {@link LogLevel.Error error} log level or lower.
* The message is only logged if the channel is configured to display {@link LogLevel.Error error} log level or lower.
*
* @param error Error or error message to log
*/
+8 -13
View File
@@ -1153,11 +1153,6 @@
resolved "https://registry.yarnpkg.com/@types/windows-foreground-love/-/windows-foreground-love-0.3.0.tgz#26bc230b2568aa7ab7c56d35bb5653c0a6965a42"
integrity sha512-tFUVA/fiofNqOh6lZlymvQiQYPY+cZXZPR9mn9wN6/KS8uwx0zgH4Ij/jmFyRYr+x+DGZWEIeknS2BMi7FZJAQ==
"@types/windows-mutex@^0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@types/windows-mutex/-/windows-mutex-0.4.0.tgz#d27070418aa26047c6c860c704952ff26aeb961b"
integrity sha512-zUMH4nutIURLARU6f10Ls6XcZWhUkwmzVEALs26dt1ZbaLv/qxsGdYiePUbwhQmrQUp3EPZ1HxopWpzzC8ot5A==
"@types/windows-process-tree@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@types/windows-process-tree/-/windows-process-tree-0.2.0.tgz#2fa205c838a8ef0a07697cd747c954653978d22c"
@@ -1391,6 +1386,14 @@
dependencies:
node-addon-api "^3.0.2"
"@vscode/windows-mutex@0.4.2":
version "0.4.2"
resolved "https://registry.yarnpkg.com/@vscode/windows-mutex/-/windows-mutex-0.4.2.tgz#3f796896c3bc2cf32bfe7148e608edb0cb7247db"
integrity sha512-7MSBH22cI7OwxXImjJ3VJ7QeHrEbumtyi/xqTgv6xqZCIZfUk/eu5MMBD2Vkehut8dGZU4xIjqt5AGdm0uPixQ==
dependencies:
bindings "^1.2.1"
nan "^2.14.0"
"@vscode/windows-registry@1.0.6":
version "1.0.6"
resolved "https://registry.yarnpkg.com/@vscode/windows-registry/-/windows-registry-1.0.6.tgz#8b9fb9a55bf5a0be4ea11849c45ae94c6910e3e4"
@@ -10842,14 +10845,6 @@ windows-foreground-love@0.5.0:
resolved "https://registry.yarnpkg.com/windows-foreground-love/-/windows-foreground-love-0.5.0.tgz#7672b04eb05f934a6543cacdc3cd16ff34e3cb10"
integrity sha512-yjBwmKEmQBDk3Z7yg/U9hizGWat8C6Pe4MQWl5bN6mvPU81Bt6HV2k/6mGlK3ETJLW1hCLhYx2wcGh+ykUUCyA==
windows-mutex@0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/windows-mutex/-/windows-mutex-0.4.1.tgz#2eccdfc312e15e7f212fb16280f060fc6b5f00cd"
integrity sha512-RW1xN6yzw8hAcfy1BKVClhJZg/PzuNz4Qz+CNhYmmdzJiwKSU9CqvVcmAvNrtdinNkXfSqTZVBVh5kUATg6xOA==
dependencies:
bindings "^1.2.1"
nan "^2.14.0"
windows-process-tree@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/windows-process-tree/-/windows-process-tree-0.4.0.tgz#31ac49c5da557e628ce7e37a5800972173d3349a"