mirror of
https://github.com/Microsoft/vscode
synced 2024-09-18 01:58:27 +00:00
Merge branch 'main' into tyriar/141599
This commit is contained in:
commit
f5fbf3b920
|
@ -209,13 +209,6 @@ function packageTask(sourceFolderName, destinationFolderName) {
|
||||||
gulp.src('resources/server/code-512.png', { base: 'resources/server' })
|
gulp.src('resources/server/code-512.png', { base: 'resources/server' })
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO@bpasero remove me in Feb
|
|
||||||
const legacyMain = es.merge(
|
|
||||||
gulp.src(sourceFolderName + '/vs/workbench/workbench.web.main.js').pipe(rename('out/vs/workbench/workbench.web.api.js')).pipe(replace('workbench.web.main', 'workbench.web.api')),
|
|
||||||
gulp.src(sourceFolderName + '/vs/workbench/workbench.web.main.css').pipe(rename('out/vs/workbench/workbench.web.api.css')),
|
|
||||||
gulp.src(sourceFolderName + '/vs/workbench/workbench.web.main.nls.js').pipe(rename('out/vs/workbench/workbench.web.api.nls.js')).pipe(replace('workbench.web.main', 'workbench.web.api'))
|
|
||||||
);
|
|
||||||
|
|
||||||
let all = es.merge(
|
let all = es.merge(
|
||||||
packageJsonStream,
|
packageJsonStream,
|
||||||
license,
|
license,
|
||||||
|
@ -223,8 +216,7 @@ function packageTask(sourceFolderName, destinationFolderName) {
|
||||||
deps,
|
deps,
|
||||||
favicon,
|
favicon,
|
||||||
manifest,
|
manifest,
|
||||||
pwaicons,
|
pwaicons
|
||||||
legacyMain
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let result = all
|
let result = all
|
||||||
|
|
|
@ -531,6 +531,11 @@
|
||||||
"title": "%command.rebaseAbort%",
|
"title": "%command.rebaseAbort%",
|
||||||
"category": "Git"
|
"category": "Git"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "git.closeAllDiffEditors",
|
||||||
|
"title": "%command.closeAllDiffEditors%",
|
||||||
|
"category": "Git"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "git.api.getRepositories",
|
"command": "git.api.getRepositories",
|
||||||
"title": "%command.api.getRepositories%",
|
"title": "%command.api.getRepositories%",
|
||||||
|
@ -933,6 +938,10 @@
|
||||||
"command": "git.timeline.compareWithSelected",
|
"command": "git.timeline.compareWithSelected",
|
||||||
"when": "false"
|
"when": "false"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "git.closeAllDiffEditors",
|
||||||
|
"when": "config.git.enabled && !git.missing && gitOpenRepositoryCount != 0"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "git.api.getRepositories",
|
"command": "git.api.getRepositories",
|
||||||
"when": "false"
|
"when": "false"
|
||||||
|
@ -2231,7 +2240,9 @@
|
||||||
"default",
|
"default",
|
||||||
"download"
|
"download"
|
||||||
],
|
],
|
||||||
"tags": ["experimental"],
|
"tags": [
|
||||||
|
"experimental"
|
||||||
|
],
|
||||||
"scope": "machine",
|
"scope": "machine",
|
||||||
"description": "%config.experimental.installGuide%",
|
"description": "%config.experimental.installGuide%",
|
||||||
"default": "default"
|
"default": "default"
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
"command.cleanAll": "Discard All Changes",
|
"command.cleanAll": "Discard All Changes",
|
||||||
"command.cleanAllTracked": "Discard All Tracked Changes",
|
"command.cleanAllTracked": "Discard All Tracked Changes",
|
||||||
"command.cleanAllUntracked": "Discard All Untracked Changes",
|
"command.cleanAllUntracked": "Discard All Untracked Changes",
|
||||||
|
"command.closeAllDiffEditors": "Close All Diff Editors",
|
||||||
"command.commit": "Commit",
|
"command.commit": "Commit",
|
||||||
"command.commitStaged": "Commit Staged",
|
"command.commitStaged": "Commit Staged",
|
||||||
"command.commitEmpty": "Commit Empty",
|
"command.commitEmpty": "Commit Empty",
|
||||||
|
|
|
@ -2753,6 +2753,17 @@ export class CommandCenter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@command('git.closeAllDiffEditors', { repository: true })
|
||||||
|
closeDiffEditors(repository: Repository): void {
|
||||||
|
const resources = [
|
||||||
|
...repository.indexGroup.resourceStates.map(r => r.resourceUri.fsPath),
|
||||||
|
...repository.workingTreeGroup.resourceStates.map(r => r.resourceUri.fsPath),
|
||||||
|
...repository.untrackedGroup.resourceStates.map(r => r.resourceUri.fsPath)
|
||||||
|
];
|
||||||
|
|
||||||
|
repository.closeDiffEditors(resources, resources, true);
|
||||||
|
}
|
||||||
|
|
||||||
private createCommand(id: string, key: string, method: Function, options: ScmCommandOptions): (...args: any[]) => any {
|
private createCommand(id: string, key: string, method: Function, options: ScmCommandOptions): (...args: any[]) => any {
|
||||||
const result = (...args: any[]) => {
|
const result = (...args: any[]) => {
|
||||||
let result: Promise<any>;
|
let result: Promise<any>;
|
||||||
|
|
|
@ -2043,7 +2043,6 @@ export class Repository {
|
||||||
|
|
||||||
if (branchName.startsWith('refs/heads/')) {
|
if (branchName.startsWith('refs/heads/')) {
|
||||||
branchName = branchName.substring(11);
|
branchName = branchName.substring(11);
|
||||||
const index = upstream.indexOf('/');
|
|
||||||
|
|
||||||
let ahead;
|
let ahead;
|
||||||
let behind;
|
let behind;
|
||||||
|
@ -2056,8 +2055,8 @@ export class Repository {
|
||||||
type: RefType.Head,
|
type: RefType.Head,
|
||||||
name: branchName,
|
name: branchName,
|
||||||
upstream: upstream ? {
|
upstream: upstream ? {
|
||||||
name: upstream.substring(index + 1),
|
name: upstream.substring(upstream.length - branchName.length),
|
||||||
remote: upstream.substring(0, index)
|
remote: upstream.substring(0, upstream.length - branchName.length - 1)
|
||||||
} : undefined,
|
} : undefined,
|
||||||
commit: ref || undefined,
|
commit: ref || undefined,
|
||||||
ahead: Number(ahead) || 0,
|
ahead: Number(ahead) || 0,
|
||||||
|
|
|
@ -1266,9 +1266,9 @@ export class Repository implements Disposable {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private closeDiffEditors(indexResources: string[], workingTreeResources: string[]): void {
|
closeDiffEditors(indexResources: string[], workingTreeResources: string[], ignoreSetting: boolean = false): void {
|
||||||
const config = workspace.getConfiguration('git', Uri.file(this.root));
|
const config = workspace.getConfiguration('git', Uri.file(this.root));
|
||||||
if (!config.get<boolean>('closeDiffOnOperation', false)) { return; }
|
if (!config.get<boolean>('closeDiffOnOperation', false) && !ignoreSetting) { return; }
|
||||||
|
|
||||||
const diffEditorTabsToClose: Tab[] = [];
|
const diffEditorTabsToClose: Tab[] = [];
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
"keytar": "7.6.0",
|
"keytar": "7.6.0",
|
||||||
"minimist": "^1.2.5",
|
"minimist": "^1.2.5",
|
||||||
"native-is-elevated": "0.4.3",
|
"native-is-elevated": "0.4.3",
|
||||||
"native-keymap": "3.1.0",
|
"native-keymap": "3.2.1",
|
||||||
"native-watchdog": "1.3.0",
|
"native-watchdog": "1.3.0",
|
||||||
"node-pty": "0.11.0-beta11",
|
"node-pty": "0.11.0-beta11",
|
||||||
"spdlog": "^0.13.0",
|
"spdlog": "^0.13.0",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"licenseFileName": "LICENSE.txt",
|
"licenseFileName": "LICENSE.txt",
|
||||||
"reportIssueUrl": "https://github.com/microsoft/vscode/issues/new",
|
"reportIssueUrl": "https://github.com/microsoft/vscode/issues/new",
|
||||||
"urlProtocol": "code-oss",
|
"urlProtocol": "code-oss",
|
||||||
"webviewContentExternalBaseUrlTemplate": "https://{{uuid}}.vscode-webview.net/insider/d372f9187401bd145a0a6e15ba369e2d82d02005/out/vs/workbench/contrib/webview/browser/pre/",
|
"webviewContentExternalBaseUrlTemplate": "https://{{uuid}}.vscode-webview.net/insider/50089c3f92c17584a4aca179f51f220b56c22020/out/vs/workbench/contrib/webview/browser/pre/",
|
||||||
"extensionAllowedProposedApi": [
|
"extensionAllowedProposedApi": [
|
||||||
"ms-vscode.vscode-js-profile-flame",
|
"ms-vscode.vscode-js-profile-flame",
|
||||||
"ms-vscode.vscode-js-profile-table",
|
"ms-vscode.vscode-js-profile-table",
|
||||||
|
|
|
@ -51,13 +51,45 @@ class WindowManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#monitoring_screen_resolution_or_zoom_level_changes
|
||||||
|
*/
|
||||||
|
class DevicePixelRatioMonitor extends Disposable {
|
||||||
|
|
||||||
|
private readonly _onDidChange = this._register(new Emitter<void>());
|
||||||
|
public readonly onDidChange = this._onDidChange.event;
|
||||||
|
|
||||||
|
private readonly _listener: () => void;
|
||||||
|
private _mediaQueryList: MediaQueryList | null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._listener = () => this._handleChange(true);
|
||||||
|
this._mediaQueryList = null;
|
||||||
|
this._handleChange(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleChange(fireEvent: boolean): void {
|
||||||
|
if (this._mediaQueryList) {
|
||||||
|
this._mediaQueryList.removeEventListener('change', this._listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._mediaQueryList = matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
|
||||||
|
this._mediaQueryList.addEventListener('change', this._listener);
|
||||||
|
|
||||||
|
if (fireEvent) {
|
||||||
|
this._onDidChange.fire();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PixelRatioImpl extends Disposable {
|
class PixelRatioImpl extends Disposable {
|
||||||
|
|
||||||
private readonly _onDidChange = this._register(new Emitter<number>());
|
private readonly _onDidChange = this._register(new Emitter<number>());
|
||||||
public readonly onDidChange = this._onDidChange.event;
|
public readonly onDidChange = this._onDidChange.event;
|
||||||
|
|
||||||
private _value: number;
|
private _value: number;
|
||||||
private _removeListener: () => void;
|
|
||||||
|
|
||||||
public get value(): number {
|
public get value(): number {
|
||||||
return this._value;
|
return this._value;
|
||||||
|
@ -67,28 +99,12 @@ class PixelRatioImpl extends Disposable {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._value = this._getPixelRatio();
|
this._value = this._getPixelRatio();
|
||||||
this._removeListener = this._installResolutionListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override dispose() {
|
const dprMonitor = this._register(new DevicePixelRatioMonitor());
|
||||||
this._removeListener();
|
this._register(dprMonitor.onDidChange(() => {
|
||||||
super.dispose();
|
this._value = this._getPixelRatio();
|
||||||
}
|
this._onDidChange.fire(this._value);
|
||||||
|
}));
|
||||||
private _installResolutionListener(): () => void {
|
|
||||||
// See https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#monitoring_screen_resolution_or_zoom_level_changes
|
|
||||||
const mediaQueryList = matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
|
|
||||||
const listener = () => this._updateValue();
|
|
||||||
mediaQueryList.addEventListener('change', listener);
|
|
||||||
return () => {
|
|
||||||
mediaQueryList.removeEventListener('change', listener);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private _updateValue(): void {
|
|
||||||
this._value = this._getPixelRatio();
|
|
||||||
this._onDidChange.fire(this._value);
|
|
||||||
this._removeListener = this._installResolutionListener();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getPixelRatio(): number {
|
private _getPixelRatio(): number {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { DistributeSizing, ISplitViewStyles, IView as ISplitView, LayoutPriority
|
||||||
import { equals as arrayEquals, tail2 as tail } from 'vs/base/common/arrays';
|
import { equals as arrayEquals, tail2 as tail } from 'vs/base/common/arrays';
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
import { Emitter, Event, Relay } from 'vs/base/common/event';
|
import { Emitter, Event, Relay } from 'vs/base/common/event';
|
||||||
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { rot } from 'vs/base/common/numbers';
|
import { rot } from 'vs/base/common/numbers';
|
||||||
import { isUndefined } from 'vs/base/common/types';
|
import { isUndefined } from 'vs/base/common/types';
|
||||||
import 'vs/css!./gridview';
|
import 'vs/css!./gridview';
|
||||||
|
@ -775,6 +775,8 @@ class LeafNode implements ISplitView<ILayoutContext>, IDisposable {
|
||||||
private _onDidViewChange: Event<number | undefined>;
|
private _onDidViewChange: Event<number | undefined>;
|
||||||
readonly onDidChange: Event<number | undefined>;
|
readonly onDidChange: Event<number | undefined>;
|
||||||
|
|
||||||
|
private disposables = new DisposableStore();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly view: IView,
|
readonly view: IView,
|
||||||
readonly orientation: Orientation,
|
readonly orientation: Orientation,
|
||||||
|
@ -786,7 +788,7 @@ class LeafNode implements ISplitView<ILayoutContext>, IDisposable {
|
||||||
this._size = size;
|
this._size = size;
|
||||||
|
|
||||||
const onDidChange = createLatchedOnDidChangeViewEvent(view);
|
const onDidChange = createLatchedOnDidChangeViewEvent(view);
|
||||||
this._onDidViewChange = Event.map(onDidChange, e => e && (this.orientation === Orientation.VERTICAL ? e.width : e.height));
|
this._onDidViewChange = Event.map(onDidChange, e => e && (this.orientation === Orientation.VERTICAL ? e.width : e.height), this.disposables);
|
||||||
this.onDidChange = Event.any(this._onDidViewChange, this._onDidSetLinkedNode.event, this._onDidLinkedWidthNodeChange.event, this._onDidLinkedHeightNodeChange.event);
|
this.onDidChange = Event.any(this._onDidViewChange, this._onDidSetLinkedNode.event, this._onDidLinkedWidthNodeChange.event, this._onDidLinkedHeightNodeChange.event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -900,7 +902,9 @@ class LeafNode implements ISplitView<ILayoutContext>, IDisposable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose(): void { }
|
dispose(): void {
|
||||||
|
this.disposables.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Node = BranchNode | LeafNode;
|
type Node = BranchNode | LeafNode;
|
||||||
|
|
|
@ -434,6 +434,7 @@ export class TextModel extends Disposable implements model.ITextModel, IDecorati
|
||||||
const emptyDisposedTextBuffer = new PieceTreeTextBuffer([], '', '\n', false, false, true, true);
|
const emptyDisposedTextBuffer = new PieceTreeTextBuffer([], '', '\n', false, false, true, true);
|
||||||
emptyDisposedTextBuffer.dispose();
|
emptyDisposedTextBuffer.dispose();
|
||||||
this._buffer = emptyDisposedTextBuffer;
|
this._buffer = emptyDisposedTextBuffer;
|
||||||
|
this._bufferDisposable = Disposable.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _assertNotDisposed(): void {
|
private _assertNotDisposed(): void {
|
||||||
|
|
|
@ -66,7 +66,6 @@ export class UserDataSyncEnablementService extends Disposable implements IUserDa
|
||||||
setResourceEnablement(resource: SyncResource, enabled: boolean): void {
|
setResourceEnablement(resource: SyncResource, enabled: boolean): void {
|
||||||
if (this.isResourceEnabled(resource) !== enabled) {
|
if (this.isResourceEnabled(resource) !== enabled) {
|
||||||
const resourceEnablementKey = getEnablementKey(resource);
|
const resourceEnablementKey = getEnablementKey(resource);
|
||||||
this.telemetryService.publicLog2<{ enabled: boolean }, SyncEnablementClassification>(resourceEnablementKey, { enabled });
|
|
||||||
this.storeResourceEnablement(resourceEnablementKey, enabled);
|
this.storeResourceEnablement(resourceEnablementKey, enabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
import 'vs/workbench/browser/style';
|
import 'vs/workbench/browser/style';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { Event, Emitter, setGlobalLeakWarningThreshold } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { RunOnceScheduler, runWhenIdle, timeout } from 'vs/base/common/async';
|
import { RunOnceScheduler, runWhenIdle, timeout } from 'vs/base/common/async';
|
||||||
import { isFirefox, isSafari, isChrome, PixelRatio } from 'vs/base/browser/browser';
|
import { isFirefox, isSafari, isChrome, PixelRatio } from 'vs/base/browser/browser';
|
||||||
import { mark } from 'vs/base/common/performance';
|
import { mark } from 'vs/base/common/performance';
|
||||||
|
@ -133,7 +133,9 @@ export class Workbench extends Layout {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Configure emitter leak warning threshold
|
// Configure emitter leak warning threshold
|
||||||
setGlobalLeakWarningThreshold(175);
|
// TODO@jrieken: This is temporarily commented out
|
||||||
|
// due to https://github.com/microsoft/vscode/issues/143111
|
||||||
|
// setGlobalLeakWarningThreshold(175);
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
const instantiationService = this.initServices(this.serviceCollection);
|
const instantiationService = this.initServices(this.serviceCollection);
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||||
|
import { AudioCue, IAudioCueService } from 'vs/workbench/contrib/audioCues/browser/audioCueService';
|
||||||
|
import { IDebugService, State } from 'vs/workbench/contrib/debug/common/debug';
|
||||||
|
|
||||||
|
export class AudioCueLineDebuggerContribution
|
||||||
|
extends Disposable
|
||||||
|
implements IWorkbenchContribution {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@IDebugService debugService: IDebugService,
|
||||||
|
@IAudioCueService audioCueService: IAudioCueService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._register(debugService.onDidChangeState(e => {
|
||||||
|
if (e === State.Stopped) {
|
||||||
|
audioCueService.playAudioCue(AudioCue.executionStopped);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,8 +16,9 @@ import { autorun, autorunDelta, constObservable, debouncedObservable, fromEvent,
|
||||||
import { ITextModel } from 'vs/editor/common/model';
|
import { ITextModel } from 'vs/editor/common/model';
|
||||||
import { GhostTextController } from 'vs/editor/contrib/inlineCompletions/browser/ghostTextController';
|
import { GhostTextController } from 'vs/editor/contrib/inlineCompletions/browser/ghostTextController';
|
||||||
import { AudioCue, IAudioCueService } from 'vs/workbench/contrib/audioCues/browser/audioCueService';
|
import { AudioCue, IAudioCueService } from 'vs/workbench/contrib/audioCues/browser/audioCueService';
|
||||||
|
import { CursorChangeReason } from 'vs/editor/common/cursorEvents';
|
||||||
|
|
||||||
export class AudioCueContribution
|
export class AudioCueLineFeatureContribution
|
||||||
extends Disposable
|
extends Disposable
|
||||||
implements IWorkbenchContribution {
|
implements IWorkbenchContribution {
|
||||||
private readonly store = this._register(new DisposableStore());
|
private readonly store = this._register(new DisposableStore());
|
||||||
|
@ -88,7 +89,13 @@ export class AudioCueContribution
|
||||||
|
|
||||||
const curLineNumber = fromEvent(
|
const curLineNumber = fromEvent(
|
||||||
editor.onDidChangeCursorPosition,
|
editor.onDidChangeCursorPosition,
|
||||||
() => editor.getPosition()?.lineNumber
|
(args) => {
|
||||||
|
if (args && args.reason !== CursorChangeReason.Explicit) {
|
||||||
|
// Ignore cursor changes caused by navigation (e.g. which happens when execution is paused).
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return editor.getPosition()?.lineNumber;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
const debouncedLineNumber = debouncedObservable(curLineNumber, 100, store);
|
const debouncedLineNumber = debouncedObservable(curLineNumber, 100, store);
|
||||||
|
|
|
@ -148,6 +148,12 @@ export class AudioCue {
|
||||||
settingsKey: 'audioCues.lineHasInlineSuggestion',
|
settingsKey: 'audioCues.lineHasInlineSuggestion',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
public static readonly executionStopped = AudioCue.register({
|
||||||
|
name: 'Debugger Execution Paused',
|
||||||
|
sound: Sound.break,
|
||||||
|
settingsKey: 'audioCues.debuggerExecutionPaused',
|
||||||
|
});
|
||||||
|
|
||||||
private constructor(
|
private constructor(
|
||||||
public readonly sound: Sound,
|
public readonly sound: Sound,
|
||||||
public readonly name: string,
|
public readonly name: string,
|
||||||
|
|
|
@ -9,14 +9,16 @@ import { Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IC
|
||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||||
import { AudioCueContribution } from 'vs/workbench/contrib/audioCues/browser/audioCueContribution';
|
import { AudioCueLineDebuggerContribution } from 'vs/workbench/contrib/audioCues/browser/audioCueDebuggerContribution';
|
||||||
|
import { AudioCueLineFeatureContribution } from 'vs/workbench/contrib/audioCues/browser/audioCueLineFeatureContribution';
|
||||||
import { AudioCueService, IAudioCueService } from 'vs/workbench/contrib/audioCues/browser/audioCueService';
|
import { AudioCueService, IAudioCueService } from 'vs/workbench/contrib/audioCues/browser/audioCueService';
|
||||||
import { ShowAudioCueHelp } from 'vs/workbench/contrib/audioCues/browser/commands';
|
import { ShowAudioCueHelp } from 'vs/workbench/contrib/audioCues/browser/commands';
|
||||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||||
|
|
||||||
registerSingleton(IAudioCueService, AudioCueService);
|
registerSingleton(IAudioCueService, AudioCueService);
|
||||||
|
|
||||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(AudioCueContribution, LifecyclePhase.Restored);
|
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(AudioCueLineFeatureContribution, LifecyclePhase.Restored);
|
||||||
|
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(AudioCueLineDebuggerContribution, LifecyclePhase.Restored);
|
||||||
|
|
||||||
const audioCueFeatureBase: IConfigurationPropertySchema = {
|
const audioCueFeatureBase: IConfigurationPropertySchema = {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
|
@ -55,6 +57,10 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).regis
|
||||||
...audioCueFeatureBase,
|
...audioCueFeatureBase,
|
||||||
default: 'off',
|
default: 'off',
|
||||||
},
|
},
|
||||||
|
'audioCues.debuggerExecutionPaused': {
|
||||||
|
'description': localize('audioCues.debuggerExecutionPaused', "Plays an audio cue when the debugger paused."),
|
||||||
|
...audioCueFeatureBase,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -18,16 +18,19 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { WorkbenchAsyncDataTree, IListService, IWorkbenchAsyncDataTreeOptions } from 'vs/platform/list/browser/listService';
|
import { WorkbenchAsyncDataTree, IListService, IWorkbenchAsyncDataTreeOptions } from 'vs/platform/list/browser/listService';
|
||||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IColorMapping } from 'vs/platform/theme/common/styler';
|
import { IColorMapping } from 'vs/platform/theme/common/styler';
|
||||||
|
import { TimestampWidget } from 'vs/workbench/contrib/comments/browser/timestamp';
|
||||||
|
import { Codicon } from 'vs/base/common/codicons';
|
||||||
|
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||||
|
|
||||||
export const COMMENTS_VIEW_ID = 'workbench.panel.comments';
|
export const COMMENTS_VIEW_ID = 'workbench.panel.comments';
|
||||||
export const COMMENTS_VIEW_TITLE = 'Comments';
|
export const COMMENTS_VIEW_TITLE = 'Comments';
|
||||||
|
|
||||||
export class CommentsAsyncDataSource implements IAsyncDataSource<any, any> {
|
export class CommentsAsyncDataSource implements IAsyncDataSource<any, any> {
|
||||||
hasChildren(element: any): boolean {
|
hasChildren(element: any): boolean {
|
||||||
return element instanceof CommentsModel || element instanceof ResourceWithCommentThreads || (element instanceof CommentNode && !!element.replies.length);
|
return (element instanceof CommentsModel || element instanceof ResourceWithCommentThreads) && !(element instanceof CommentNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
getChildren(element: any): any[] | Promise<any[]> {
|
getChildren(element: any): any[] | Promise<any[]> {
|
||||||
|
@ -37,9 +40,6 @@ export class CommentsAsyncDataSource implements IAsyncDataSource<any, any> {
|
||||||
if (element instanceof ResourceWithCommentThreads) {
|
if (element instanceof ResourceWithCommentThreads) {
|
||||||
return Promise.resolve(element.commentThreads);
|
return Promise.resolve(element.commentThreads);
|
||||||
}
|
}
|
||||||
if (element instanceof CommentNode) {
|
|
||||||
return Promise.resolve(element.replies);
|
|
||||||
}
|
|
||||||
return Promise.resolve([]);
|
return Promise.resolve([]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,9 +49,21 @@ interface IResourceTemplateData {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ICommentThreadTemplateData {
|
interface ICommentThreadTemplateData {
|
||||||
icon: HTMLImageElement;
|
threadMetadata: {
|
||||||
userName: HTMLSpanElement;
|
icon?: HTMLElement;
|
||||||
commentText: HTMLElement;
|
userNames: HTMLSpanElement;
|
||||||
|
timestamp: TimestampWidget;
|
||||||
|
separator: HTMLElement;
|
||||||
|
commentPreview: HTMLSpanElement;
|
||||||
|
};
|
||||||
|
repliesMetadata: {
|
||||||
|
container: HTMLElement;
|
||||||
|
icon: HTMLElement;
|
||||||
|
count: HTMLSpanElement;
|
||||||
|
lastReplyDetail: HTMLSpanElement;
|
||||||
|
separator: HTMLElement;
|
||||||
|
timestamp: TimestampWidget;
|
||||||
|
};
|
||||||
disposables: IDisposable[];
|
disposables: IDisposable[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +73,9 @@ export class CommentsModelVirualDelegate implements IListVirtualDelegate<any> {
|
||||||
|
|
||||||
|
|
||||||
getHeight(element: any): number {
|
getHeight(element: any): number {
|
||||||
|
if ((element instanceof CommentNode) && element.hasReply()) {
|
||||||
|
return 44;
|
||||||
|
}
|
||||||
return 22;
|
return 22;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,50 +120,97 @@ export class CommentNodeRenderer implements IListRenderer<ITreeNode<CommentNode>
|
||||||
templateId: string = 'comment-node';
|
templateId: string = 'comment-node';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IOpenerService private readonly openerService: IOpenerService
|
@IOpenerService private readonly openerService: IOpenerService,
|
||||||
|
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
renderTemplate(container: HTMLElement) {
|
renderTemplate(container: HTMLElement) {
|
||||||
const data = <ICommentThreadTemplateData>Object.create(null);
|
const data = <ICommentThreadTemplateData>Object.create(null);
|
||||||
const labelContainer = dom.append(container, dom.$('.comment-container'));
|
|
||||||
data.userName = dom.append(labelContainer, dom.$('.user'));
|
const threadContainer = dom.append(container, dom.$('.comment-thread-container'));
|
||||||
data.commentText = dom.append(labelContainer, dom.$('.text'));
|
const metadataContainer = dom.append(threadContainer, dom.$('.comment-metadata-container'));
|
||||||
data.disposables = [];
|
data.threadMetadata = {
|
||||||
|
icon: dom.append(metadataContainer, dom.$('.icon')),
|
||||||
|
userNames: dom.append(metadataContainer, dom.$('.user')),
|
||||||
|
timestamp: new TimestampWidget(this.configurationService, dom.append(metadataContainer, dom.$('.timestamp-container'))),
|
||||||
|
separator: dom.append(metadataContainer, dom.$('.separator')),
|
||||||
|
commentPreview: dom.append(metadataContainer, dom.$('.text'))
|
||||||
|
};
|
||||||
|
data.threadMetadata.separator.innerText = '\u00b7';
|
||||||
|
|
||||||
|
const snippetContainer = dom.append(threadContainer, dom.$('.comment-snippet-container'));
|
||||||
|
data.repliesMetadata = {
|
||||||
|
container: snippetContainer,
|
||||||
|
icon: dom.append(snippetContainer, dom.$('.icon')),
|
||||||
|
count: dom.append(snippetContainer, dom.$('.count')),
|
||||||
|
lastReplyDetail: dom.append(snippetContainer, dom.$('.reply-detail')),
|
||||||
|
separator: dom.append(snippetContainer, dom.$('.separator')),
|
||||||
|
timestamp: new TimestampWidget(this.configurationService, dom.append(snippetContainer, dom.$('.timestamp-container'))),
|
||||||
|
};
|
||||||
|
data.repliesMetadata.separator.innerText = '\u00b7';
|
||||||
|
data.repliesMetadata.icon.classList.add(...ThemeIcon.asClassNameArray(Codicon.indent));
|
||||||
|
data.disposables = [data.threadMetadata.timestamp, data.repliesMetadata.timestamp];
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderElement(node: ITreeNode<CommentNode>, index: number, templateData: ICommentThreadTemplateData, height: number | undefined): void {
|
private getCountString(commentCount: number): string {
|
||||||
templateData.userName.textContent = node.element.comment.userName;
|
if (commentCount > 1) {
|
||||||
templateData.commentText.innerText = '';
|
return nls.localize('commentsCount', "{0} comments", commentCount);
|
||||||
if (typeof node.element.comment.body === 'string') {
|
} else {
|
||||||
templateData.commentText.innerText = node.element.comment.body;
|
return nls.localize('commentCount', "1 comment");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRenderedComment(commentBody: IMarkdownString, disposables: DisposableStore) {
|
||||||
|
const renderedComment = renderMarkdown(commentBody, {
|
||||||
|
inline: true,
|
||||||
|
actionHandler: {
|
||||||
|
callback: (content) => {
|
||||||
|
this.openerService.open(content, { allowCommands: commentBody.isTrusted }).catch(onUnexpectedError);
|
||||||
|
},
|
||||||
|
disposables: disposables
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const images = renderedComment.element.getElementsByTagName('img');
|
||||||
|
for (let i = 0; i < images.length; i++) {
|
||||||
|
const image = images[i];
|
||||||
|
const textDescription = dom.$('');
|
||||||
|
textDescription.textContent = image.alt ? nls.localize('imageWithLabel', "Image: {0}", image.alt) : nls.localize('image', "Image");
|
||||||
|
image.parentNode!.replaceChild(textDescription, image);
|
||||||
|
}
|
||||||
|
return renderedComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderElement(node: ITreeNode<CommentNode>, index: number, templateData: ICommentThreadTemplateData, height: number | undefined): void {
|
||||||
|
const commentCount = node.element.replies.length + 1;
|
||||||
|
templateData.threadMetadata.icon?.classList.add(...ThemeIcon.asClassNameArray((commentCount === 1) ? Codicon.comment : Codicon.commentDiscussion));
|
||||||
|
templateData.threadMetadata.userNames.textContent = node.element.comment.userName;
|
||||||
|
templateData.threadMetadata.timestamp.setTimestamp(node.element.comment.timestamp ? new Date(node.element.comment.timestamp) : undefined);
|
||||||
|
const originalComment = node.element;
|
||||||
|
|
||||||
|
templateData.threadMetadata.commentPreview.innerText = '';
|
||||||
|
if (typeof originalComment.comment.body === 'string') {
|
||||||
|
templateData.threadMetadata.commentPreview.innerText = originalComment.comment.body;
|
||||||
} else {
|
} else {
|
||||||
const commentBody = node.element.comment.body;
|
|
||||||
const disposables = new DisposableStore();
|
const disposables = new DisposableStore();
|
||||||
templateData.disposables.push(disposables);
|
templateData.disposables.push(disposables);
|
||||||
const renderedComment = renderMarkdown(commentBody, {
|
const renderedComment = this.getRenderedComment(originalComment.comment.body, disposables);
|
||||||
inline: true,
|
|
||||||
actionHandler: {
|
|
||||||
callback: (content) => {
|
|
||||||
this.openerService.open(content, { allowCommands: commentBody.isTrusted }).catch(onUnexpectedError);
|
|
||||||
},
|
|
||||||
disposables: disposables
|
|
||||||
}
|
|
||||||
});
|
|
||||||
templateData.disposables.push(renderedComment);
|
templateData.disposables.push(renderedComment);
|
||||||
|
templateData.threadMetadata.commentPreview.appendChild(renderedComment.element);
|
||||||
const images = renderedComment.element.getElementsByTagName('img');
|
templateData.threadMetadata.commentPreview.title = renderedComment.element.textContent ?? '';
|
||||||
for (let i = 0; i < images.length; i++) {
|
|
||||||
const image = images[i];
|
|
||||||
const textDescription = dom.$('');
|
|
||||||
textDescription.textContent = image.alt ? nls.localize('imageWithLabel', "Image: {0}", image.alt) : nls.localize('image', "Image");
|
|
||||||
image.parentNode!.replaceChild(textDescription, image);
|
|
||||||
}
|
|
||||||
|
|
||||||
templateData.commentText.appendChild(renderedComment.element);
|
|
||||||
templateData.commentText.title = renderedComment.element.textContent ?? '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!node.element.hasReply()) {
|
||||||
|
templateData.repliesMetadata.container.style.display = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
templateData.repliesMetadata.container.style.display = '';
|
||||||
|
templateData.repliesMetadata.count.textContent = this.getCountString(commentCount);
|
||||||
|
templateData.repliesMetadata.lastReplyDetail.textContent = nls.localize('lastReplyFrom', "Last reply from {0}", node.element.replies[node.element.replies.length - 1].comment.userName);
|
||||||
|
templateData.repliesMetadata.timestamp.setTimestamp(originalComment.comment.timestamp ? new Date(originalComment.comment.timestamp) : undefined);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
disposeTemplate(templateData: ICommentThreadTemplateData): void {
|
disposeTemplate(templateData: ICommentThreadTemplateData): void {
|
||||||
|
|
|
@ -68,6 +68,7 @@ export class CommentsPanel extends ViewPane {
|
||||||
|
|
||||||
let domContainer = dom.append(container, dom.$('.comments-panel-container'));
|
let domContainer = dom.append(container, dom.$('.comments-panel-container'));
|
||||||
this.treeContainer = dom.append(domContainer, dom.$('.tree-container'));
|
this.treeContainer = dom.append(domContainer, dom.$('.tree-container'));
|
||||||
|
this.treeContainer.classList.add('file-icon-themable-tree', 'show-file-icons');
|
||||||
this.commentsModel = new CommentsModel();
|
this.commentsModel = new CommentsModel();
|
||||||
|
|
||||||
this.createTree();
|
this.createTree();
|
||||||
|
|
|
@ -20,31 +20,57 @@
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.comments-panel .comments-panel-container .tree-container .resource-container,
|
.comments-panel .comments-panel-container .tree-container .resource-container,
|
||||||
.comments-panel .comments-panel-container .tree-container .comment-container {
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container .comment-metadata-container,
|
||||||
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container .comment-snippet-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comments-panel .count,
|
||||||
.comments-panel .user {
|
.comments-panel .user {
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
opacity: 0.5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.comments-panel .comments-panel-container .tree-container .comment-container .text {
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container .icon {
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container .comment-metadata-container .count,
|
||||||
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container .comment-snippet-container .text {
|
||||||
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comments-panel .comments-panel-container .tree-container .comment-container .text * {
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container .reply-detail,
|
||||||
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container .timestamp {
|
||||||
|
display:flex;
|
||||||
|
font-size: 0.9em;
|
||||||
|
padding-right: 5px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container .text * {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
max-width: 500px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comments-panel .comments-panel-container .tree-container .comment-container .text code {
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container .comment-snippet-container .text code {
|
||||||
font-family: var(--monaco-monospace-font);
|
font-family: var(--monaco-monospace-font);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container .separator {
|
||||||
|
padding-right: 5px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
.comments-panel .comments-panel-container .message-box-container {
|
.comments-panel .comments-panel-container .message-box-container {
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
|
@ -55,7 +81,12 @@
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comments-panel .comments-panel-container .tree-container .comment-container {
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container .comment-metadata-container,
|
||||||
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container .comment-snippet-container {
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comments-panel .comments-panel-container .tree-container .comment-thread-container .comment-snippet-container {
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ export class TimestampWidget extends Disposable {
|
||||||
constructor(private configurationService: IConfigurationService, container: HTMLElement, timeStamp?: Date) {
|
constructor(private configurationService: IConfigurationService, container: HTMLElement, timeStamp?: Date) {
|
||||||
super();
|
super();
|
||||||
this._date = dom.append(container, dom.$('span.timestamp'));
|
this._date = dom.append(container, dom.$('span.timestamp'));
|
||||||
|
this._date.style.display = 'none';
|
||||||
this._useRelativeTime = this.useRelativeTimeSetting;
|
this._useRelativeTime = this.useRelativeTimeSetting;
|
||||||
this.setTimestamp(timeStamp);
|
this.setTimestamp(timeStamp);
|
||||||
}
|
}
|
||||||
|
@ -37,9 +38,10 @@ export class TimestampWidget extends Disposable {
|
||||||
private updateDate(timestamp?: Date) {
|
private updateDate(timestamp?: Date) {
|
||||||
if (!timestamp) {
|
if (!timestamp) {
|
||||||
this._date.textContent = '';
|
this._date.textContent = '';
|
||||||
|
this._date.style.display = 'none';
|
||||||
} else if ((timestamp !== this._timestamp)
|
} else if ((timestamp !== this._timestamp)
|
||||||
|| (this.useRelativeTimeSetting !== this._useRelativeTime)) {
|
|| (this.useRelativeTimeSetting !== this._useRelativeTime)) {
|
||||||
|
this._date.style.display = '';
|
||||||
let textContent: string;
|
let textContent: string;
|
||||||
let tooltip: string | undefined;
|
let tooltip: string | undefined;
|
||||||
if (this.useRelativeTimeSetting) {
|
if (this.useRelativeTimeSetting) {
|
||||||
|
|
|
@ -280,19 +280,28 @@ export const VIEW_CONTAINER: ViewContainer = viewContainerRegistry.registerViewC
|
||||||
},
|
},
|
||||||
}, ViewContainerLocation.Sidebar, { isDefault: true });
|
}, ViewContainerLocation.Sidebar, { isDefault: true });
|
||||||
|
|
||||||
|
const openFolder = localize('openFolder', "Open Folder");
|
||||||
|
const addAFolder = localize('addAFolder', "add a folder");
|
||||||
|
|
||||||
|
const addRootFolderButton = `[${openFolder}](command:${AddRootFolderAction.ID})`;
|
||||||
|
const addAFolderButton = `[${addAFolder}](command:${AddRootFolderAction.ID})`;
|
||||||
|
|
||||||
|
const commandId = (isMacintosh && !isWeb) ? OpenFileFolderAction.ID : OpenFolderAction.ID;
|
||||||
|
const openFolderButton = `[${openFolder}](command:${commandId})`;
|
||||||
|
|
||||||
|
|
||||||
const viewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
|
const viewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
|
||||||
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
||||||
content: localize({ key: 'noWorkspaceHelp', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
|
content: localize({ key: 'noWorkspaceHelp', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
|
||||||
"You have not yet added a folder to the workspace.\n[Open Folder](command:{0})", AddRootFolderAction.ID),
|
"You have not yet added a folder to the workspace.\n{0}", addRootFolderButton),
|
||||||
when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('workspace'), IsIOSContext.toNegated()),
|
when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('workspace'), IsIOSContext.toNegated()),
|
||||||
group: ViewContentGroups.Open,
|
group: ViewContentGroups.Open,
|
||||||
order: 1
|
order: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
const commandId = (isMacintosh && !isWeb) ? OpenFileFolderAction.ID : OpenFolderAction.ID;
|
|
||||||
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
||||||
content: localize({ key: 'remoteNoFolderHelp', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
|
content: localize({ key: 'remoteNoFolderHelp', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
|
||||||
"Connected to remote.\n[Open Folder](command:{0})", commandId),
|
"Connected to remote.\n{0}", openFolderButton),
|
||||||
when: ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.notEqualsTo(''), IsWebContext.toNegated()),
|
when: ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.notEqualsTo(''), IsWebContext.toNegated()),
|
||||||
group: ViewContentGroups.Open,
|
group: ViewContentGroups.Open,
|
||||||
order: 1
|
order: 1
|
||||||
|
@ -300,7 +309,7 @@ viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
||||||
|
|
||||||
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
||||||
content: localize({ key: 'noFolderButEditorsHelp', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
|
content: localize({ key: 'noFolderButEditorsHelp', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
|
||||||
"You have not yet opened a folder.\n[Open Folder](command:{0})\nOpening a folder will close all currently open editors. To keep them open, [add a folder](command:{1}) instead.", commandId, AddRootFolderAction.ID),
|
"You have not yet opened a folder.\n{0}\nOpening a folder will close all currently open editors. To keep them open, {0} instead.", openFolderButton, addAFolderButton),
|
||||||
when: ContextKeyExpr.and(ContextKeyExpr.has('editorIsOpen'), ContextKeyExpr.or(ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.isEqualTo('')), ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), IsWebContext))),
|
when: ContextKeyExpr.and(ContextKeyExpr.has('editorIsOpen'), ContextKeyExpr.or(ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.isEqualTo('')), ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), IsWebContext))),
|
||||||
group: ViewContentGroups.Open,
|
group: ViewContentGroups.Open,
|
||||||
order: 1
|
order: 1
|
||||||
|
@ -308,7 +317,7 @@ viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
||||||
|
|
||||||
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
viewsRegistry.registerViewWelcomeContent(EmptyView.ID, {
|
||||||
content: localize({ key: 'noFolderHelp', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
|
content: localize({ key: 'noFolderHelp', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
|
||||||
"You have not yet opened a folder.\n[Open Folder](command:{0})", commandId),
|
"You have not yet opened a folder.\n{0}", openFolderButton),
|
||||||
when: ContextKeyExpr.and(ContextKeyExpr.has('editorIsOpen')?.negate(), ContextKeyExpr.or(ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.isEqualTo('')), ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), IsWebContext))),
|
when: ContextKeyExpr.and(ContextKeyExpr.has('editorIsOpen')?.negate(), ContextKeyExpr.or(ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.isEqualTo('')), ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), IsWebContext))),
|
||||||
group: ViewContentGroups.Open,
|
group: ViewContentGroups.Open,
|
||||||
order: 1
|
order: 1
|
||||||
|
|
|
@ -42,7 +42,7 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile
|
||||||
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
|
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
|
||||||
import { isCancellationError } from 'vs/base/common/errors';
|
import { isCancellationError } from 'vs/base/common/errors';
|
||||||
import { toAction } from 'vs/base/common/actions';
|
import { toAction } from 'vs/base/common/actions';
|
||||||
import { EditorResolution } from 'vs/platform/editor/common/editor';
|
import { EditorOpenContext, EditorResolution } from 'vs/platform/editor/common/editor';
|
||||||
import { hash } from 'vs/base/common/hash';
|
import { hash } from 'vs/base/common/hash';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
|
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
|
||||||
|
@ -365,7 +365,7 @@ CommandsRegistry.registerCommand({
|
||||||
|
|
||||||
const uri = getResourceForCommand(resource, accessor.get(IListService), accessor.get(IEditorService));
|
const uri = getResourceForCommand(resource, accessor.get(IListService), accessor.get(IEditorService));
|
||||||
if (uri) {
|
if (uri) {
|
||||||
return editorService.openEditor({ resource: uri, options: { override: EditorResolution.PICK } });
|
return editorService.openEditor({ resource: uri, options: { override: EditorResolution.PICK, context: EditorOpenContext.USER } });
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
|
@ -259,7 +259,7 @@ export class SettingsEditor2 extends EditorPane {
|
||||||
this.modelDisposables = this._register(new DisposableStore());
|
this.modelDisposables = this._register(new DisposableStore());
|
||||||
}
|
}
|
||||||
|
|
||||||
override get minimumWidth(): number { return 375; }
|
override get minimumWidth(): number { return SettingsEditor2.EDITOR_MIN_WIDTH; }
|
||||||
override get maximumWidth(): number { return Number.POSITIVE_INFINITY; }
|
override get maximumWidth(): number { return Number.POSITIVE_INFINITY; }
|
||||||
|
|
||||||
// these setters need to exist because this extends from EditorPane
|
// these setters need to exist because this extends from EditorPane
|
||||||
|
|
|
@ -34,7 +34,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability {
|
||||||
private _cwd: string | undefined;
|
private _cwd: string | undefined;
|
||||||
private _currentCommand: ICurrentPartialCommand = {};
|
private _currentCommand: ICurrentPartialCommand = {};
|
||||||
private _isWindowsPty: boolean = false;
|
private _isWindowsPty: boolean = false;
|
||||||
private _onDataListener?: IDisposable;
|
private _onCursorMoveListener?: IDisposable;
|
||||||
private _commandMarkers: IMarker[] = [];
|
private _commandMarkers: IMarker[] = [];
|
||||||
|
|
||||||
get commands(): readonly ITerminalCommand[] { return this._commands; }
|
get commands(): readonly ITerminalCommand[] { return this._commands; }
|
||||||
|
@ -72,7 +72,8 @@ export class CommandDetectionCapability implements ICommandDetectionCapability {
|
||||||
this._currentCommand.commandStartMarker = this._terminal.registerMarker(0);
|
this._currentCommand.commandStartMarker = this._terminal.registerMarker(0);
|
||||||
// On Windows track all cursor movements after the command start sequence
|
// On Windows track all cursor movements after the command start sequence
|
||||||
if (this._isWindowsPty) {
|
if (this._isWindowsPty) {
|
||||||
this._onDataListener = this._terminal.onCursorMove(() => {
|
this._commandMarkers.length = 0;
|
||||||
|
this._onCursorMoveListener = this._terminal.onCursorMove(() => {
|
||||||
if (this._commandMarkers.length === 0 || this._commandMarkers[this._commandMarkers.length - 1].line !== this._terminal.buffer.active.cursorY) {
|
if (this._commandMarkers.length === 0 || this._commandMarkers[this._commandMarkers.length - 1].line !== this._terminal.buffer.active.cursorY) {
|
||||||
const marker = this._terminal.registerMarker(0);
|
const marker = this._terminal.registerMarker(0);
|
||||||
if (marker) {
|
if (marker) {
|
||||||
|
@ -87,13 +88,9 @@ export class CommandDetectionCapability implements ICommandDetectionCapability {
|
||||||
handleCommandExecuted(): void {
|
handleCommandExecuted(): void {
|
||||||
// On Windows, use the gathered cursor move markers to correct the command start and
|
// On Windows, use the gathered cursor move markers to correct the command start and
|
||||||
// executed markers
|
// executed markers
|
||||||
if (this._isWindowsPty && this._commandMarkers.length > 0) {
|
if (this._isWindowsPty) {
|
||||||
this._commandMarkers = this._commandMarkers.sort((a, b) => a.line - b.line);
|
this._onCursorMoveListener?.dispose();
|
||||||
this._currentCommand.commandStartMarker = this._commandMarkers[0];
|
this._onCursorMoveListener = undefined;
|
||||||
this._currentCommand.commandExecutedMarker = this._commandMarkers[this._commandMarkers.length - 1];
|
|
||||||
this._onDataListener?.dispose();
|
|
||||||
this._onDataListener = undefined;
|
|
||||||
this._commandMarkers.length = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._currentCommand.commandExecutedMarker = this._terminal.registerMarker(0);
|
this._currentCommand.commandExecutedMarker = this._terminal.registerMarker(0);
|
||||||
|
@ -126,6 +123,15 @@ export class CommandDetectionCapability implements ICommandDetectionCapability {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCommandFinished(exitCode: number | undefined): void {
|
handleCommandFinished(exitCode: number | undefined): void {
|
||||||
|
// On Windows, use the gathered cursor move markers to correct the command start and
|
||||||
|
// executed markers. This is done on command finished just in case command executed never
|
||||||
|
// happens (for example PSReadLine tab completion)
|
||||||
|
if (this._isWindowsPty) {
|
||||||
|
this._commandMarkers = this._commandMarkers.sort((a, b) => a.line - b.line);
|
||||||
|
this._currentCommand.commandStartMarker = this._commandMarkers[0];
|
||||||
|
this._currentCommand.commandExecutedMarker = this._commandMarkers[this._commandMarkers.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
this._currentCommand.commandFinishedMarker = this._terminal.registerMarker(0);
|
this._currentCommand.commandFinishedMarker = this._terminal.registerMarker(0);
|
||||||
const command = this._currentCommand.command;
|
const command = this._currentCommand.command;
|
||||||
this._logService.debug('CommandDetectionCapability#handleCommandFinished', this._terminal.buffer.active.cursorX, this._currentCommand.commandFinishedMarker?.line, this._currentCommand.command, this._currentCommand);
|
this._logService.debug('CommandDetectionCapability#handleCommandFinished', this._terminal.buffer.active.cursorX, this._currentCommand.commandFinishedMarker?.line, this._currentCommand.command, this._currentCommand);
|
||||||
|
@ -145,7 +151,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability {
|
||||||
timestamp,
|
timestamp,
|
||||||
cwd: this._cwd,
|
cwd: this._cwd,
|
||||||
exitCode: this._exitCode,
|
exitCode: this._exitCode,
|
||||||
hasOutput: (this._currentCommand.commandExecutedMarker!.line < this._currentCommand.commandFinishedMarker!.line),
|
hasOutput: !!(this._currentCommand.commandExecutedMarker && this._currentCommand.commandFinishedMarker && this._currentCommand.commandExecutedMarker?.line < this._currentCommand.commandFinishedMarker!.line),
|
||||||
getOutput: () => getOutputForCommand(clonedPartialCommand, buffer)
|
getOutput: () => getOutputForCommand(clonedPartialCommand, buffer)
|
||||||
};
|
};
|
||||||
this._commands.push(newCommand);
|
this._commands.push(newCommand);
|
||||||
|
|
|
@ -15,6 +15,8 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
IN_COMMAND_EXECUTION="1"
|
IN_COMMAND_EXECUTION="1"
|
||||||
|
LAST_HISTORY_ID=$(history | tail -n1 | awk '{print $1;}')
|
||||||
|
|
||||||
prompt_start() {
|
prompt_start() {
|
||||||
printf "\033]633;A\007"
|
printf "\033]633;A\007"
|
||||||
}
|
}
|
||||||
|
@ -32,7 +34,14 @@ command_output_start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
command_complete() {
|
command_complete() {
|
||||||
printf "\033]633;D;%s\007" "$STATUS"
|
local HISTORY_ID=$(history | tail -n1 | awk '{print $1;}')
|
||||||
|
if [[ "$HISTORY_ID" == "$LAST_HISTORY_ID" ]]; then
|
||||||
|
printf "\033]633;D\007"
|
||||||
|
else
|
||||||
|
printf "\033]633;D;%s\007" "$STATUS"
|
||||||
|
LAST_HISTORY_ID=$HISTORY_ID
|
||||||
|
fi
|
||||||
|
|
||||||
update_cwd
|
update_cwd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ function Global:__VSCode-Get-LastExitCode {
|
||||||
}
|
}
|
||||||
|
|
||||||
function Global:Prompt() {
|
function Global:Prompt() {
|
||||||
|
$LastExitCode = $(__VSCode-Get-LastExitCode);
|
||||||
$LastHistoryEntry = $(Get-History -Count 1)
|
$LastHistoryEntry = $(Get-History -Count 1)
|
||||||
if ($LastHistoryEntry.Id -eq $Global:__LastHistoryId) {
|
if ($LastHistoryEntry.Id -eq $Global:__LastHistoryId) {
|
||||||
# Don't provide a command line or exit code if there was no history entry (eg. ctrl+c, enter on no command)
|
# Don't provide a command line or exit code if there was no history entry (eg. ctrl+c, enter on no command)
|
||||||
|
@ -38,7 +39,7 @@ function Global:Prompt() {
|
||||||
$Result += "`a"
|
$Result += "`a"
|
||||||
# Command finished exit code
|
# Command finished exit code
|
||||||
# OSC 633 ; D [; <ExitCode>] ST
|
# OSC 633 ; D [; <ExitCode>] ST
|
||||||
$Result += "`e]633;D;$(__VSCode-Get-LastExitCode)`a"
|
$Result += "`e]633;D;$LastExitCode`a"
|
||||||
}
|
}
|
||||||
# Prompt started
|
# Prompt started
|
||||||
# OSC 633 ; A ST
|
# OSC 633 ; A ST
|
||||||
|
|
|
@ -413,6 +413,9 @@
|
||||||
top: 50%;
|
top: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.terminal-command-decoration:hover {
|
.terminal-command-decoration:not(.skipped):hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.terminal-command-decoration.skipped {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
|
@ -1638,16 +1638,23 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||||
}
|
}
|
||||||
|
|
||||||
@debounce(2000)
|
@debounce(2000)
|
||||||
private async _updateProcessCwd(): Promise<string> {
|
private async _updateProcessCwd(): Promise<void> {
|
||||||
if (this._isDisposed) {
|
if (this._isDisposed) {
|
||||||
return this.cwd || this._initialCwd || '';
|
return;
|
||||||
}
|
}
|
||||||
// reset cwd if it has changed, so file based url paths can be resolved
|
// reset cwd if it has changed, so file based url paths can be resolved
|
||||||
const cwd = await this.refreshProperty(ProcessPropertyType.Cwd);
|
try {
|
||||||
if (typeof cwd !== 'string') {
|
const cwd = await this.refreshProperty(ProcessPropertyType.Cwd);
|
||||||
throw new Error('cwd is not a string');
|
if (typeof cwd !== 'string') {
|
||||||
|
throw new Error('cwd is not a string');
|
||||||
|
}
|
||||||
|
} catch (e: unknown) {
|
||||||
|
// Swallow this as it means the process has been killed
|
||||||
|
if (e instanceof Error && e.message === 'Cannot refresh property when process is not set') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
return cwd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateConfig(): void {
|
updateConfig(): void {
|
||||||
|
|
|
@ -597,7 +597,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
|
||||||
|
|
||||||
async refreshProperty<T extends ProcessPropertyType>(type: T): Promise<IProcessPropertyMap[T]> {
|
async refreshProperty<T extends ProcessPropertyType>(type: T): Promise<IProcessPropertyMap[T]> {
|
||||||
if (!this._process) {
|
if (!this._process) {
|
||||||
throw new Error('Cannot refresh property when process is undefined');
|
throw new Error('Cannot refresh property when process is not set');
|
||||||
}
|
}
|
||||||
return this._process.refreshProperty(type);
|
return this._process.refreshProperty(type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import * as dom from 'vs/base/browser/dom';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
|
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
|
||||||
import { IColorTheme, ICssStyleCollector, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
import { IColorTheme, ICssStyleCollector, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||||
import { TERMINAL_COMMAND_DECORATION_DEFAULT_BACKGROUND_COLOR, TERMINAL_COMMAND_DECORATION_ERROR_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
|
import { TERMINAL_COMMAND_DECORATION_DEFAULT_BACKGROUND_COLOR, TERMINAL_COMMAND_DECORATION_ERROR_BACKGROUND_COLOR, TERMINAL_COMMAND_DECORATION_SKIPPED_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
|
||||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { IHoverService } from 'vs/workbench/services/hover/browser/hover';
|
import { IHoverService } from 'vs/workbench/services/hover/browser/hover';
|
||||||
import { IAction } from 'vs/base/common/actions';
|
import { IAction } from 'vs/base/common/actions';
|
||||||
|
@ -26,12 +26,13 @@ import { TerminalSettingId } from 'vs/platform/terminal/common/terminal';
|
||||||
const enum DecorationSelector {
|
const enum DecorationSelector {
|
||||||
CommandDecoration = 'terminal-command-decoration',
|
CommandDecoration = 'terminal-command-decoration',
|
||||||
ErrorColor = 'error',
|
ErrorColor = 'error',
|
||||||
|
SkippedColor = 'skipped',
|
||||||
Codicon = 'codicon',
|
Codicon = 'codicon',
|
||||||
}
|
}
|
||||||
|
|
||||||
const enum DecorationStyles { ButtonMargin = 4 }
|
const enum DecorationStyles { ButtonMargin = 4 }
|
||||||
|
|
||||||
interface IDisposableDecoration { decoration: IDecoration; diposables: IDisposable[] }
|
interface IDisposableDecoration { decoration: IDecoration; disposables: IDisposable[] }
|
||||||
|
|
||||||
export class DecorationAddon extends Disposable implements ITerminalAddon {
|
export class DecorationAddon extends Disposable implements ITerminalAddon {
|
||||||
protected _terminal: Terminal | undefined;
|
protected _terminal: Terminal | undefined;
|
||||||
|
@ -105,7 +106,7 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
|
||||||
if (!command.marker) {
|
if (!command.marker) {
|
||||||
throw new Error(`cannot add a decoration for a command ${JSON.stringify(command)} with no marker`);
|
throw new Error(`cannot add a decoration for a command ${JSON.stringify(command)} with no marker`);
|
||||||
}
|
}
|
||||||
if (!this._terminal || command.command.trim().length === 0) {
|
if (!this._terminal) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,14 +117,19 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
|
||||||
|
|
||||||
decoration.onRender(target => {
|
decoration.onRender(target => {
|
||||||
if (decoration.element && !this._decorations.get(decoration.marker.id)) {
|
if (decoration.element && !this._decorations.get(decoration.marker.id)) {
|
||||||
this._decorations.set(decoration.marker.id, { decoration, diposables: [this._createContextMenu(decoration.element, command), ...this._createHover(decoration.element, command)] });
|
const disposables = command.exitCode === undefined ? [] : [this._createContextMenu(decoration.element, command), ...this._createHover(decoration.element, command)];
|
||||||
|
this._decorations.set(decoration.marker.id, { decoration, disposables });
|
||||||
}
|
}
|
||||||
if (decoration.element?.clientWidth! > 0) {
|
if (decoration.element?.clientWidth! > 0) {
|
||||||
const marginWidth = ((decoration.element?.parentElement?.parentElement?.previousElementSibling?.clientWidth || 0) - (decoration.element?.parentElement?.parentElement?.clientWidth || 0)) * .5;
|
const marginWidth = ((decoration.element?.parentElement?.parentElement?.previousElementSibling?.clientWidth || 0) - (decoration.element?.parentElement?.parentElement?.clientWidth || 0)) * .5;
|
||||||
target.style.marginLeft = `${((marginWidth - (decoration.element!.clientWidth + DecorationStyles.ButtonMargin)) * .5) - marginWidth}px`;
|
target.style.marginLeft = `${((marginWidth - (decoration.element!.clientWidth + DecorationStyles.ButtonMargin)) * .5) - marginWidth}px`;
|
||||||
target.classList.add(DecorationSelector.CommandDecoration);
|
target.classList.add(DecorationSelector.CommandDecoration);
|
||||||
target.classList.add(DecorationSelector.Codicon);
|
target.classList.add(DecorationSelector.Codicon);
|
||||||
if (command.exitCode) {
|
if (command.exitCode === undefined) {
|
||||||
|
target.classList.add(DecorationSelector.SkippedColor);
|
||||||
|
// TODO: Use outline icon?
|
||||||
|
target.classList.add(`codicon-${this._configurationService.getValue(TerminalSettingId.CommandIcon)}`);
|
||||||
|
} else if (command.exitCode) {
|
||||||
target.classList.add(DecorationSelector.ErrorColor);
|
target.classList.add(DecorationSelector.ErrorColor);
|
||||||
target.classList.add(`codicon-${this._configurationService.getValue(TerminalSettingId.CommandIconError)}`);
|
target.classList.add(`codicon-${this._configurationService.getValue(TerminalSettingId.CommandIconError)}`);
|
||||||
} else {
|
} else {
|
||||||
|
@ -147,18 +153,26 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
|
||||||
|
|
||||||
private _createHover(target: HTMLElement, command: ITerminalCommand): IDisposable[] {
|
private _createHover(target: HTMLElement, command: ITerminalCommand): IDisposable[] {
|
||||||
return [
|
return [
|
||||||
dom.addDisposableListener(target, dom.EventType.MOUSE_ENTER, async () => {
|
dom.addDisposableListener(target, dom.EventType.MOUSE_ENTER, () => {
|
||||||
if (this._contextMenuVisible) {
|
if (this._contextMenuVisible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let hoverContent = `${localize('terminal-prompt-context-menu', "Show Actions")}` + ` ...${fromNow(command.timestamp, true)}`;
|
this._hoverDelayer.trigger(() => {
|
||||||
if (command.exitCode) {
|
let hoverContent = `${localize('terminal-prompt-context-menu', "Show Actions")}...\n\n---\n\n- ${localize('terminal-prompt-command-executed-time', 'Executed: {0}', fromNow(command.timestamp, true))}`;
|
||||||
hoverContent += `\n\n\n\nExit Code: ${command.exitCode} `;
|
if (command.exitCode) {
|
||||||
}
|
hoverContent += `\n- ${command.exitCode === -1 ? localize('terminal-prompt-command-failed', 'Failed') : localize('terminal-prompt-command-exit-code', 'Exit code: {0}', command.exitCode)}`;
|
||||||
await this._hoverDelayer.trigger(() => { this._hoverService.showHover({ content: new MarkdownString(hoverContent), target }); });
|
}
|
||||||
|
this._hoverService.showHover({ content: new MarkdownString(hoverContent), target });
|
||||||
|
});
|
||||||
}),
|
}),
|
||||||
dom.addDisposableListener(target, dom.EventType.MOUSE_LEAVE, () => this._hoverService.hideHover()),
|
dom.addDisposableListener(target, dom.EventType.MOUSE_LEAVE, () => this._hideHover()),
|
||||||
dom.addDisposableListener(target, dom.EventType.MOUSE_OUT, () => this._hoverService.hideHover())];
|
dom.addDisposableListener(target, dom.EventType.MOUSE_OUT, () => this._hideHover())
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private _hideHover() {
|
||||||
|
this._hoverDelayer.cancel();
|
||||||
|
this._hoverService.hideHover();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _getCommandActions(command: ITerminalCommand): Promise<IAction[]> {
|
private async _getCommandActions(command: ITerminalCommand): Promise<IAction[]> {
|
||||||
|
@ -182,6 +196,8 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
||||||
collector.addRule(`.${DecorationSelector.CommandDecoration} { color: ${commandDecorationDefaultColor ? commandDecorationDefaultColor.toString() : ''}; } `);
|
collector.addRule(`.${DecorationSelector.CommandDecoration} { color: ${commandDecorationDefaultColor ? commandDecorationDefaultColor.toString() : ''}; } `);
|
||||||
const commandDecorationErrorColor = theme.getColor(TERMINAL_COMMAND_DECORATION_ERROR_BACKGROUND_COLOR);
|
const commandDecorationErrorColor = theme.getColor(TERMINAL_COMMAND_DECORATION_ERROR_BACKGROUND_COLOR);
|
||||||
collector.addRule(`.${DecorationSelector.CommandDecoration}.${DecorationSelector.ErrorColor} { color: ${commandDecorationErrorColor ? commandDecorationErrorColor.toString() : ''}; } `);
|
collector.addRule(`.${DecorationSelector.CommandDecoration}.${DecorationSelector.ErrorColor} { color: ${commandDecorationErrorColor ? commandDecorationErrorColor.toString() : ''}; } `);
|
||||||
|
const commandDecorationSkippedColor = theme.getColor(TERMINAL_COMMAND_DECORATION_SKIPPED_BACKGROUND_COLOR);
|
||||||
|
collector.addRule(`.${DecorationSelector.CommandDecoration}.${DecorationSelector.SkippedColor} { color: ${commandDecorationSkippedColor ? commandDecorationSkippedColor.toString() : ''}; } `);
|
||||||
const toolbarHoverBackgroundColor = theme.getColor(toolbarHoverBackground);
|
const toolbarHoverBackgroundColor = theme.getColor(toolbarHoverBackground);
|
||||||
collector.addRule(`.${DecorationSelector.CommandDecoration}:hover { background-color: ${toolbarHoverBackgroundColor ? toolbarHoverBackgroundColor.toString() : ''}; }`);
|
collector.addRule(`.${DecorationSelector.CommandDecoration}:not(.${DecorationSelector.SkippedColor}):hover { background-color: ${toolbarHoverBackgroundColor ? toolbarHoverBackgroundColor.toString() : ''}; }`);
|
||||||
});
|
});
|
||||||
|
|
|
@ -31,12 +31,17 @@ export const TERMINAL_COMMAND_DECORATION_DEFAULT_BACKGROUND_COLOR = registerColo
|
||||||
light: '#66afe0',
|
light: '#66afe0',
|
||||||
dark: '#399ee6',
|
dark: '#399ee6',
|
||||||
hc: '#399ee6'
|
hc: '#399ee6'
|
||||||
}, nls.localize('terminalCommandDecoration.defaultBackground', 'The default terminal command decoration background color.'));
|
}, nls.localize('terminalCommandDecoration.defaultBackground', 'The default terminal command decoration background color for successful commands (zero exit code).'));
|
||||||
export const TERMINAL_COMMAND_DECORATION_ERROR_BACKGROUND_COLOR = registerColor('terminalCommandDecoration.errorBackground', {
|
export const TERMINAL_COMMAND_DECORATION_ERROR_BACKGROUND_COLOR = registerColor('terminalCommandDecoration.errorBackground', {
|
||||||
light: '#a1260d',
|
light: '#a1260d',
|
||||||
dark: '#be1100',
|
dark: '#be1100',
|
||||||
hc: '#be1100'
|
hc: '#be1100'
|
||||||
}, nls.localize('terminalCommandDecoration.errorBackground', 'The terminal command decoration background color when there is an exit code.'));
|
}, nls.localize('terminalCommandDecoration.errorBackground', 'The terminal command decoration background color when the command fails (non-zero exit code).'));
|
||||||
|
export const TERMINAL_COMMAND_DECORATION_SKIPPED_BACKGROUND_COLOR = registerColor('terminalCommandDecoration.skippedBackground', {
|
||||||
|
light: '#00000040',
|
||||||
|
dark: '#ffffff40',
|
||||||
|
hc: '#ffffff80'
|
||||||
|
}, nls.localize('terminalCommandDecoration.skippedBackground', 'The terminal command decoration background color when the command was skipped (undefined exit code).'));
|
||||||
export const TERMINAL_BORDER_COLOR = registerColor('terminal.border', {
|
export const TERMINAL_BORDER_COLOR = registerColor('terminal.border', {
|
||||||
dark: PANEL_BORDER,
|
dark: PANEL_BORDER,
|
||||||
light: PANEL_BORDER,
|
light: PANEL_BORDER,
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { IComputedStateAccessor, refreshComputedState } from 'vs/workbench/contr
|
||||||
import { IObservableValue, MutableObservableValue, staticObservableValue } from 'vs/workbench/contrib/testing/common/observableValue';
|
import { IObservableValue, MutableObservableValue, staticObservableValue } from 'vs/workbench/contrib/testing/common/observableValue';
|
||||||
import { IRichLocation, ISerializedTestResults, ITestItem, ITestMessage, ITestOutputMessage, ITestRunTask, ITestTaskState, ResolvedTestRunRequest, TestItemExpandState, TestMessageType, TestResultItem, TestResultState } from 'vs/workbench/contrib/testing/common/testCollection';
|
import { IRichLocation, ISerializedTestResults, ITestItem, ITestMessage, ITestOutputMessage, ITestRunTask, ITestTaskState, ResolvedTestRunRequest, TestItemExpandState, TestMessageType, TestResultItem, TestResultState } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||||
import { TestCoverage } from 'vs/workbench/contrib/testing/common/testCoverage';
|
import { TestCoverage } from 'vs/workbench/contrib/testing/common/testCoverage';
|
||||||
import { maxPriority, statesInOrder } from 'vs/workbench/contrib/testing/common/testingStates';
|
import { maxPriority, statesInOrder, terminalStatePriorities } from 'vs/workbench/contrib/testing/common/testingStates';
|
||||||
|
|
||||||
export interface ITestRunTaskResults extends ITestRunTask {
|
export interface ITestRunTaskResults extends ITestRunTask {
|
||||||
/**
|
/**
|
||||||
|
@ -379,6 +379,17 @@ export class LiveTestResult implements ITestResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
const index = this.mustGetTaskIndex(taskId);
|
const index = this.mustGetTaskIndex(taskId);
|
||||||
|
|
||||||
|
const oldTerminalStatePrio = terminalStatePriorities[entry.tasks[index].state];
|
||||||
|
const newTerminalStatePrio = terminalStatePriorities[state];
|
||||||
|
|
||||||
|
// Ignore requests to set the state from one terminal state back to a
|
||||||
|
// "lower" one, e.g. from failed back to passed:
|
||||||
|
if (oldTerminalStatePrio !== undefined &&
|
||||||
|
(newTerminalStatePrio === undefined || newTerminalStatePrio < oldTerminalStatePrio)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.fireUpdateAndRefresh(entry, index, state, duration);
|
this.fireUpdateAndRefresh(entry, index, state, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,3 +59,15 @@ export const maxPriority = (...states: TestResultState[]) => {
|
||||||
export const statesInOrder = Object.keys(statePriority).map(s => Number(s) as TestResultState).sort(cmpPriority);
|
export const statesInOrder = Object.keys(statePriority).map(s => Number(s) as TestResultState).sort(cmpPriority);
|
||||||
|
|
||||||
export const isRunningState = (s: TestResultState) => s === TestResultState.Queued || s === TestResultState.Running;
|
export const isRunningState = (s: TestResultState) => s === TestResultState.Queued || s === TestResultState.Running;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some states are considered terminal; once these are set for a given test run, they
|
||||||
|
* are not reset back to a non-terminal state, or to a terminal state with lower
|
||||||
|
* priority.
|
||||||
|
*/
|
||||||
|
export const terminalStatePriorities: { [key in TestResultState]?: number } = {
|
||||||
|
[TestResultState.Passed]: 0,
|
||||||
|
[TestResultState.Skipped]: 1,
|
||||||
|
[TestResultState.Failed]: 2,
|
||||||
|
[TestResultState.Errored]: 3,
|
||||||
|
};
|
||||||
|
|
|
@ -144,14 +144,15 @@ suite('Workbench - Test Results Service', () => {
|
||||||
|
|
||||||
test('updateState', () => {
|
test('updateState', () => {
|
||||||
changed.clear();
|
changed.clear();
|
||||||
r.updateState(new TestId(['ctrlId', 'id-a', 'id-aa']).toString(), 't', TestResultState.Running);
|
const testId = new TestId(['ctrlId', 'id-a', 'id-aa']).toString();
|
||||||
|
r.updateState(testId, 't', TestResultState.Running);
|
||||||
assert.deepStrictEqual(r.counts, {
|
assert.deepStrictEqual(r.counts, {
|
||||||
...makeEmptyCounts(),
|
...makeEmptyCounts(),
|
||||||
[TestResultState.Unset]: 2,
|
[TestResultState.Unset]: 2,
|
||||||
[TestResultState.Running]: 1,
|
[TestResultState.Running]: 1,
|
||||||
[TestResultState.Queued]: 1,
|
[TestResultState.Queued]: 1,
|
||||||
});
|
});
|
||||||
assert.deepStrictEqual(r.getStateById(new TestId(['ctrlId', 'id-a', 'id-aa']).toString())?.ownComputedState, TestResultState.Running);
|
assert.deepStrictEqual(r.getStateById(testId)?.ownComputedState, TestResultState.Running);
|
||||||
// update computed state:
|
// update computed state:
|
||||||
assert.deepStrictEqual(r.getStateById(tests.root.id)?.computedState, TestResultState.Running);
|
assert.deepStrictEqual(r.getStateById(tests.root.id)?.computedState, TestResultState.Running);
|
||||||
assert.deepStrictEqual(getChangeSummary(), [
|
assert.deepStrictEqual(getChangeSummary(), [
|
||||||
|
@ -159,6 +160,15 @@ suite('Workbench - Test Results Service', () => {
|
||||||
{ label: 'aa', reason: TestResultItemChangeReason.OwnStateChange },
|
{ label: 'aa', reason: TestResultItemChangeReason.OwnStateChange },
|
||||||
{ label: 'root', reason: TestResultItemChangeReason.ComputedStateChange },
|
{ label: 'root', reason: TestResultItemChangeReason.ComputedStateChange },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
r.updateState(testId, 't', TestResultState.Passed);
|
||||||
|
assert.deepStrictEqual(r.getStateById(testId)?.ownComputedState, TestResultState.Passed);
|
||||||
|
|
||||||
|
r.updateState(testId, 't', TestResultState.Errored);
|
||||||
|
assert.deepStrictEqual(r.getStateById(testId)?.ownComputedState, TestResultState.Errored);
|
||||||
|
|
||||||
|
r.updateState(testId, 't', TestResultState.Passed);
|
||||||
|
assert.deepStrictEqual(r.getStateById(testId)?.ownComputedState, TestResultState.Errored);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('retire', () => {
|
test('retire', () => {
|
||||||
|
|
|
@ -869,7 +869,7 @@ onDomReady(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.allowScripts && isSafari) {
|
if (!options.allowScripts && isSafari) {
|
||||||
// On Safari for iframes with scripts disabled, the `DOMContentLoaded` never seems to be fired.
|
// On Safari for iframes with scripts disabled, the `DOMContentLoaded` never seems to be fired: https://bugs.webkit.org/show_bug.cgi?id=33604
|
||||||
// Use polling instead.
|
// Use polling instead.
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
// If the frame is no longer mounted, loading has stopped
|
// If the frame is no longer mounted, loading has stopped
|
||||||
|
@ -881,7 +881,8 @@ onDomReady(() => {
|
||||||
const contentDocument = assertIsDefined(newFrame.contentDocument);
|
const contentDocument = assertIsDefined(newFrame.contentDocument);
|
||||||
if (contentDocument.readyState !== 'loading') {
|
if (contentDocument.readyState !== 'loading') {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
onFrameLoaded(contentDocument);
|
// Workaround for https://bugs.webkit.org/show_bug.cgi?id=236624
|
||||||
|
setTimeout(() => onFrameLoaded(contentDocument), 50);
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -182,7 +182,7 @@ export class BrowserWorkbenchEnvironmentService implements IBrowserWorkbenchEnvi
|
||||||
|
|
||||||
const webviewExternalEndpointCommit = this.payload?.get('webviewExternalEndpointCommit');
|
const webviewExternalEndpointCommit = this.payload?.get('webviewExternalEndpointCommit');
|
||||||
return endpoint
|
return endpoint
|
||||||
.replace('{{commit}}', webviewExternalEndpointCommit ?? this.productService.commit ?? 'd372f9187401bd145a0a6e15ba369e2d82d02005')
|
.replace('{{commit}}', webviewExternalEndpointCommit ?? this.productService.commit ?? '50089c3f92c17584a4aca179f51f220b56c22020')
|
||||||
.replace('{{quality}}', (webviewExternalEndpointCommit ? 'insider' : this.productService.quality) ?? 'insider');
|
.replace('{{quality}}', (webviewExternalEndpointCommit ? 'insider' : this.productService.quality) ?? 'insider');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,11 +208,6 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||||
|
|
||||||
this._extensionHostProcess = new ExtensionHostProcess(extensionHostCreationResult.id, this._extensionHostStarter);
|
this._extensionHostProcess = new ExtensionHostProcess(extensionHostCreationResult.id, this._extensionHostStarter);
|
||||||
|
|
||||||
let lang = processEnv['LANG'];
|
|
||||||
if (platform.isMacintosh && lang === undefined) {
|
|
||||||
lang = Intl.DateTimeFormat().resolvedOptions().locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
const env = objects.mixin(processEnv, {
|
const env = objects.mixin(processEnv, {
|
||||||
VSCODE_AMD_ENTRYPOINT: 'vs/workbench/api/node/extensionHostProcess',
|
VSCODE_AMD_ENTRYPOINT: 'vs/workbench/api/node/extensionHostProcess',
|
||||||
VSCODE_PIPE_LOGGING: 'true',
|
VSCODE_PIPE_LOGGING: 'true',
|
||||||
|
@ -220,8 +215,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||||
VSCODE_LOG_NATIVE: this._isExtensionDevHost,
|
VSCODE_LOG_NATIVE: this._isExtensionDevHost,
|
||||||
VSCODE_IPC_HOOK_EXTHOST: pipeName,
|
VSCODE_IPC_HOOK_EXTHOST: pipeName,
|
||||||
VSCODE_HANDLES_UNCAUGHT_ERRORS: true,
|
VSCODE_HANDLES_UNCAUGHT_ERRORS: true,
|
||||||
VSCODE_LOG_STACK: !this._isExtensionDevTestFromCli && (this._isExtensionDevHost || !this._environmentService.isBuilt || this._productService.quality !== 'stable' || this._environmentService.verbose),
|
VSCODE_LOG_STACK: !this._isExtensionDevTestFromCli && (this._isExtensionDevHost || !this._environmentService.isBuilt || this._productService.quality !== 'stable' || this._environmentService.verbose)
|
||||||
'LANG': lang
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this._environmentService.debugExtensionHost.env) {
|
if (this._environmentService.debugExtensionHost.env) {
|
||||||
|
|
|
@ -282,7 +282,7 @@ async function launchBrowser(options: LaunchOptions, endpoint: string) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const payloadParam = `[["enableProposedApi",""],["webviewExternalEndpointCommit","d372f9187401bd145a0a6e15ba369e2d82d02005"],["skipWelcome","true"]]`;
|
const payloadParam = `[["enableProposedApi",""],["webviewExternalEndpointCommit","50089c3f92c17584a4aca179f51f220b56c22020"],["skipWelcome","true"]]`;
|
||||||
await measureAndLog(page.goto(`${endpoint}&folder=${URI.file(workspacePath!).path}&payload=${payloadParam}`), 'page.goto()', logger);
|
await measureAndLog(page.goto(`${endpoint}&folder=${URI.file(workspacePath!).path}&payload=${payloadParam}`), 'page.goto()', logger);
|
||||||
|
|
||||||
return { browser, context, page };
|
return { browser, context, page };
|
||||||
|
|
|
@ -65,7 +65,7 @@ async function runTestsInBrowser(browserType: BrowserType, endpoint: url.UrlWith
|
||||||
const testExtensionUri = url.format({ pathname: URI.file(path.resolve(optimist.argv.extensionDevelopmentPath)).path, protocol, host, slashes: true });
|
const testExtensionUri = url.format({ pathname: URI.file(path.resolve(optimist.argv.extensionDevelopmentPath)).path, protocol, host, slashes: true });
|
||||||
const testFilesUri = url.format({ pathname: URI.file(path.resolve(optimist.argv.extensionTestsPath)).path, protocol, host, slashes: true });
|
const testFilesUri = url.format({ pathname: URI.file(path.resolve(optimist.argv.extensionTestsPath)).path, protocol, host, slashes: true });
|
||||||
|
|
||||||
const payloadParam = `[["extensionDevelopmentPath","${testExtensionUri}"],["extensionTestsPath","${testFilesUri}"],["enableProposedApi",""],["webviewExternalEndpointCommit","d372f9187401bd145a0a6e15ba369e2d82d02005"],["skipWelcome","true"]]`;
|
const payloadParam = `[["extensionDevelopmentPath","${testExtensionUri}"],["extensionTestsPath","${testFilesUri}"],["enableProposedApi",""],["webviewExternalEndpointCommit","50089c3f92c17584a4aca179f51f220b56c22020"],["skipWelcome","true"]]`;
|
||||||
|
|
||||||
if (path.extname(testWorkspacePath) === '.code-workspace') {
|
if (path.extname(testWorkspacePath) === '.code-workspace') {
|
||||||
await page.goto(`${endpoint.href}&workspace=${testWorkspacePath}&payload=${payloadParam}`);
|
await page.goto(`${endpoint.href}&workspace=${testWorkspacePath}&payload=${payloadParam}`);
|
||||||
|
|
|
@ -8193,10 +8193,10 @@ native-is-elevated@0.4.3:
|
||||||
resolved "https://registry.yarnpkg.com/native-is-elevated/-/native-is-elevated-0.4.3.tgz#f1071c4a821acc71d43f36ff8051d3816d832e1c"
|
resolved "https://registry.yarnpkg.com/native-is-elevated/-/native-is-elevated-0.4.3.tgz#f1071c4a821acc71d43f36ff8051d3816d832e1c"
|
||||||
integrity sha512-bHS3sCoh+raqFGIxmL/plER3eBQ+IEBy4RH/4uahhToZneTvqNKQrL0PgOTtnpL55XjBd3dy0pNtZMkCk0J48g==
|
integrity sha512-bHS3sCoh+raqFGIxmL/plER3eBQ+IEBy4RH/4uahhToZneTvqNKQrL0PgOTtnpL55XjBd3dy0pNtZMkCk0J48g==
|
||||||
|
|
||||||
native-keymap@3.1.0:
|
native-keymap@3.2.1:
|
||||||
version "3.1.0"
|
version "3.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/native-keymap/-/native-keymap-3.1.0.tgz#4ad8350f9253d0ae13c77f37d4a34ab4773e305f"
|
resolved "https://registry.yarnpkg.com/native-keymap/-/native-keymap-3.2.1.tgz#2b34ee7e08722f107baba9beae7e61ea43eceae7"
|
||||||
integrity sha512-h67B9n/L0DRGAftZqO7ZTlgGy7UY8r7N/GOAnnDibmRqFoenjbd9IdkN9uCf1Xs+vGW4BDJn9ZtO6xwJAbDmEA==
|
integrity sha512-kR8r1Ody16qNE52fenuCMQBHtFpIV7HNVjQA7dm/pXpFcQmqCl8jWQuJYdZvNH7fQmyAv3lOgPfR3FDHPRYiiA==
|
||||||
|
|
||||||
native-watchdog@1.3.0:
|
native-watchdog@1.3.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
|
|
Loading…
Reference in a new issue