Merge from vscode 1eb87b0e9ce9886afeaecec22b31abd0d9b7939f (#7282)
* Merge from vscode 1eb87b0e9ce9886afeaecec22b31abd0d9b7939f * fix various icon issues * fix preview features
@@ -14,7 +14,7 @@ import { Action } from 'vs/base/common/actions';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
|
||||
@@ -4,19 +4,22 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { UnownedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { WebviewEditorState } from 'vs/editor/common/modes';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IEditorModel } from 'vs/platform/editor/common/editor';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IEditorInput, Verbosity } from 'vs/workbench/common/editor';
|
||||
import { ConfirmResult, IEditorInput, Verbosity } from 'vs/workbench/common/editor';
|
||||
import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput';
|
||||
import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput';
|
||||
import { IWebviewEditorService } from 'vs/workbench/contrib/webview/browser/webviewEditorService';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { WebviewEditorState } from 'vs/editor/common/modes';
|
||||
import { promptSave } from 'vs/workbench/services/textfile/browser/textFileService';
|
||||
|
||||
export class CustomFileEditorInput extends WebviewEditorInput {
|
||||
export class CustomFileEditorInput extends WebviewInput {
|
||||
|
||||
public static typeId = 'workbench.editors.webviewEditor';
|
||||
|
||||
@@ -30,12 +33,10 @@ export class CustomFileEditorInput extends WebviewEditorInput {
|
||||
viewType: string,
|
||||
id: string,
|
||||
webview: UnownedDisposable<WebviewEditorOverlay>,
|
||||
@ILabelService
|
||||
private readonly labelService: ILabelService,
|
||||
@IWebviewEditorService
|
||||
private readonly _webviewEditorService: IWebviewEditorService,
|
||||
@IExtensionService
|
||||
private readonly _extensionService: IExtensionService
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IWebviewEditorService private readonly _webviewEditorService: IWebviewEditorService,
|
||||
@IExtensionService private readonly _extensionService: IExtensionService,
|
||||
@IDialogService private readonly dialogService: IDialogService,
|
||||
) {
|
||||
super(id, viewType, '', undefined, webview);
|
||||
this._editorResource = resource;
|
||||
@@ -77,7 +78,7 @@ export class CustomFileEditorInput extends WebviewEditorInput {
|
||||
return this.labelService.getUriLabel(this.getResource());
|
||||
}
|
||||
|
||||
getTitle(verbosity?: Verbosity): string {
|
||||
public getTitle(verbosity?: Verbosity): string {
|
||||
switch (verbosity) {
|
||||
case Verbosity.SHORT:
|
||||
return this.shortTitle;
|
||||
@@ -106,4 +107,26 @@ export class CustomFileEditorInput extends WebviewEditorInput {
|
||||
public isDirty() {
|
||||
return this._state === WebviewEditorState.Dirty;
|
||||
}
|
||||
|
||||
public async confirmSave(): Promise<ConfirmResult> {
|
||||
if (!this.isDirty()) {
|
||||
return ConfirmResult.DONT_SAVE;
|
||||
}
|
||||
return promptSave(this.dialogService, [this.getResource()]);
|
||||
}
|
||||
|
||||
public async save(): Promise<boolean> {
|
||||
if (!this.isDirty) {
|
||||
return true;
|
||||
}
|
||||
const waitingOn: Promise<boolean>[] = [];
|
||||
this._onWillSave.fire({
|
||||
waitUntil: (thenable: Promise<boolean>): void => { waitingOn.push(thenable); },
|
||||
});
|
||||
const result = await Promise.all(waitingOn);
|
||||
return result.every(x => x);
|
||||
}
|
||||
|
||||
private readonly _onWillSave = this._register(new Emitter<{ waitUntil: (thenable: Thenable<boolean>) => void }>());
|
||||
public readonly onWillSave = this._onWillSave.event;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
import { coalesce, distinct } from 'vs/base/common/arrays';
|
||||
import * as glob from 'vs/base/common/glob';
|
||||
import { UnownedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { basename, DataUri } from 'vs/base/common/resources';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
@@ -16,7 +17,8 @@ import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/ed
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { EditorOptions, IEditor, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, EditorOptions, IEditor, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { webviewEditorsExtensionPoint } from 'vs/workbench/contrib/customEditor/browser/extensionPoint';
|
||||
import { CustomEditorDiscretion, CustomEditorInfo, CustomEditorSelector, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
@@ -25,10 +27,48 @@ import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsSe
|
||||
import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { CustomFileEditorInput } from './customEditorInput';
|
||||
|
||||
const defaultEditorId = 'default';
|
||||
|
||||
const defaultEditorInfo: CustomEditorInfo = {
|
||||
id: defaultEditorId,
|
||||
displayName: nls.localize('promptOpenWith.defaultEditor', "Default built-in editor"),
|
||||
selector: [
|
||||
{ filenamePattern: '*' }
|
||||
],
|
||||
discretion: CustomEditorDiscretion.default,
|
||||
};
|
||||
|
||||
export class CustomEditorStore {
|
||||
private readonly contributedEditors = new Map<string, CustomEditorInfo>();
|
||||
|
||||
public clear() {
|
||||
this.contributedEditors.clear();
|
||||
}
|
||||
|
||||
public get(viewType: string): CustomEditorInfo | undefined {
|
||||
return viewType === defaultEditorId
|
||||
? defaultEditorInfo
|
||||
: this.contributedEditors.get(viewType);
|
||||
}
|
||||
|
||||
public add(info: CustomEditorInfo): void {
|
||||
if (info.id === defaultEditorId || this.contributedEditors.has(info.id)) {
|
||||
console.log(`Custom editor with id '${info.id}' already registered`);
|
||||
return;
|
||||
}
|
||||
this.contributedEditors.set(info.id, info);
|
||||
}
|
||||
|
||||
public getContributedEditors(resource: URI): readonly CustomEditorInfo[] {
|
||||
return Array.from(this.contributedEditors.values()).filter(customEditor =>
|
||||
customEditor.selector.some(selector => matches(selector, resource)));
|
||||
}
|
||||
}
|
||||
|
||||
export class CustomEditorService implements ICustomEditorService {
|
||||
_serviceBrand: any;
|
||||
|
||||
private readonly customEditors = new Map<string, CustomEditorInfo>();
|
||||
private readonly editors = new CustomEditorStore();
|
||||
|
||||
constructor(
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@@ -38,9 +78,11 @@ export class CustomEditorService implements ICustomEditorService {
|
||||
@IWebviewService private readonly webviewService: IWebviewService,
|
||||
) {
|
||||
webviewEditorsExtensionPoint.setHandler(extensions => {
|
||||
this.editors.clear();
|
||||
|
||||
for (const extension of extensions) {
|
||||
for (const webviewEditorContribution of extension.value) {
|
||||
this.customEditors.set(webviewEditorContribution.viewType, {
|
||||
this.editors.add({
|
||||
id: webviewEditorContribution.viewType,
|
||||
displayName: webviewEditorContribution.displayName,
|
||||
selector: webviewEditorContribution.selector || [],
|
||||
@@ -52,15 +94,14 @@ export class CustomEditorService implements ICustomEditorService {
|
||||
}
|
||||
|
||||
public getContributedCustomEditors(resource: URI): readonly CustomEditorInfo[] {
|
||||
return Array.from(this.customEditors.values()).filter(customEditor =>
|
||||
customEditor.selector.some(selector => matches(selector, resource)));
|
||||
return this.editors.getContributedEditors(resource);
|
||||
}
|
||||
|
||||
public getUserConfiguredCustomEditors(resource: URI): readonly CustomEditorInfo[] {
|
||||
const rawAssociations = this.configurationService.getValue<CustomEditorsAssociations>(customEditorsAssociationsKey) || [];
|
||||
return coalesce(rawAssociations
|
||||
.filter(association => matches(association, resource))
|
||||
.map(association => this.customEditors.get(association.viewType)));
|
||||
.map(association => this.editors.get(association.viewType)));
|
||||
}
|
||||
|
||||
public async promptOpenWith(
|
||||
@@ -69,34 +110,23 @@ export class CustomEditorService implements ICustomEditorService {
|
||||
group?: IEditorGroup,
|
||||
): Promise<IEditor | undefined> {
|
||||
const customEditors = distinct([
|
||||
defaultEditorInfo,
|
||||
...this.getUserConfiguredCustomEditors(resource),
|
||||
...this.getContributedCustomEditors(resource),
|
||||
], editor => editor.id);
|
||||
|
||||
const defaultEditorId = 'default';
|
||||
const pick = await this.quickInputService.pick([
|
||||
{
|
||||
label: nls.localize('promptOpenWith.defaultEditor', "Default built-in editor"),
|
||||
id: defaultEditorId,
|
||||
},
|
||||
...customEditors.map((editorDescriptor): IQuickPickItem => ({
|
||||
const pick = await this.quickInputService.pick(
|
||||
customEditors.map((editorDescriptor): IQuickPickItem => ({
|
||||
label: editorDescriptor.displayName,
|
||||
id: editorDescriptor.id,
|
||||
}))
|
||||
], {
|
||||
})), {
|
||||
placeHolder: nls.localize('promptOpenWith.placeHolder', "Select editor to use for '{0}'...", basename(resource)),
|
||||
});
|
||||
|
||||
if (!pick) {
|
||||
if (!pick || !pick.id) {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
|
||||
if (pick.id === defaultEditorId) {
|
||||
const fileInput = this.instantiationService.createInstance(FileEditorInput, resource, undefined, undefined);
|
||||
return this.openEditorForResource(resource, fileInput, { ...options, ignoreOverrides: true }, group);
|
||||
} else {
|
||||
return this.openWith(resource, pick.id!, options, group);
|
||||
}
|
||||
return this.openWith(resource, pick.id, options, group);
|
||||
}
|
||||
|
||||
public openWith(
|
||||
@@ -105,17 +135,31 @@ export class CustomEditorService implements ICustomEditorService {
|
||||
options?: ITextEditorOptions,
|
||||
group?: IEditorGroup,
|
||||
): Promise<IEditor | undefined> {
|
||||
if (!this.customEditors.has(viewType)) {
|
||||
if (viewType === defaultEditorId) {
|
||||
const fileInput = this.instantiationService.createInstance(FileEditorInput, resource, undefined, undefined);
|
||||
return this.openEditorForResource(resource, fileInput, { ...options, ignoreOverrides: true }, group);
|
||||
}
|
||||
|
||||
if (!this.editors.get(viewType)) {
|
||||
return this.promptOpenWith(resource, options, group);
|
||||
}
|
||||
|
||||
const input = this.createInput(resource, viewType, group);
|
||||
return this.openEditorForResource(resource, input, options, group);
|
||||
}
|
||||
|
||||
public createInput(
|
||||
resource: URI,
|
||||
viewType: string,
|
||||
group: IEditorGroup | undefined
|
||||
): CustomFileEditorInput {
|
||||
const id = generateUuid();
|
||||
const webview = this.webviewService.createWebviewEditorOverlay(id, {}, {});
|
||||
const input = this.instantiationService.createInstance(CustomFileEditorInput, resource, viewType, id, new UnownedDisposable(webview));
|
||||
if (group) {
|
||||
input.updateGroup(group!.id);
|
||||
}
|
||||
return this.openEditorForResource(resource, input, options, group);
|
||||
return input;
|
||||
}
|
||||
|
||||
private async openEditorForResource(
|
||||
@@ -159,6 +203,42 @@ export class CustomEditorContribution implements IWorkbenchContribution {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
|
||||
if (editor instanceof DiffEditorInput) {
|
||||
const getCustomEditorOverrideForSubInput = (subInput: IEditorInput): EditorInput | undefined => {
|
||||
if (subInput instanceof CustomFileEditorInput) {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
const resource = subInput.getResource();
|
||||
if (!resource) {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
|
||||
const editors = distinct([
|
||||
...this.customEditorService.getUserConfiguredCustomEditors(resource),
|
||||
...this.customEditorService.getContributedCustomEditors(resource),
|
||||
], editor => editor.id);
|
||||
|
||||
// Always prefer the first editor in the diff editor case
|
||||
return editors.length
|
||||
? this.customEditorService.createInput(resource, editors[0].id, group)
|
||||
: undefined;
|
||||
};
|
||||
|
||||
const modifiedOverride = getCustomEditorOverrideForSubInput(editor.modifiedInput);
|
||||
const originalOverride = getCustomEditorOverrideForSubInput(editor.originalInput);
|
||||
|
||||
if (modifiedOverride || originalOverride) {
|
||||
return {
|
||||
override: (async () => {
|
||||
const input = new DiffEditorInput(editor.getName(), editor.getDescription(), originalOverride || editor.originalInput, modifiedOverride || editor.modifiedInput);
|
||||
return this.editorService.openEditor(input, { ...options, ignoreOverrides: true }, group);
|
||||
})(),
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const resource = editor.getResource();
|
||||
if (!resource) {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
@@ -214,6 +294,15 @@ export class CustomEditorContribution implements IWorkbenchContribution {
|
||||
}
|
||||
|
||||
function matches(selector: CustomEditorSelector, resource: URI): boolean {
|
||||
if (resource.scheme === Schemas.data) {
|
||||
const metadata = DataUri.parseMetaData(resource);
|
||||
const mime = metadata.get(DataUri.META_DATA_MIME);
|
||||
if (!selector.mime || !mime) {
|
||||
return false;
|
||||
}
|
||||
return glob.match(selector.mime, mime.toLowerCase());
|
||||
}
|
||||
|
||||
if (!selector.filenamePattern && !selector.scheme) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IEditor } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, IEditor } from 'vs/workbench/common/editor';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
|
||||
|
||||
export const ICustomEditorService = createDecorator<ICustomEditorService>('customEditorService');
|
||||
|
||||
export interface ICustomEditorService {
|
||||
@@ -18,6 +17,8 @@ export interface ICustomEditorService {
|
||||
getContributedCustomEditors(resource: URI): readonly CustomEditorInfo[];
|
||||
getUserConfiguredCustomEditors(resource: URI): readonly CustomEditorInfo[];
|
||||
|
||||
createInput(resource: URI, viewType: string, group: IEditorGroup | undefined): EditorInput;
|
||||
|
||||
openWith(resource: URI, customEditorViewType: string, options?: ITextEditorOptions, group?: IEditorGroup): Promise<IEditor | undefined>;
|
||||
promptOpenWith(resource: URI, options?: ITextEditorOptions, group?: IEditorGroup): Promise<IEditor | undefined>;
|
||||
}
|
||||
@@ -30,6 +31,7 @@ export const enum CustomEditorDiscretion {
|
||||
export interface CustomEditorSelector {
|
||||
readonly scheme?: string;
|
||||
readonly filenamePattern?: string;
|
||||
readonly mime?: string;
|
||||
}
|
||||
|
||||
export interface CustomEditorInfo {
|
||||
|
||||
@@ -0,0 +1,567 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as env from 'vs/base/common/platform';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { URI as uri } from 'vs/base/common/uri';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ICodeEditor, IEditorMouseEvent, MouseTargetType, IContentWidget, IActiveCodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
|
||||
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { IModelDecorationOptions, IModelDeltaDecoration, TrackedRangeStickiness, ITextModel } from 'vs/editor/common/model';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { RemoveBreakpointAction } from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, BreakpointWidgetContext, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
|
||||
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { BreakpointWidget } from 'vs/workbench/contrib/debug/browser/breakpointWidget';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { getBreakpointMessageAndClassName } from 'vs/workbench/contrib/debug/browser/breakpointsView';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { distinct } from 'vs/base/common/arrays';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
interface IBreakpointDecoration {
|
||||
decorationId: string;
|
||||
breakpoint: IBreakpoint;
|
||||
range: Range;
|
||||
inlineWidget?: InlineBreakpointWidget;
|
||||
}
|
||||
|
||||
const breakpointHelperDecoration: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-breakpoint-hint',
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
|
||||
};
|
||||
|
||||
function createBreakpointDecorations(model: ITextModel, breakpoints: ReadonlyArray<IBreakpoint>, debugService: IDebugService): { range: Range; options: IModelDecorationOptions; }[] {
|
||||
const result: { range: Range; options: IModelDecorationOptions; }[] = [];
|
||||
breakpoints.forEach((breakpoint) => {
|
||||
if (breakpoint.lineNumber <= model.getLineCount()) {
|
||||
const column = model.getLineFirstNonWhitespaceColumn(breakpoint.lineNumber);
|
||||
const range = model.validateRange(
|
||||
breakpoint.column ? new Range(breakpoint.lineNumber, breakpoint.column, breakpoint.lineNumber, breakpoint.column + 1)
|
||||
: new Range(breakpoint.lineNumber, column, breakpoint.lineNumber, column + 1) // Decoration has to have a width #20688
|
||||
);
|
||||
|
||||
result.push({
|
||||
options: getBreakpointDecorationOptions(model, breakpoint, debugService),
|
||||
range
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoint, debugService: IDebugService): IModelDecorationOptions {
|
||||
const { className, message } = getBreakpointMessageAndClassName(debugService, breakpoint);
|
||||
let glyphMarginHoverMessage: MarkdownString | undefined;
|
||||
|
||||
if (message) {
|
||||
if (breakpoint.condition || breakpoint.hitCondition) {
|
||||
const modeId = model.getLanguageIdentifier().language;
|
||||
glyphMarginHoverMessage = new MarkdownString().appendCodeblock(modeId, message);
|
||||
} else {
|
||||
glyphMarginHoverMessage = new MarkdownString().appendText(message);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
glyphMarginClassName: className,
|
||||
glyphMarginHoverMessage,
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
beforeContentClassName: breakpoint.column ? `debug-breakpoint-placeholder` : undefined
|
||||
};
|
||||
}
|
||||
|
||||
async function createCandidateDecorations(model: ITextModel, breakpointDecorations: IBreakpointDecoration[], debugService: IDebugService): Promise<{ range: Range; options: IModelDecorationOptions; breakpoint: IBreakpoint | undefined }[]> {
|
||||
const lineNumbers = distinct(breakpointDecorations.map(bpd => bpd.range.startLineNumber));
|
||||
const result: { range: Range; options: IModelDecorationOptions; breakpoint: IBreakpoint | undefined }[] = [];
|
||||
const session = debugService.getViewModel().focusedSession;
|
||||
if (session && session.capabilities.supportsBreakpointLocationsRequest) {
|
||||
await Promise.all(lineNumbers.map(async lineNumber => {
|
||||
const positions = await session.breakpointsLocations(model.uri, lineNumber);
|
||||
if (positions.length > 1) {
|
||||
// Do not render candidates if there is only one, since it is already covered by the line breakpoint
|
||||
positions.forEach(p => {
|
||||
const range = new Range(p.lineNumber, p.column, p.lineNumber, p.column + 1);
|
||||
const breakpointAtPosition = breakpointDecorations.filter(bpd => bpd.range.equalsRange(range)).pop();
|
||||
if (breakpointAtPosition && breakpointAtPosition.inlineWidget) {
|
||||
// Space already occupied, do not render candidate.
|
||||
return;
|
||||
}
|
||||
result.push({
|
||||
range,
|
||||
options: {
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
beforeContentClassName: `debug-breakpoint-placeholder`
|
||||
},
|
||||
breakpoint: breakpointAtPosition ? breakpointAtPosition.breakpoint : undefined
|
||||
});
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
class BreakpointEditorContribution implements IBreakpointEditorContribution {
|
||||
|
||||
private breakpointHintDecoration: string[] = [];
|
||||
private breakpointWidget: BreakpointWidget | undefined;
|
||||
private breakpointWidgetVisible: IContextKey<boolean>;
|
||||
private toDispose: IDisposable[] = [];
|
||||
private ignoreDecorationsChangedEvent = false;
|
||||
private ignoreBreakpointsChangeEvent = false;
|
||||
private breakpointDecorations: IBreakpointDecoration[] = [];
|
||||
private candidateDecorations: { decorationId: string, inlineWidget: InlineBreakpointWidget }[] = [];
|
||||
private setDecorationsScheduler: RunOnceScheduler;
|
||||
|
||||
constructor(
|
||||
private readonly editor: ICodeEditor,
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IDialogService private readonly dialogService: IDialogService,
|
||||
) {
|
||||
this.breakpointWidgetVisible = CONTEXT_BREAKPOINT_WIDGET_VISIBLE.bindTo(contextKeyService);
|
||||
this.registerListeners();
|
||||
this.setDecorationsScheduler = new RunOnceScheduler(() => this.setDecorations(), 30);
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return BREAKPOINT_EDITOR_CONTRIBUTION_ID;
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this.toDispose.push(this.editor.onMouseDown(async (e: IEditorMouseEvent) => {
|
||||
const data = e.target.detail as IMarginData;
|
||||
const model = this.editor.getModel();
|
||||
if (!e.target.position || !model || e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN || data.isAfterLines || !this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
|
||||
return;
|
||||
}
|
||||
const canSetBreakpoints = this.debugService.getConfigurationManager().canSetBreakpointsIn(model);
|
||||
const lineNumber = e.target.position.lineNumber;
|
||||
const uri = model.uri;
|
||||
|
||||
if (e.event.rightButton || (env.isMacintosh && e.event.leftButton && e.event.ctrlKey)) {
|
||||
if (!canSetBreakpoints) {
|
||||
return;
|
||||
}
|
||||
|
||||
const anchor = { x: e.event.posx, y: e.event.posy };
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints({ lineNumber, uri });
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => this.getContextMenuActions(breakpoints, uri, lineNumber),
|
||||
getActionsContext: () => breakpoints.length ? breakpoints[0] : undefined
|
||||
});
|
||||
} else {
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints({ uri, lineNumber });
|
||||
|
||||
if (breakpoints.length) {
|
||||
// Show the dialog if there is a potential condition to be accidently lost.
|
||||
// Do not show dialog on linux due to electron issue freezing the mouse #50026
|
||||
if (!env.isLinux && breakpoints.some(bp => !!bp.condition || !!bp.logMessage || !!bp.hitCondition)) {
|
||||
const logPoint = breakpoints.every(bp => !!bp.logMessage);
|
||||
const breakpointType = logPoint ? nls.localize('logPoint', "Logpoint") : nls.localize('breakpoint', "Breakpoint");
|
||||
const disable = breakpoints.some(bp => bp.enabled);
|
||||
|
||||
const enabling = nls.localize('breakpointHasConditionDisabled',
|
||||
"This {0} has a {1} that will get lost on remove. Consider enabling the {0} instead.",
|
||||
breakpointType.toLowerCase(),
|
||||
logPoint ? nls.localize('message', "message") : nls.localize('condition', "condition")
|
||||
);
|
||||
const disabling = nls.localize('breakpointHasConditionEnabled',
|
||||
"This {0} has a {1} that will get lost on remove. Consider disabling the {0} instead.",
|
||||
breakpointType.toLowerCase(),
|
||||
logPoint ? nls.localize('message', "message") : nls.localize('condition', "condition")
|
||||
);
|
||||
|
||||
const { choice } = await this.dialogService.show(severity.Info, disable ? disabling : enabling, [
|
||||
nls.localize('removeLogPoint', "Remove {0}", breakpointType),
|
||||
nls.localize('disableLogPoint', "{0} {1}", disable ? nls.localize('disable', "Disable") : nls.localize('enable', "Enable"), breakpointType),
|
||||
nls.localize('cancel', "Cancel")
|
||||
], { cancelId: 2 });
|
||||
|
||||
if (choice === 0) {
|
||||
breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()));
|
||||
}
|
||||
if (choice === 1) {
|
||||
breakpoints.forEach(bp => this.debugService.enableOrDisableBreakpoints(!disable, bp));
|
||||
}
|
||||
} else {
|
||||
breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()));
|
||||
}
|
||||
} else if (canSetBreakpoints) {
|
||||
this.debugService.addBreakpoints(uri, [{ lineNumber }], `debugEditorGutter`);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
this.toDispose.push(this.editor.onMouseMove((e: IEditorMouseEvent) => {
|
||||
let showBreakpointHintAtLineNumber = -1;
|
||||
const model = this.editor.getModel();
|
||||
if (model && e.target.position && e.target.type === MouseTargetType.GUTTER_GLYPH_MARGIN && this.debugService.getConfigurationManager().canSetBreakpointsIn(model) &&
|
||||
this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
|
||||
const data = e.target.detail as IMarginData;
|
||||
if (!data.isAfterLines) {
|
||||
showBreakpointHintAtLineNumber = e.target.position.lineNumber;
|
||||
}
|
||||
}
|
||||
this.ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber);
|
||||
}));
|
||||
this.toDispose.push(this.editor.onMouseLeave((e: IEditorMouseEvent) => {
|
||||
this.ensureBreakpointHintDecoration(-1);
|
||||
}));
|
||||
|
||||
this.toDispose.push(this.editor.onDidChangeModel(async () => {
|
||||
this.closeBreakpointWidget();
|
||||
await this.setDecorations();
|
||||
}));
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(async () => {
|
||||
if (!this.ignoreBreakpointsChangeEvent && !this.setDecorationsScheduler.isScheduled()) {
|
||||
this.setDecorationsScheduler.schedule();
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(this.editor.onDidChangeModelDecorations(() => this.onModelDecorationsChanged()));
|
||||
}
|
||||
|
||||
private getContextMenuActions(breakpoints: ReadonlyArray<IBreakpoint>, uri: uri, lineNumber: number, column?: number): Array<IAction | ContextSubMenu> {
|
||||
const actions: Array<IAction | ContextSubMenu> = [];
|
||||
if (breakpoints.length === 1) {
|
||||
const breakpointType = breakpoints[0].logMessage ? nls.localize('logPoint', "Logpoint") : nls.localize('breakpoint', "Breakpoint");
|
||||
actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService));
|
||||
actions.push(new Action(
|
||||
'workbench.debug.action.editBreakpointAction',
|
||||
nls.localize('editBreakpoint', "Edit {0}...", breakpointType),
|
||||
undefined,
|
||||
true,
|
||||
() => Promise.resolve(this.showBreakpointWidget(breakpoints[0].lineNumber, breakpoints[0].column))
|
||||
));
|
||||
|
||||
actions.push(new Action(
|
||||
`workbench.debug.viewlet.action.toggleBreakpoint`,
|
||||
breakpoints[0].enabled ? nls.localize('disableBreakpoint', "Disable {0}", breakpointType) : nls.localize('enableBreakpoint', "Enable {0}", breakpointType),
|
||||
undefined,
|
||||
true,
|
||||
() => this.debugService.enableOrDisableBreakpoints(!breakpoints[0].enabled, breakpoints[0])
|
||||
));
|
||||
} else if (breakpoints.length > 1) {
|
||||
const sorted = breakpoints.slice().sort((first, second) => (first.column && second.column) ? first.column - second.column : 1);
|
||||
actions.push(new ContextSubMenu(nls.localize('removeBreakpoints', "Remove Breakpoints"), sorted.map(bp => new Action(
|
||||
'removeInlineBreakpoint',
|
||||
bp.column ? nls.localize('removeInlineBreakpointOnColumn', "Remove Inline Breakpoint on Column {0}", bp.column) : nls.localize('removeLineBreakpoint', "Remove Line Breakpoint"),
|
||||
undefined,
|
||||
true,
|
||||
() => this.debugService.removeBreakpoints(bp.getId())
|
||||
))));
|
||||
|
||||
actions.push(new ContextSubMenu(nls.localize('editBreakpoints', "Edit Breakpoints"), sorted.map(bp =>
|
||||
new Action('editBreakpoint',
|
||||
bp.column ? nls.localize('editInlineBreakpointOnColumn', "Edit Inline Breakpoint on Column {0}", bp.column) : nls.localize('editLineBrekapoint', "Edit Line Breakpoint"),
|
||||
undefined,
|
||||
true,
|
||||
() => Promise.resolve(this.showBreakpointWidget(bp.lineNumber, bp.column))
|
||||
)
|
||||
)));
|
||||
|
||||
actions.push(new ContextSubMenu(nls.localize('enableDisableBreakpoints', "Enable/Disable Breakpoints"), sorted.map(bp => new Action(
|
||||
bp.enabled ? 'disableColumnBreakpoint' : 'enableColumnBreakpoint',
|
||||
bp.enabled ? (bp.column ? nls.localize('disableInlineColumnBreakpoint', "Disable Inline Breakpoint on Column {0}", bp.column) : nls.localize('disableBreakpointOnLine', "Disable Line Breakpoint"))
|
||||
: (bp.column ? nls.localize('enableBreakpoints', "Enable Inline Breakpoint on Column {0}", bp.column) : nls.localize('enableBreakpointOnLine', "Enable Line Breakpoint")),
|
||||
undefined,
|
||||
true,
|
||||
() => this.debugService.enableOrDisableBreakpoints(!bp.enabled, bp)
|
||||
))));
|
||||
} else {
|
||||
actions.push(new Action(
|
||||
'addBreakpoint',
|
||||
nls.localize('addBreakpoint', "Add Breakpoint"),
|
||||
undefined,
|
||||
true,
|
||||
() => this.debugService.addBreakpoints(uri, [{ lineNumber, column }], `debugEditorContextMenu`)
|
||||
));
|
||||
actions.push(new Action(
|
||||
'addConditionalBreakpoint',
|
||||
nls.localize('addConditionalBreakpoint', "Add Conditional Breakpoint..."),
|
||||
undefined,
|
||||
true,
|
||||
() => Promise.resolve(this.showBreakpointWidget(lineNumber, column))
|
||||
));
|
||||
actions.push(new Action(
|
||||
'addLogPoint',
|
||||
nls.localize('addLogPoint', "Add Logpoint..."),
|
||||
undefined,
|
||||
true,
|
||||
() => Promise.resolve(this.showBreakpointWidget(lineNumber, column, BreakpointWidgetContext.LOG_MESSAGE))
|
||||
));
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
private marginFreeFromNonDebugDecorations(line: number): boolean {
|
||||
const decorations = this.editor.getLineDecorations(line);
|
||||
if (decorations) {
|
||||
for (const { options } of decorations) {
|
||||
if (options.glyphMarginClassName && options.glyphMarginClassName.indexOf('debug') === -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber: number): void {
|
||||
const newDecoration: IModelDeltaDecoration[] = [];
|
||||
if (showBreakpointHintAtLineNumber !== -1) {
|
||||
newDecoration.push({
|
||||
options: breakpointHelperDecoration,
|
||||
range: {
|
||||
startLineNumber: showBreakpointHintAtLineNumber,
|
||||
startColumn: 1,
|
||||
endLineNumber: showBreakpointHintAtLineNumber,
|
||||
endColumn: 1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.breakpointHintDecoration = this.editor.deltaDecorations(this.breakpointHintDecoration, newDecoration);
|
||||
}
|
||||
|
||||
private async setDecorations(): Promise<void> {
|
||||
if (!this.editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const activeCodeEditor = this.editor;
|
||||
const model = activeCodeEditor.getModel();
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints({ uri: model.uri });
|
||||
const desiredBreakpointDecorations = createBreakpointDecorations(model, breakpoints, this.debugService);
|
||||
|
||||
try {
|
||||
this.ignoreDecorationsChangedEvent = true;
|
||||
|
||||
// Set breakpoint decorations
|
||||
const decorationIds = activeCodeEditor.deltaDecorations(this.breakpointDecorations.map(bpd => bpd.decorationId), desiredBreakpointDecorations);
|
||||
this.breakpointDecorations.forEach(bpd => {
|
||||
if (bpd.inlineWidget) {
|
||||
bpd.inlineWidget.dispose();
|
||||
}
|
||||
});
|
||||
this.breakpointDecorations = decorationIds.map((decorationId, index) => {
|
||||
let inlineWidget: InlineBreakpointWidget | undefined = undefined;
|
||||
const breakpoint = breakpoints[index];
|
||||
if (breakpoint.column) {
|
||||
inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, desiredBreakpointDecorations[index].options.glyphMarginClassName, breakpoint, this.debugService, this.contextMenuService, () => this.getContextMenuActions([breakpoint], activeCodeEditor.getModel().uri, breakpoint.lineNumber, breakpoint.column));
|
||||
}
|
||||
|
||||
return {
|
||||
decorationId,
|
||||
breakpoint,
|
||||
range: desiredBreakpointDecorations[index].range,
|
||||
inlineWidget
|
||||
};
|
||||
});
|
||||
|
||||
} finally {
|
||||
this.ignoreDecorationsChangedEvent = false;
|
||||
}
|
||||
|
||||
// Set breakpoint candidate decorations
|
||||
const desiredCandidateDecorations = await createCandidateDecorations(this.editor.getModel(), this.breakpointDecorations, this.debugService);
|
||||
const candidateDecorationIds = this.editor.deltaDecorations(this.candidateDecorations.map(c => c.decorationId), desiredCandidateDecorations);
|
||||
this.candidateDecorations.forEach(candidate => {
|
||||
candidate.inlineWidget.dispose();
|
||||
});
|
||||
this.candidateDecorations = candidateDecorationIds.map((decorationId, index) => {
|
||||
const candidate = desiredCandidateDecorations[index];
|
||||
const cssClass = candidate.breakpoint ? undefined : 'debug-breakpoint-disabled';
|
||||
const inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, cssClass, candidate.breakpoint, this.debugService, this.contextMenuService, () => this.getContextMenuActions([], activeCodeEditor.getModel().uri, candidate.range.startLineNumber, candidate.range.startColumn));
|
||||
|
||||
return {
|
||||
decorationId,
|
||||
inlineWidget
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private async onModelDecorationsChanged(): Promise<void> {
|
||||
if (this.breakpointDecorations.length === 0 || this.ignoreDecorationsChangedEvent || !this.editor.hasModel()) {
|
||||
// I have no decorations
|
||||
return;
|
||||
}
|
||||
let somethingChanged = false;
|
||||
const model = this.editor.getModel();
|
||||
this.breakpointDecorations.forEach(breakpointDecoration => {
|
||||
if (somethingChanged) {
|
||||
return;
|
||||
}
|
||||
const newBreakpointRange = model.getDecorationRange(breakpointDecoration.decorationId);
|
||||
if (newBreakpointRange && (!breakpointDecoration.range.equalsRange(newBreakpointRange))) {
|
||||
somethingChanged = true;
|
||||
}
|
||||
});
|
||||
if (!somethingChanged) {
|
||||
// nothing to do, my decorations did not change.
|
||||
return;
|
||||
}
|
||||
|
||||
const data = new Map<string, IBreakpointUpdateData>();
|
||||
for (let i = 0, len = this.breakpointDecorations.length; i < len; i++) {
|
||||
const breakpointDecoration = this.breakpointDecorations[i];
|
||||
const decorationRange = model.getDecorationRange(breakpointDecoration.decorationId);
|
||||
// check if the line got deleted.
|
||||
if (decorationRange) {
|
||||
// since we know it is collapsed, it cannot grow to multiple lines
|
||||
if (breakpointDecoration.breakpoint) {
|
||||
data.set(breakpointDecoration.breakpoint.getId(), {
|
||||
lineNumber: decorationRange.startLineNumber,
|
||||
column: breakpointDecoration.breakpoint.column ? decorationRange.startColumn : undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
this.ignoreBreakpointsChangeEvent = true;
|
||||
await this.debugService.updateBreakpoints(model.uri, data, true);
|
||||
} finally {
|
||||
this.ignoreBreakpointsChangeEvent = false;
|
||||
}
|
||||
}
|
||||
|
||||
// breakpoint widget
|
||||
showBreakpointWidget(lineNumber: number, column: number | undefined, context?: BreakpointWidgetContext): void {
|
||||
if (this.breakpointWidget) {
|
||||
this.breakpointWidget.dispose();
|
||||
}
|
||||
|
||||
this.breakpointWidget = this.instantiationService.createInstance(BreakpointWidget, this.editor, lineNumber, column, context);
|
||||
this.breakpointWidget.show({ lineNumber, column: 1 });
|
||||
this.breakpointWidgetVisible.set(true);
|
||||
}
|
||||
|
||||
closeBreakpointWidget(): void {
|
||||
if (this.breakpointWidget) {
|
||||
this.breakpointWidget.dispose();
|
||||
this.breakpointWidget = undefined;
|
||||
this.breakpointWidgetVisible.reset();
|
||||
this.editor.focus();
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
if (this.breakpointWidget) {
|
||||
this.breakpointWidget.dispose();
|
||||
}
|
||||
this.editor.deltaDecorations(this.breakpointDecorations.map(bpd => bpd.decorationId), []);
|
||||
dispose(this.toDispose);
|
||||
}
|
||||
}
|
||||
|
||||
class InlineBreakpointWidget implements IContentWidget, IDisposable {
|
||||
|
||||
// editor.IContentWidget.allowEditorOverflow
|
||||
allowEditorOverflow = false;
|
||||
suppressMouseDown = true;
|
||||
|
||||
private domNode!: HTMLElement;
|
||||
private range: Range | null;
|
||||
private toDispose: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly editor: IActiveCodeEditor,
|
||||
private readonly decorationId: string,
|
||||
cssClass: string | null | undefined,
|
||||
private readonly breakpoint: IBreakpoint | undefined,
|
||||
private readonly debugService: IDebugService,
|
||||
private readonly contextMenuService: IContextMenuService,
|
||||
private readonly getContextMenuActions: () => ReadonlyArray<IAction | ContextSubMenu>
|
||||
) {
|
||||
this.range = this.editor.getModel().getDecorationRange(decorationId);
|
||||
this.toDispose.push(this.editor.onDidChangeModelDecorations(() => {
|
||||
const model = this.editor.getModel();
|
||||
const range = model.getDecorationRange(this.decorationId);
|
||||
if (this.range && !this.range.equalsRange(range)) {
|
||||
this.range = range;
|
||||
this.editor.layoutContentWidget(this);
|
||||
}
|
||||
}));
|
||||
this.create(cssClass);
|
||||
|
||||
this.editor.addContentWidget(this);
|
||||
this.editor.layoutContentWidget(this);
|
||||
}
|
||||
|
||||
private create(cssClass: string | null | undefined): void {
|
||||
this.domNode = $('.inline-breakpoint-widget');
|
||||
if (cssClass) {
|
||||
this.domNode.classList.add(cssClass);
|
||||
}
|
||||
this.toDispose.push(dom.addDisposableListener(this.domNode, dom.EventType.CLICK, async e => {
|
||||
if (this.breakpoint) {
|
||||
await this.debugService.removeBreakpoints(this.breakpoint.getId());
|
||||
} else {
|
||||
await this.debugService.addBreakpoints(this.editor.getModel().uri, [{ lineNumber: this.range!.startLineNumber, column: this.range!.startColumn }], 'debugEditorInlineWidget');
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(dom.addDisposableListener(this.domNode, dom.EventType.CONTEXT_MENU, async e => {
|
||||
const event = new StandardMouseEvent(e);
|
||||
const anchor = { x: event.posx, y: event.posy };
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => this.getContextMenuActions(),
|
||||
getActionsContext: () => this.breakpoint
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
@memoize
|
||||
getId(): string {
|
||||
return generateUuid();
|
||||
}
|
||||
|
||||
getDomNode(): HTMLElement {
|
||||
return this.domNode;
|
||||
}
|
||||
|
||||
getPosition(): IContentWidgetPosition | null {
|
||||
if (!this.range) {
|
||||
return null;
|
||||
}
|
||||
// Workaround: since the content widget can not be placed before the first column we need to force the left position
|
||||
dom.toggleClass(this.domNode, 'line-start', this.range.startColumn === 1);
|
||||
|
||||
return {
|
||||
position: { lineNumber: this.range.startLineNumber, column: this.range.startColumn - 1 },
|
||||
preference: [ContentWidgetPositionPreference.EXACT]
|
||||
};
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.editor.removeContentWidget(this);
|
||||
dispose(this.toDispose);
|
||||
}
|
||||
}
|
||||
|
||||
registerEditorContribution(BreakpointEditorContribution);
|
||||
@@ -13,7 +13,7 @@ import { Position, IPosition } from 'vs/editor/common/core/position';
|
||||
import { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IDebugService, IBreakpoint, BreakpointWidgetContext as Context, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, DEBUG_SCHEME, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, CONTEXT_IN_BREAKPOINT_WIDGET, IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebugService, IBreakpoint, BreakpointWidgetContext as Context, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, DEBUG_SCHEME, CONTEXT_IN_BREAKPOINT_WIDGET, IBreakpointUpdateData, IBreakpointEditorContribution, BREAKPOINT_EDITOR_CONTRIBUTION_ID } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -37,7 +37,7 @@ import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
|
||||
const $ = dom.$;
|
||||
const IPrivateBreakpointWidgetService = createDecorator<IPrivateBreakpointWidgetService>('privateBreakopintWidgetService');
|
||||
const IPrivateBreakpointWidgetService = createDecorator<IPrivateBreakpointWidgetService>('privateBreakpointWidgetService');
|
||||
export interface IPrivateBreakpointWidgetService {
|
||||
_serviceBrand: undefined;
|
||||
close(success: boolean): void;
|
||||
@@ -55,7 +55,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
|
||||
private logMessageInput = '';
|
||||
private breakpoint: IBreakpoint | undefined;
|
||||
|
||||
constructor(editor: ICodeEditor, private lineNumber: number, private context: Context,
|
||||
constructor(editor: ICodeEditor, private lineNumber: number, private column: number | undefined, private context: Context,
|
||||
@IContextViewService private readonly contextViewService: IContextViewService,
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@@ -70,7 +70,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
|
||||
const model = this.editor.getModel();
|
||||
if (model) {
|
||||
const uri = model.uri;
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints({ lineNumber: this.lineNumber, uri });
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints({ lineNumber: this.lineNumber, column: this.column, uri });
|
||||
this.breakpoint = breakpoints.length ? breakpoints[0] : undefined;
|
||||
}
|
||||
|
||||
@@ -130,12 +130,12 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
|
||||
}
|
||||
}
|
||||
|
||||
show(rangeOrPos: IRange | IPosition, heightInLines: number) {
|
||||
show(rangeOrPos: IRange | IPosition): void {
|
||||
const lineNum = this.input.getModel().getLineCount();
|
||||
super.show(rangeOrPos, lineNum + 1);
|
||||
}
|
||||
|
||||
fitHeightToContent() {
|
||||
fitHeightToContent(): void {
|
||||
const lineNum = this.input.getModel().getLineCount();
|
||||
this._relayout(lineNum + 1);
|
||||
}
|
||||
@@ -293,6 +293,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
|
||||
if (model) {
|
||||
this.debugService.addBreakpoints(model.uri, [{
|
||||
lineNumber: this.lineNumber,
|
||||
column: this.column,
|
||||
enabled: true,
|
||||
condition,
|
||||
hitCondition,
|
||||
@@ -348,7 +349,7 @@ class CloseBreakpointWidgetCommand extends EditorCommand {
|
||||
}
|
||||
|
||||
runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
|
||||
const debugContribution = editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID);
|
||||
const debugContribution = editor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID);
|
||||
if (debugContribution) {
|
||||
// if focus is in outer editor we need to use the debug contribution to close
|
||||
return debugContribution.closeBreakpointWidget();
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINTS_FOCUSED, EDITOR_CONTRIBUTION_ID, State, DEBUG_SCHEME, IFunctionBreakpoint, IExceptionBreakpoint, IEnablement, IDebugEditorContribution } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINTS_FOCUSED, State, DEBUG_SCHEME, IFunctionBreakpoint, IExceptionBreakpoint, IEnablement, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { ExceptionBreakpoint, FunctionBreakpoint, Breakpoint, DataBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { AddFunctionBreakpointAction, ToggleBreakpointsActivatedAction, RemoveAllBreakpointsAction, RemoveBreakpointAction, EnableAllBreakpointsAction, DisableAllBreakpointsAction, ReapplyBreakpointsAction } from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
@@ -167,7 +167,7 @@ export class BreakpointsView extends ViewletPanel {
|
||||
if (editor) {
|
||||
const codeEditor = editor.getControl();
|
||||
if (isCodeEditor(codeEditor)) {
|
||||
codeEditor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(element.lineNumber, element.column);
|
||||
codeEditor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(element.lineNumber, element.column);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -180,7 +180,7 @@ export class BreakpointsView extends ViewletPanel {
|
||||
actions.push(new Separator());
|
||||
}
|
||||
|
||||
actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService, this.keybindingService));
|
||||
actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService));
|
||||
|
||||
if (this.debugService.getModel().getBreakpoints().length + this.debugService.getModel().getFunctionBreakpoints().length > 1) {
|
||||
actions.push(new RemoveAllBreakpointsAction(RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL, this.debugService, this.keybindingService));
|
||||
|
||||
@@ -24,7 +24,6 @@ import {
|
||||
} from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { DebugEditorModelManager } from 'vs/workbench/contrib/debug/browser/debugEditorModelManager';
|
||||
import { StartAction, AddFunctionBreakpointAction, ConfigureAction, DisableAllBreakpointsAction, EnableAllBreakpointsAction, RemoveAllBreakpointsAction, RunAction, ReapplyBreakpointsAction, SelectAndStartAction } from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar';
|
||||
import * as service from 'vs/workbench/contrib/debug/browser/debugService';
|
||||
@@ -49,6 +48,7 @@ import { VariablesView } from 'vs/workbench/contrib/debug/browser/variablesView'
|
||||
import { ClearReplAction, Repl } from 'vs/workbench/contrib/debug/browser/repl';
|
||||
import { DebugContentProvider } from 'vs/workbench/contrib/debug/common/debugContentProvider';
|
||||
import { registerAndGetAmdImageURL } from 'vs/base/common/amd';
|
||||
import { DebugCallStackContribution } from 'vs/workbench/contrib/debug/browser/debugCallStackContribution';
|
||||
|
||||
class OpenDebugViewletAction extends ShowViewletAction {
|
||||
public static readonly ID = VIEWLET_ID;
|
||||
@@ -121,7 +121,7 @@ const registry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionRegistryEx
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDebugPanelAction, OpenDebugPanelAction.ID, OpenDebugPanelAction.LABEL, openPanelKb), 'View: Debug Console', nls.localize('view', "View"));
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDebugViewletAction, OpenDebugViewletAction.ID, OpenDebugViewletAction.LABEL, openViewletKb), 'View: Show Debug', nls.localize('view', "View"));
|
||||
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugEditorModelManager, LifecyclePhase.Restored);
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugCallStackContribution, LifecyclePhase.Restored);
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugToolBar, LifecyclePhase.Restored);
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugContentProvider, LifecyclePhase.Eventually);
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(StatusBarColorProvider, LifecyclePhase.Eventually);
|
||||
|
||||
@@ -181,12 +181,12 @@ export class SelectAndStartAction extends AbstractDebugAction {
|
||||
}
|
||||
}
|
||||
|
||||
export class RemoveBreakpointAction extends AbstractDebugAction {
|
||||
export class RemoveBreakpointAction extends Action {
|
||||
static readonly ID = 'workbench.debug.viewlet.action.removeBreakpoint';
|
||||
static LABEL = nls.localize('removeBreakpoint', "Remove Breakpoint");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action remove', debugService, keybindingService);
|
||||
constructor(id: string, label: string, @IDebugService private readonly debugService: IDebugService) {
|
||||
super(id, label, 'debug-action remove');
|
||||
}
|
||||
|
||||
public run(breakpoint: IBreakpoint): Promise<any> {
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Constants } from 'vs/editor/common/core/uint';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ITextModel, TrackedRangeStickiness, IModelDeltaDecoration, IModelDecorationOptions } from 'vs/editor/common/model';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IDebugService, State } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
interface IDebugEditorModelData {
|
||||
model: ITextModel;
|
||||
currentStackDecorations: string[];
|
||||
topStackFrameRange: Range | undefined;
|
||||
}
|
||||
|
||||
const stickiness = TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges;
|
||||
|
||||
export class DebugCallStackContribution implements IWorkbenchContribution {
|
||||
private modelDataMap = new Map<string, IDebugEditorModelData>();
|
||||
private toDispose: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
@IModelService private readonly modelService: IModelService,
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
) {
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this.toDispose.push(this.modelService.onModelAdded(this.onModelAdded, this));
|
||||
this.modelService.getModels().forEach(model => this.onModelAdded(model));
|
||||
this.toDispose.push(this.modelService.onModelRemoved(this.onModelRemoved, this));
|
||||
|
||||
this.toDispose.push(this.debugService.getViewModel().onDidFocusStackFrame(() => this.onFocusStackFrame()));
|
||||
this.toDispose.push(this.debugService.onDidChangeState(state => {
|
||||
if (state === State.Inactive) {
|
||||
this.modelDataMap.forEach(modelData => {
|
||||
modelData.topStackFrameRange = undefined;
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private onModelAdded(model: ITextModel): void {
|
||||
const modelUriStr = model.uri.toString();
|
||||
const currentStackDecorations = model.deltaDecorations([], this.createCallStackDecorations(modelUriStr));
|
||||
|
||||
this.modelDataMap.set(modelUriStr, {
|
||||
model: model,
|
||||
currentStackDecorations: currentStackDecorations,
|
||||
topStackFrameRange: undefined
|
||||
});
|
||||
}
|
||||
|
||||
private onModelRemoved(model: ITextModel): void {
|
||||
const modelUriStr = model.uri.toString();
|
||||
const data = this.modelDataMap.get(modelUriStr);
|
||||
if (data) {
|
||||
this.modelDataMap.delete(modelUriStr);
|
||||
}
|
||||
}
|
||||
|
||||
private onFocusStackFrame(): void {
|
||||
this.modelDataMap.forEach((modelData, uri) => {
|
||||
modelData.currentStackDecorations = modelData.model.deltaDecorations(modelData.currentStackDecorations, this.createCallStackDecorations(uri));
|
||||
});
|
||||
}
|
||||
|
||||
private createCallStackDecorations(modelUriStr: string): IModelDeltaDecoration[] {
|
||||
const result: IModelDeltaDecoration[] = [];
|
||||
const stackFrame = this.debugService.getViewModel().focusedStackFrame;
|
||||
if (!stackFrame || stackFrame.source.uri.toString() !== modelUriStr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// only show decorations for the currently focused thread.
|
||||
const columnUntilEOLRange = new Range(stackFrame.range.startLineNumber, stackFrame.range.startColumn, stackFrame.range.startLineNumber, Constants.MAX_SAFE_SMALL_INTEGER);
|
||||
const range = new Range(stackFrame.range.startLineNumber, stackFrame.range.startColumn, stackFrame.range.startLineNumber, stackFrame.range.startColumn + 1);
|
||||
|
||||
// compute how to decorate the editor. Different decorations are used if this is a top stack frame, focused stack frame,
|
||||
// an exception or a stack frame that did not change the line number (we only decorate the columns, not the whole line).
|
||||
const callStack = stackFrame.thread.getCallStack();
|
||||
if (callStack && callStack.length && stackFrame === callStack[0]) {
|
||||
result.push({
|
||||
options: DebugCallStackContribution.TOP_STACK_FRAME_MARGIN,
|
||||
range
|
||||
});
|
||||
|
||||
result.push({
|
||||
options: DebugCallStackContribution.TOP_STACK_FRAME_DECORATION,
|
||||
range: columnUntilEOLRange
|
||||
});
|
||||
|
||||
const modelData = this.modelDataMap.get(modelUriStr);
|
||||
if (modelData) {
|
||||
if (modelData.topStackFrameRange && modelData.topStackFrameRange.startLineNumber === stackFrame.range.startLineNumber && modelData.topStackFrameRange.startColumn !== stackFrame.range.startColumn) {
|
||||
result.push({
|
||||
options: DebugCallStackContribution.TOP_STACK_FRAME_INLINE_DECORATION,
|
||||
range: columnUntilEOLRange
|
||||
});
|
||||
}
|
||||
modelData.topStackFrameRange = columnUntilEOLRange;
|
||||
}
|
||||
} else {
|
||||
result.push({
|
||||
options: DebugCallStackContribution.FOCUSED_STACK_FRAME_MARGIN,
|
||||
range
|
||||
});
|
||||
|
||||
result.push({
|
||||
options: DebugCallStackContribution.FOCUSED_STACK_FRAME_DECORATION,
|
||||
range: columnUntilEOLRange
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// editor decorations
|
||||
|
||||
static readonly STICKINESS = TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges;
|
||||
// we need a separate decoration for glyph margin, since we do not want it on each line of a multi line statement.
|
||||
private static TOP_STACK_FRAME_MARGIN: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-top-stack-frame',
|
||||
stickiness
|
||||
};
|
||||
|
||||
private static FOCUSED_STACK_FRAME_MARGIN: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-focused-stack-frame',
|
||||
stickiness
|
||||
};
|
||||
|
||||
private static TOP_STACK_FRAME_DECORATION: IModelDecorationOptions = {
|
||||
isWholeLine: true,
|
||||
inlineClassName: 'debug-remove-token-colors',
|
||||
className: 'debug-top-stack-frame-line',
|
||||
stickiness
|
||||
};
|
||||
|
||||
private static TOP_STACK_FRAME_INLINE_DECORATION: IModelDecorationOptions = {
|
||||
beforeContentClassName: 'debug-top-stack-frame-column'
|
||||
};
|
||||
|
||||
private static FOCUSED_STACK_FRAME_DECORATION: IModelDecorationOptions = {
|
||||
isWholeLine: true,
|
||||
inlineClassName: 'debug-remove-token-colors',
|
||||
className: 'debug-focused-stack-frame-line',
|
||||
stickiness
|
||||
};
|
||||
|
||||
dispose(): void {
|
||||
this.modelDataMap.forEach(modelData => {
|
||||
modelData.model.deltaDecorations(modelData.currentStackDecorations, []);
|
||||
});
|
||||
this.toDispose = dispose(this.toDispose);
|
||||
|
||||
this.modelDataMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const topStackFrame = theme.getColor(topStackFrameColor);
|
||||
if (topStackFrame) {
|
||||
collector.addRule(`.monaco-editor .view-overlays .debug-top-stack-frame-line { background: ${topStackFrame}; }`);
|
||||
collector.addRule(`.monaco-editor .view-overlays .debug-top-stack-frame-line { background: ${topStackFrame}; }`);
|
||||
}
|
||||
|
||||
const focusedStackFrame = theme.getColor(focusedStackFrameColor);
|
||||
if (focusedStackFrame) {
|
||||
collector.addRule(`.monaco-editor .view-overlays .debug-focused-stack-frame-line { background: ${focusedStackFrame}; }`);
|
||||
}
|
||||
});
|
||||
|
||||
const topStackFrameColor = registerColor('editor.stackFrameHighlightBackground', { dark: '#ffff0033', light: '#ffff6673', hc: '#fff600' }, localize('topStackFrameLineHighlight', 'Background color for the highlight of line at the top stack frame position.'));
|
||||
const focusedStackFrameColor = registerColor('editor.focusedStackFrameHighlightBackground', { dark: '#7abd7a4d', light: '#cee7ce73', hc: '#cee7ce' }, localize('focusedStackFrameLineHighlight', 'Background color for the highlight of line at focused stack frame position.'));
|
||||
@@ -9,7 +9,7 @@ import { Range } from 'vs/editor/common/core/range';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { ServicesAccessor, registerEditorAction, EditorAction, IActionOptions } from 'vs/editor/browser/editorExtensions';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IDebugService, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE, State, REPL_ID, VIEWLET_ID, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, BreakpointWidgetContext, IBreakpoint } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebugService, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE, State, REPL_ID, VIEWLET_ID, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, BreakpointWidgetContext, IBreakpoint, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
@@ -75,7 +75,7 @@ class ConditionalBreakpointAction extends EditorAction {
|
||||
|
||||
const position = editor.getPosition();
|
||||
if (position && editor.hasModel() && debugService.getConfigurationManager().canSetBreakpointsIn(editor.getModel())) {
|
||||
editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber, position.column);
|
||||
editor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber, undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,7 @@ class LogPointAction extends EditorAction {
|
||||
|
||||
const position = editor.getPosition();
|
||||
if (position && editor.hasModel() && debugService.getConfigurationManager().canSetBreakpointsIn(editor.getModel())) {
|
||||
editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber, position.column, BreakpointWidgetContext.LOG_MESSAGE);
|
||||
editor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID).showBreakpointWidget(position.lineNumber, BreakpointWidgetContext.LOG_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,9 @@
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import * as env from 'vs/base/common/platform';
|
||||
import { URI as uri } from 'vs/base/common/uri';
|
||||
import { visit } from 'vs/base/common/json';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { Constants } from 'vs/editor/common/core/uint';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { StandardTokenType } from 'vs/editor/common/modes';
|
||||
@@ -19,32 +15,25 @@ import { DEFAULT_WORD_REGEXP } from 'vs/editor/common/model/wordHelper';
|
||||
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { IDecorationOptions } from 'vs/editor/common/editorCommon';
|
||||
import { IModelDecorationOptions, IModelDeltaDecoration, TrackedRangeStickiness, ITextModel } from 'vs/editor/common/model';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { RemoveBreakpointAction } from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
import { IDebugEditorContribution, IDebugService, State, IBreakpoint, EDITOR_CONTRIBUTION_ID, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, IStackFrame, IDebugConfiguration, IExpression, IExceptionInfo, BreakpointWidgetContext } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebugEditorContribution, IDebugService, State, EDITOR_CONTRIBUTION_ID, IStackFrame, IDebugConfiguration, IExpression, IExceptionInfo } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { ExceptionWidget } from 'vs/workbench/contrib/debug/browser/exceptionWidget';
|
||||
import { FloatingClickWidget } from 'vs/workbench/browser/parts/editor/editorWidgets';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { CoreEditingCommands } from 'vs/editor/browser/controller/coreCommands';
|
||||
import { first } from 'vs/base/common/arrays';
|
||||
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { getHover } from 'vs/editor/contrib/hover/getHover';
|
||||
import { IEditorHoverOptions, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { BreakpointWidget } from 'vs/workbench/contrib/debug/browser/breakpointWidget';
|
||||
import { DebugHoverWidget } from 'vs/workbench/contrib/debug/browser/debugHover';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { getHover } from 'vs/editor/contrib/hover/getHover';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
const HOVER_DELAY = 300;
|
||||
const LAUNCH_JSON_REGEX = /launch\.json$/;
|
||||
@@ -53,17 +42,14 @@ const MAX_NUM_INLINE_VALUES = 100; // JS Global scope can have 700+ entries. We
|
||||
const MAX_INLINE_DECORATOR_LENGTH = 150; // Max string length of each inline decorator when debugging. If exceeded ... is added
|
||||
const MAX_TOKENIZATION_LINE_LEN = 500; // If line is too long, then inline values for the line are skipped
|
||||
|
||||
export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
class DebugEditorContribution implements IDebugEditorContribution {
|
||||
|
||||
private toDispose: lifecycle.IDisposable[];
|
||||
private toDispose: IDisposable[];
|
||||
private hoverWidget: DebugHoverWidget;
|
||||
private nonDebugHoverPosition: Position | undefined;
|
||||
private hoverRange: Range | null = null;
|
||||
private mouseDown = false;
|
||||
|
||||
private breakpointHintDecoration: string[];
|
||||
private breakpointWidget: BreakpointWidget | undefined;
|
||||
private breakpointWidgetVisible: IContextKey<boolean>;
|
||||
private wordToLineNumbersMap: Map<string, Position[]> | undefined;
|
||||
|
||||
private exceptionWidget: ExceptionWidget | undefined;
|
||||
@@ -73,182 +59,21 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
constructor(
|
||||
private editor: ICodeEditor,
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
@ICodeEditorService private readonly codeEditorService: ICodeEditorService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||
@IDialogService private readonly dialogService: IDialogService,
|
||||
) {
|
||||
this.breakpointHintDecoration = [];
|
||||
this.hoverWidget = this.instantiationService.createInstance(DebugHoverWidget, this.editor);
|
||||
this.toDispose = [];
|
||||
this.registerListeners();
|
||||
this.breakpointWidgetVisible = CONTEXT_BREAKPOINT_WIDGET_VISIBLE.bindTo(contextKeyService);
|
||||
this.updateConfigurationWidgetVisibility();
|
||||
this.codeEditorService.registerDecorationType(INLINE_VALUE_DECORATION_KEY, {});
|
||||
this.toggleExceptionWidget();
|
||||
}
|
||||
|
||||
private getContextMenuActions(breakpoints: ReadonlyArray<IBreakpoint>, uri: uri, lineNumber: number): Array<IAction | ContextSubMenu> {
|
||||
const actions: Array<IAction | ContextSubMenu> = [];
|
||||
if (breakpoints.length === 1) {
|
||||
const breakpointType = breakpoints[0].logMessage ? nls.localize('logPoint', "Logpoint") : nls.localize('breakpoint', "Breakpoint");
|
||||
actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService, this.keybindingService));
|
||||
actions.push(new Action(
|
||||
'workbench.debug.action.editBreakpointAction',
|
||||
nls.localize('editBreakpoint', "Edit {0}...", breakpointType),
|
||||
undefined,
|
||||
true,
|
||||
() => Promise.resolve(this.editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(breakpoints[0].lineNumber, breakpoints[0].column))
|
||||
));
|
||||
|
||||
actions.push(new Action(
|
||||
`workbench.debug.viewlet.action.toggleBreakpoint`,
|
||||
breakpoints[0].enabled ? nls.localize('disableBreakpoint', "Disable {0}", breakpointType) : nls.localize('enableBreakpoint', "Enable {0}", breakpointType),
|
||||
undefined,
|
||||
true,
|
||||
() => this.debugService.enableOrDisableBreakpoints(!breakpoints[0].enabled, breakpoints[0])
|
||||
));
|
||||
} else if (breakpoints.length > 1) {
|
||||
const sorted = breakpoints.slice().sort((first, second) => (first.column && second.column) ? first.column - second.column : 1);
|
||||
actions.push(new ContextSubMenu(nls.localize('removeBreakpoints', "Remove Breakpoints"), sorted.map(bp => new Action(
|
||||
'removeInlineBreakpoint',
|
||||
bp.column ? nls.localize('removeInlineBreakpointOnColumn', "Remove Inline Breakpoint on Column {0}", bp.column) : nls.localize('removeLineBreakpoint', "Remove Line Breakpoint"),
|
||||
undefined,
|
||||
true,
|
||||
() => this.debugService.removeBreakpoints(bp.getId())
|
||||
))));
|
||||
|
||||
actions.push(new ContextSubMenu(nls.localize('editBreakpoints', "Edit Breakpoints"), sorted.map(bp =>
|
||||
new Action('editBreakpoint',
|
||||
bp.column ? nls.localize('editInlineBreakpointOnColumn', "Edit Inline Breakpoint on Column {0}", bp.column) : nls.localize('editLineBrekapoint', "Edit Line Breakpoint"),
|
||||
undefined,
|
||||
true,
|
||||
() => Promise.resolve(this.editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(bp.lineNumber, bp.column))
|
||||
)
|
||||
)));
|
||||
|
||||
actions.push(new ContextSubMenu(nls.localize('enableDisableBreakpoints', "Enable/Disable Breakpoints"), sorted.map(bp => new Action(
|
||||
bp.enabled ? 'disableColumnBreakpoint' : 'enableColumnBreakpoint',
|
||||
bp.enabled ? (bp.column ? nls.localize('disableInlineColumnBreakpoint', "Disable Inline Breakpoint on Column {0}", bp.column) : nls.localize('disableBreakpointOnLine', "Disable Line Breakpoint"))
|
||||
: (bp.column ? nls.localize('enableBreakpoints', "Enable Inline Breakpoint on Column {0}", bp.column) : nls.localize('enableBreakpointOnLine', "Enable Line Breakpoint")),
|
||||
undefined,
|
||||
true,
|
||||
() => this.debugService.enableOrDisableBreakpoints(!bp.enabled, bp)
|
||||
))));
|
||||
} else {
|
||||
actions.push(new Action(
|
||||
'addBreakpoint',
|
||||
nls.localize('addBreakpoint', "Add Breakpoint"),
|
||||
undefined,
|
||||
true,
|
||||
() => this.debugService.addBreakpoints(uri, [{ lineNumber }], `debugEditorContextMenu`)
|
||||
));
|
||||
actions.push(new Action(
|
||||
'addConditionalBreakpoint',
|
||||
nls.localize('addConditionalBreakpoint', "Add Conditional Breakpoint..."),
|
||||
undefined,
|
||||
true,
|
||||
() => Promise.resolve(this.editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(lineNumber, undefined))
|
||||
));
|
||||
actions.push(new Action(
|
||||
'addLogPoint',
|
||||
nls.localize('addLogPoint', "Add Logpoint..."),
|
||||
undefined,
|
||||
true,
|
||||
() => Promise.resolve(this.editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(lineNumber, undefined, BreakpointWidgetContext.LOG_MESSAGE))
|
||||
));
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this.toDispose.push(this.editor.onMouseDown(async (e: IEditorMouseEvent) => {
|
||||
const data = e.target.detail as IMarginData;
|
||||
const model = this.editor.getModel();
|
||||
if (!e.target.position || !model || e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN || data.isAfterLines || !this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
|
||||
return;
|
||||
}
|
||||
const canSetBreakpoints = this.debugService.getConfigurationManager().canSetBreakpointsIn(model);
|
||||
const lineNumber = e.target.position.lineNumber;
|
||||
const uri = model.uri;
|
||||
|
||||
if (e.event.rightButton || (env.isMacintosh && e.event.leftButton && e.event.ctrlKey)) {
|
||||
if (!canSetBreakpoints) {
|
||||
return;
|
||||
}
|
||||
|
||||
const anchor = { x: e.event.posx, y: e.event.posy };
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints({ lineNumber, uri });
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => this.getContextMenuActions(breakpoints, uri, lineNumber),
|
||||
getActionsContext: () => breakpoints.length ? breakpoints[0] : undefined
|
||||
});
|
||||
} else {
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints({ uri, lineNumber });
|
||||
|
||||
if (breakpoints.length) {
|
||||
// Show the dialog if there is a potential condition to be accidently lost.
|
||||
// Do not show dialog on linux due to electron issue freezing the mouse #50026
|
||||
if (!env.isLinux && breakpoints.some(bp => !!bp.condition || !!bp.logMessage || !!bp.hitCondition)) {
|
||||
const logPoint = breakpoints.every(bp => !!bp.logMessage);
|
||||
const breakpointType = logPoint ? nls.localize('logPoint', "Logpoint") : nls.localize('breakpoint', "Breakpoint");
|
||||
const disable = breakpoints.some(bp => bp.enabled);
|
||||
|
||||
const enabling = nls.localize('breakpointHasConditionDisabled',
|
||||
"This {0} has a {1} that will get lost on remove. Consider enabling the {0} instead.",
|
||||
breakpointType.toLowerCase(),
|
||||
logPoint ? nls.localize('message', "message") : nls.localize('condition', "condition")
|
||||
);
|
||||
const disabling = nls.localize('breakpointHasConditionEnabled',
|
||||
"This {0} has a {1} that will get lost on remove. Consider disabling the {0} instead.",
|
||||
breakpointType.toLowerCase(),
|
||||
logPoint ? nls.localize('message', "message") : nls.localize('condition', "condition")
|
||||
);
|
||||
|
||||
const { choice } = await this.dialogService.show(severity.Info, disable ? disabling : enabling, [
|
||||
nls.localize('removeLogPoint', "Remove {0}", breakpointType),
|
||||
nls.localize('disableLogPoint', "{0} {1}", disable ? nls.localize('disable', "Disable") : nls.localize('enable', "Enable"), breakpointType),
|
||||
nls.localize('cancel', "Cancel")
|
||||
], { cancelId: 2 });
|
||||
|
||||
if (choice === 0) {
|
||||
breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()));
|
||||
}
|
||||
if (choice === 1) {
|
||||
breakpoints.forEach(bp => this.debugService.enableOrDisableBreakpoints(!disable, bp));
|
||||
}
|
||||
} else {
|
||||
breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()));
|
||||
}
|
||||
} else if (canSetBreakpoints) {
|
||||
this.debugService.addBreakpoints(uri, [{ lineNumber }], `debugEditorGutter`);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
this.toDispose.push(this.editor.onMouseMove((e: IEditorMouseEvent) => {
|
||||
let showBreakpointHintAtLineNumber = -1;
|
||||
const model = this.editor.getModel();
|
||||
if (model && e.target.position && e.target.type === MouseTargetType.GUTTER_GLYPH_MARGIN && this.debugService.getConfigurationManager().canSetBreakpointsIn(model) &&
|
||||
this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
|
||||
const data = e.target.detail as IMarginData;
|
||||
if (!data.isAfterLines) {
|
||||
showBreakpointHintAtLineNumber = e.target.position.lineNumber;
|
||||
}
|
||||
}
|
||||
this.ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber);
|
||||
}));
|
||||
this.toDispose.push(this.editor.onMouseLeave((e: IEditorMouseEvent) => {
|
||||
this.ensureBreakpointHintDecoration(-1);
|
||||
}));
|
||||
this.toDispose.push(this.debugService.getViewModel().onDidFocusStackFrame(e => this.onFocusStackFrame(e.stackFrame)));
|
||||
|
||||
// hover listeners & hover widget
|
||||
@@ -279,7 +104,6 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
if (model) {
|
||||
this._applyHoverConfiguration(model, stackFrame);
|
||||
}
|
||||
this.closeBreakpointWidget();
|
||||
this.toggleExceptionWidget();
|
||||
this.hideHoverWidget();
|
||||
this.updateConfigurationWidgetVisibility();
|
||||
@@ -317,11 +141,11 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
}
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
getId(): string {
|
||||
return EDITOR_CONTRIBUTION_ID;
|
||||
}
|
||||
|
||||
public showHover(range: Range, focus: boolean): Promise<void> {
|
||||
showHover(range: Range, focus: boolean): Promise<void> {
|
||||
const sf = this.debugService.getViewModel().focusedStackFrame;
|
||||
const model = this.editor.getModel();
|
||||
if (sf && model && sf.source.uri.toString() === model.uri.toString()) {
|
||||
@@ -331,36 +155,6 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
private marginFreeFromNonDebugDecorations(line: number): boolean {
|
||||
const decorations = this.editor.getLineDecorations(line);
|
||||
if (decorations) {
|
||||
for (const { options } of decorations) {
|
||||
if (options.glyphMarginClassName && options.glyphMarginClassName.indexOf('debug') === -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber: number): void {
|
||||
const newDecoration: IModelDeltaDecoration[] = [];
|
||||
if (showBreakpointHintAtLineNumber !== -1) {
|
||||
newDecoration.push({
|
||||
options: DebugEditorContribution.BREAKPOINT_HELPER_DECORATION,
|
||||
range: {
|
||||
startLineNumber: showBreakpointHintAtLineNumber,
|
||||
startColumn: 1,
|
||||
endLineNumber: showBreakpointHintAtLineNumber,
|
||||
endColumn: 1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.breakpointHintDecoration = this.editor.deltaDecorations(this.breakpointHintDecoration, newDecoration);
|
||||
}
|
||||
|
||||
private onFocusStackFrame(sf: IStackFrame | undefined): void {
|
||||
const model = this.editor.getModel();
|
||||
if (model) {
|
||||
@@ -464,29 +258,8 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
this.hideHoverWidget();
|
||||
}
|
||||
}
|
||||
|
||||
// end hover business
|
||||
|
||||
// breakpoint widget
|
||||
public showBreakpointWidget(lineNumber: number, column: number, context?: BreakpointWidgetContext): void {
|
||||
if (this.breakpointWidget) {
|
||||
this.breakpointWidget.dispose();
|
||||
}
|
||||
|
||||
this.breakpointWidget = this.instantiationService.createInstance(BreakpointWidget, this.editor, lineNumber, context);
|
||||
this.breakpointWidget.show({ lineNumber, column: 1 }, 2);
|
||||
this.breakpointWidgetVisible.set(true);
|
||||
}
|
||||
|
||||
public closeBreakpointWidget(): void {
|
||||
if (this.breakpointWidget) {
|
||||
this.breakpointWidget.dispose();
|
||||
this.breakpointWidget = undefined;
|
||||
this.breakpointWidgetVisible.reset();
|
||||
this.editor.focus();
|
||||
}
|
||||
}
|
||||
|
||||
// exception widget
|
||||
private toggleExceptionWidget(): void {
|
||||
// Toggles exception widget based on the state of the current editor model and debug stack frame
|
||||
@@ -547,7 +320,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
}
|
||||
}
|
||||
|
||||
public addLaunchConfiguration(): Promise<any> {
|
||||
addLaunchConfiguration(): Promise<any> {
|
||||
/* __GDPR__
|
||||
"debug/addLaunchConfiguration" : {}
|
||||
*/
|
||||
@@ -594,11 +367,6 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
return insertLine(configurationsArrayPosition).then(() => this.commandService.executeCommand('editor.action.triggerSuggest'));
|
||||
}
|
||||
|
||||
private static BREAKPOINT_HELPER_DECORATION: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-breakpoint-hint',
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
|
||||
};
|
||||
|
||||
// Inline Decorations
|
||||
|
||||
@memoize
|
||||
@@ -768,17 +536,14 @@ export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
return this.wordToLineNumbersMap;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this.breakpointWidget) {
|
||||
this.breakpointWidget.dispose();
|
||||
}
|
||||
dispose(): void {
|
||||
if (this.hoverWidget) {
|
||||
this.hoverWidget.dispose();
|
||||
}
|
||||
if (this.configurationWidget) {
|
||||
this.configurationWidget.dispose();
|
||||
}
|
||||
this.toDispose = lifecycle.dispose(this.toDispose);
|
||||
this.toDispose = dispose(this.toDispose);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,334 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import { Constants } from 'vs/editor/common/core/uint';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ITextModel, TrackedRangeStickiness, IModelDeltaDecoration, IModelDecorationOptions } from 'vs/editor/common/model';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IDebugService, IBreakpoint, State, IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { getBreakpointMessageAndClassName } from 'vs/workbench/contrib/debug/browser/breakpointsView';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { localize } from 'vs/nls';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
|
||||
interface IBreakpointDecoration {
|
||||
decorationId: string;
|
||||
modelId: string;
|
||||
range: Range;
|
||||
}
|
||||
|
||||
interface IDebugEditorModelData {
|
||||
model: ITextModel;
|
||||
toDispose: lifecycle.IDisposable[];
|
||||
breakpointDecorations: IBreakpointDecoration[];
|
||||
currentStackDecorations: string[];
|
||||
topStackFrameRange: Range | undefined;
|
||||
}
|
||||
|
||||
export class DebugEditorModelManager implements IWorkbenchContribution {
|
||||
static readonly ID = 'breakpointManager';
|
||||
static readonly STICKINESS = TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges;
|
||||
private modelDataMap: Map<string, IDebugEditorModelData>;
|
||||
private toDispose: lifecycle.IDisposable[];
|
||||
private ignoreDecorationsChangedEvent = false;
|
||||
|
||||
constructor(
|
||||
@IModelService private readonly modelService: IModelService,
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
) {
|
||||
this.modelDataMap = new Map<string, IDebugEditorModelData>();
|
||||
this.toDispose = [];
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.modelDataMap.forEach(modelData => {
|
||||
lifecycle.dispose(modelData.toDispose);
|
||||
modelData.model.deltaDecorations(modelData.breakpointDecorations.map(bpd => bpd.decorationId), []);
|
||||
modelData.model.deltaDecorations(modelData.currentStackDecorations, []);
|
||||
});
|
||||
this.toDispose = lifecycle.dispose(this.toDispose);
|
||||
|
||||
this.modelDataMap.clear();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this.toDispose.push(this.modelService.onModelAdded(this.onModelAdded, this));
|
||||
this.modelService.getModels().forEach(model => this.onModelAdded(model));
|
||||
this.toDispose.push(this.modelService.onModelRemoved(this.onModelRemoved, this));
|
||||
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange()));
|
||||
this.toDispose.push(this.debugService.getViewModel().onDidFocusStackFrame(() => this.onFocusStackFrame()));
|
||||
this.toDispose.push(this.debugService.onDidChangeState(state => {
|
||||
if (state === State.Inactive) {
|
||||
this.modelDataMap.forEach(modelData => {
|
||||
modelData.topStackFrameRange = undefined;
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private onModelAdded(model: ITextModel): void {
|
||||
const modelUriStr = model.uri.toString();
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints({ uri: model.uri });
|
||||
|
||||
const currentStackDecorations = model.deltaDecorations([], this.createCallStackDecorations(modelUriStr));
|
||||
const desiredDecorations = this.createBreakpointDecorations(model, breakpoints);
|
||||
const breakpointDecorationIds = model.deltaDecorations([], desiredDecorations);
|
||||
const toDispose: lifecycle.IDisposable[] = [model.onDidChangeDecorations((e) => this.onModelDecorationsChanged(modelUriStr))];
|
||||
|
||||
this.modelDataMap.set(modelUriStr, {
|
||||
model: model,
|
||||
toDispose: toDispose,
|
||||
breakpointDecorations: breakpointDecorationIds.map((decorationId, index) => ({ decorationId, modelId: breakpoints[index].getId(), range: desiredDecorations[index].range })),
|
||||
currentStackDecorations: currentStackDecorations,
|
||||
topStackFrameRange: undefined
|
||||
});
|
||||
}
|
||||
|
||||
private onModelRemoved(model: ITextModel): void {
|
||||
const modelUriStr = model.uri.toString();
|
||||
const data = this.modelDataMap.get(modelUriStr);
|
||||
if (data) {
|
||||
lifecycle.dispose(data.toDispose);
|
||||
this.modelDataMap.delete(modelUriStr);
|
||||
}
|
||||
}
|
||||
|
||||
// call stack management. Represent data coming from the debug service.
|
||||
|
||||
private onFocusStackFrame(): void {
|
||||
this.modelDataMap.forEach((modelData, uri) => {
|
||||
modelData.currentStackDecorations = modelData.model.deltaDecorations(modelData.currentStackDecorations, this.createCallStackDecorations(uri));
|
||||
});
|
||||
}
|
||||
|
||||
private createCallStackDecorations(modelUriStr: string): IModelDeltaDecoration[] {
|
||||
const result: IModelDeltaDecoration[] = [];
|
||||
const stackFrame = this.debugService.getViewModel().focusedStackFrame;
|
||||
if (!stackFrame || stackFrame.source.uri.toString() !== modelUriStr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// only show decorations for the currently focused thread.
|
||||
const columnUntilEOLRange = new Range(stackFrame.range.startLineNumber, stackFrame.range.startColumn, stackFrame.range.startLineNumber, Constants.MAX_SAFE_SMALL_INTEGER);
|
||||
const range = new Range(stackFrame.range.startLineNumber, stackFrame.range.startColumn, stackFrame.range.startLineNumber, stackFrame.range.startColumn + 1);
|
||||
|
||||
// compute how to decorate the editor. Different decorations are used if this is a top stack frame, focused stack frame,
|
||||
// an exception or a stack frame that did not change the line number (we only decorate the columns, not the whole line).
|
||||
const callStack = stackFrame.thread.getCallStack();
|
||||
if (callStack && callStack.length && stackFrame === callStack[0]) {
|
||||
result.push({
|
||||
options: DebugEditorModelManager.TOP_STACK_FRAME_MARGIN,
|
||||
range
|
||||
});
|
||||
|
||||
result.push({
|
||||
options: DebugEditorModelManager.TOP_STACK_FRAME_DECORATION,
|
||||
range: columnUntilEOLRange
|
||||
});
|
||||
|
||||
const modelData = this.modelDataMap.get(modelUriStr);
|
||||
if (modelData) {
|
||||
if (modelData.topStackFrameRange && modelData.topStackFrameRange.startLineNumber === stackFrame.range.startLineNumber && modelData.topStackFrameRange.startColumn !== stackFrame.range.startColumn) {
|
||||
result.push({
|
||||
options: DebugEditorModelManager.TOP_STACK_FRAME_INLINE_DECORATION,
|
||||
range: columnUntilEOLRange
|
||||
});
|
||||
}
|
||||
modelData.topStackFrameRange = columnUntilEOLRange;
|
||||
}
|
||||
} else {
|
||||
result.push({
|
||||
options: DebugEditorModelManager.FOCUSED_STACK_FRAME_MARGIN,
|
||||
range
|
||||
});
|
||||
|
||||
result.push({
|
||||
options: DebugEditorModelManager.FOCUSED_STACK_FRAME_DECORATION,
|
||||
range: columnUntilEOLRange
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// breakpoints management. Represent data coming from the debug service and also send data back.
|
||||
private onModelDecorationsChanged(modelUrlStr: string): void {
|
||||
const modelData = this.modelDataMap.get(modelUrlStr);
|
||||
if (!modelData || modelData.breakpointDecorations.length === 0 || this.ignoreDecorationsChangedEvent) {
|
||||
// I have no decorations
|
||||
return;
|
||||
}
|
||||
let somethingChanged = false;
|
||||
modelData.breakpointDecorations.forEach(breakpointDecoration => {
|
||||
if (somethingChanged) {
|
||||
return;
|
||||
}
|
||||
const newBreakpointRange = modelData.model.getDecorationRange(breakpointDecoration.decorationId);
|
||||
if (newBreakpointRange && (!breakpointDecoration.range.equalsRange(newBreakpointRange))) {
|
||||
somethingChanged = true;
|
||||
}
|
||||
});
|
||||
if (!somethingChanged) {
|
||||
// nothing to do, my decorations did not change.
|
||||
return;
|
||||
}
|
||||
|
||||
const data = new Map<string, IBreakpointUpdateData>();
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints();
|
||||
const modelUri = modelData.model.uri;
|
||||
for (let i = 0, len = modelData.breakpointDecorations.length; i < len; i++) {
|
||||
const breakpointDecoration = modelData.breakpointDecorations[i];
|
||||
const decorationRange = modelData.model.getDecorationRange(breakpointDecoration.decorationId);
|
||||
// check if the line got deleted.
|
||||
if (decorationRange) {
|
||||
const breakpoint = breakpoints.filter(bp => bp.getId() === breakpointDecoration.modelId).pop();
|
||||
// since we know it is collapsed, it cannot grow to multiple lines
|
||||
if (breakpoint) {
|
||||
data.set(breakpoint.getId(), {
|
||||
lineNumber: decorationRange.startLineNumber,
|
||||
column: breakpoint.column ? decorationRange.startColumn : undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.debugService.updateBreakpoints(modelUri, data, true).then(undefined, onUnexpectedError);
|
||||
}
|
||||
|
||||
private onBreakpointsChange(): void {
|
||||
const breakpointsMap = new Map<string, IBreakpoint[]>();
|
||||
this.debugService.getModel().getBreakpoints().forEach(bp => {
|
||||
const uriStr = bp.uri.toString();
|
||||
const breakpoints = breakpointsMap.get(uriStr);
|
||||
if (breakpoints) {
|
||||
breakpoints.push(bp);
|
||||
} else {
|
||||
breakpointsMap.set(uriStr, [bp]);
|
||||
}
|
||||
});
|
||||
|
||||
breakpointsMap.forEach((bps, uri) => {
|
||||
const data = this.modelDataMap.get(uri);
|
||||
if (data) {
|
||||
this.updateBreakpoints(data, breakpointsMap.get(uri)!);
|
||||
}
|
||||
});
|
||||
this.modelDataMap.forEach((modelData, uri) => {
|
||||
if (!breakpointsMap.has(uri)) {
|
||||
this.updateBreakpoints(modelData, []);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private updateBreakpoints(modelData: IDebugEditorModelData, newBreakpoints: IBreakpoint[]): void {
|
||||
const desiredDecorations = this.createBreakpointDecorations(modelData.model, newBreakpoints);
|
||||
try {
|
||||
this.ignoreDecorationsChangedEvent = true;
|
||||
const breakpointDecorationIds = modelData.model.deltaDecorations(modelData.breakpointDecorations.map(bpd => bpd.decorationId), desiredDecorations);
|
||||
modelData.breakpointDecorations = breakpointDecorationIds.map((decorationId, index) => ({
|
||||
decorationId,
|
||||
modelId: newBreakpoints[index].getId(),
|
||||
range: desiredDecorations[index].range
|
||||
}));
|
||||
} finally {
|
||||
this.ignoreDecorationsChangedEvent = false;
|
||||
}
|
||||
}
|
||||
|
||||
private createBreakpointDecorations(model: ITextModel, breakpoints: ReadonlyArray<IBreakpoint>): { range: Range; options: IModelDecorationOptions; }[] {
|
||||
const result: { range: Range; options: IModelDecorationOptions; }[] = [];
|
||||
breakpoints.forEach((breakpoint) => {
|
||||
if (breakpoint.lineNumber <= model.getLineCount()) {
|
||||
const column = model.getLineFirstNonWhitespaceColumn(breakpoint.lineNumber);
|
||||
const range = model.validateRange(
|
||||
breakpoint.column ? new Range(breakpoint.lineNumber, breakpoint.column, breakpoint.lineNumber, breakpoint.column + 1)
|
||||
: new Range(breakpoint.lineNumber, column, breakpoint.lineNumber, column + 1) // Decoration has to have a width #20688
|
||||
);
|
||||
|
||||
result.push({
|
||||
options: this.getBreakpointDecorationOptions(breakpoint),
|
||||
range
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private getBreakpointDecorationOptions(breakpoint: IBreakpoint): IModelDecorationOptions {
|
||||
const { className, message } = getBreakpointMessageAndClassName(this.debugService, breakpoint);
|
||||
let glyphMarginHoverMessage: MarkdownString | undefined;
|
||||
|
||||
if (message) {
|
||||
if (breakpoint.condition || breakpoint.hitCondition) {
|
||||
const modelData = this.modelDataMap.get(breakpoint.uri.toString());
|
||||
const modeId = modelData ? modelData.model.getLanguageIdentifier().language : '';
|
||||
glyphMarginHoverMessage = new MarkdownString().appendCodeblock(modeId, message);
|
||||
} else {
|
||||
glyphMarginHoverMessage = new MarkdownString().appendText(message);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
glyphMarginClassName: className,
|
||||
glyphMarginHoverMessage,
|
||||
stickiness: DebugEditorModelManager.STICKINESS,
|
||||
beforeContentClassName: breakpoint.column ? `debug-breakpoint-column ${className}-column` : undefined
|
||||
};
|
||||
}
|
||||
|
||||
// editor decorations
|
||||
|
||||
// we need a separate decoration for glyph margin, since we do not want it on each line of a multi line statement.
|
||||
private static TOP_STACK_FRAME_MARGIN: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-top-stack-frame',
|
||||
stickiness: DebugEditorModelManager.STICKINESS
|
||||
};
|
||||
|
||||
private static FOCUSED_STACK_FRAME_MARGIN: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-focused-stack-frame',
|
||||
stickiness: DebugEditorModelManager.STICKINESS
|
||||
};
|
||||
|
||||
private static TOP_STACK_FRAME_DECORATION: IModelDecorationOptions = {
|
||||
isWholeLine: true,
|
||||
inlineClassName: 'debug-remove-token-colors',
|
||||
className: 'debug-top-stack-frame-line',
|
||||
stickiness: DebugEditorModelManager.STICKINESS
|
||||
};
|
||||
|
||||
private static TOP_STACK_FRAME_INLINE_DECORATION: IModelDecorationOptions = {
|
||||
beforeContentClassName: 'debug-top-stack-frame-column'
|
||||
};
|
||||
|
||||
private static FOCUSED_STACK_FRAME_DECORATION: IModelDecorationOptions = {
|
||||
isWholeLine: true,
|
||||
inlineClassName: 'debug-remove-token-colors',
|
||||
className: 'debug-focused-stack-frame-line',
|
||||
stickiness: DebugEditorModelManager.STICKINESS
|
||||
};
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const topStackFrame = theme.getColor(topStackFrameColor);
|
||||
if (topStackFrame) {
|
||||
collector.addRule(`.monaco-editor .view-overlays .debug-top-stack-frame-line { background: ${topStackFrame}; }`);
|
||||
collector.addRule(`.monaco-editor .view-overlays .debug-top-stack-frame-line { background: ${topStackFrame}; }`);
|
||||
}
|
||||
|
||||
const focusedStackFrame = theme.getColor(focusedStackFrameColor);
|
||||
if (focusedStackFrame) {
|
||||
collector.addRule(`.monaco-editor .view-overlays .debug-focused-stack-frame-line { background: ${focusedStackFrame}; }`);
|
||||
}
|
||||
});
|
||||
|
||||
const topStackFrameColor = registerColor('editor.stackFrameHighlightBackground', { dark: '#ffff0033', light: '#ffff6673', hc: '#fff600' }, localize('topStackFrameLineHighlight', 'Background color for the highlight of line at the top stack frame position.'));
|
||||
const focusedStackFrameColor = registerColor('editor.focusedStackFrameHighlightBackground', { dark: '#7abd7a4d', light: '#cee7ce73', hc: '#cee7ce' }, localize('focusedStackFrameLineHighlight', 'Background color for the highlight of line at focused stack frame position.'));
|
||||
@@ -10,19 +10,20 @@ import * as platform from 'vs/base/common/platform';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { CompletionItem, completionKindFromString } from 'vs/editor/common/modes';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Position, IPosition } from 'vs/editor/common/core/position';
|
||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
import { IDebugSession, IConfig, IThread, IRawModelUpdate, IDebugService, IRawStoppedDetails, State, LoadedSourceEvent, IFunctionBreakpoint, IExceptionBreakpoint, IBreakpoint, IExceptionInfo, AdapterEndEvent, IDebugger, VIEWLET_ID, IDebugConfiguration, IReplElement, IStackFrame, IExpression, IReplElementSource, IDataBreakpoint } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { Thread, ExpressionContainer, DebugModel } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { RawDebugSession } from 'vs/workbench/contrib/debug/browser/rawDebugSession';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IWorkspaceFolder, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { normalizeDriveLetter } from 'vs/base/common/labels';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
@@ -34,6 +35,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { variableSetEmitter } from 'vs/workbench/contrib/debug/browser/variablesView';
|
||||
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { distinct } from 'vs/base/common/arrays';
|
||||
|
||||
export class DebugSession implements IDebugSession {
|
||||
|
||||
@@ -73,7 +75,7 @@ export class DebugSession implements IDebugSession {
|
||||
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IWindowsService private readonly windowsService: IWindowsService,
|
||||
@IExtensionHostDebugService private readonly extensionHostDebugService: IExtensionHostDebugService,
|
||||
@IOpenerService private readonly openerService: IOpenerService
|
||||
) {
|
||||
this.id = generateUuid();
|
||||
@@ -185,7 +187,7 @@ export class DebugSession implements IDebugSession {
|
||||
|
||||
return dbgr.createDebugAdapter(this).then(debugAdapter => {
|
||||
|
||||
this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.windowsService, this.openerService);
|
||||
this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.extensionHostDebugService, this.openerService);
|
||||
|
||||
return this.raw.start().then(() => {
|
||||
|
||||
@@ -284,15 +286,7 @@ export class DebugSession implements IDebugSession {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const source = this.getSourceForUri(modelUri);
|
||||
let rawSource: DebugProtocol.Source;
|
||||
if (source) {
|
||||
rawSource = source.raw;
|
||||
} else {
|
||||
const data = Source.getEncodedDebugData(modelUri);
|
||||
rawSource = { name: data.name, path: data.path, sourceReference: data.sourceReference };
|
||||
}
|
||||
|
||||
const rawSource = this.getRawSource(modelUri);
|
||||
if (breakpointsToSend.length && !rawSource.adapterData) {
|
||||
rawSource.adapterData = breakpointsToSend[0].adapterData;
|
||||
}
|
||||
@@ -376,6 +370,17 @@ export class DebugSession implements IDebugSession {
|
||||
return Promise.reject(new Error('no debug adapter'));
|
||||
}
|
||||
|
||||
async breakpointsLocations(uri: URI, lineNumber: number): Promise<IPosition[]> {
|
||||
if (this.raw) {
|
||||
const source = this.getRawSource(uri);
|
||||
const response = await this.raw.breakpointLocations({ source, line: lineNumber });
|
||||
const positions = response.body.breakpoints.map(bp => ({ lineNumber: bp.line, column: bp.column || 1 }));
|
||||
|
||||
return distinct(positions, p => `${p.lineNumber}:${p.column}`);
|
||||
}
|
||||
return Promise.reject(new Error('no debug adapter'));
|
||||
}
|
||||
|
||||
customRequest(request: string, args: any): Promise<DebugProtocol.Response> {
|
||||
if (this.raw) {
|
||||
return this.raw.custom(request, args);
|
||||
@@ -914,6 +919,16 @@ export class DebugSession implements IDebugSession {
|
||||
return source;
|
||||
}
|
||||
|
||||
private getRawSource(uri: URI): DebugProtocol.Source {
|
||||
const source = this.getSourceForUri(uri);
|
||||
if (source) {
|
||||
return source.raw;
|
||||
} else {
|
||||
const data = Source.getEncodedDebugData(uri);
|
||||
return { name: data.name, path: data.path, sourceReference: data.sourceReference };
|
||||
}
|
||||
}
|
||||
|
||||
private getNewCancellationToken(threadId: number): CancellationToken {
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
const tokens = this.cancellationMap.get(threadId) || [];
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
|
||||
import { IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug';
|
||||
@@ -13,8 +13,10 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
|
||||
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient {
|
||||
class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient implements IExtensionHostDebugService {
|
||||
|
||||
constructor(
|
||||
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
|
||||
@@ -45,6 +47,52 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient {
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void> {
|
||||
// we pass the "ParsedArgs" as query parameters of the URL
|
||||
|
||||
let newAddress = `${document.location.origin}${document.location.pathname}?`;
|
||||
let gotFolder = false;
|
||||
|
||||
const addQueryParameter = (key: string, value: string) => {
|
||||
const lastChar = newAddress.charAt(newAddress.length - 1);
|
||||
if (lastChar !== '?' && lastChar !== '&') {
|
||||
newAddress += '&';
|
||||
}
|
||||
newAddress += `${key}=${encodeURIComponent(value)}`;
|
||||
};
|
||||
|
||||
const f = args['folder-uri'];
|
||||
if (f) {
|
||||
const u = URI.parse(f[0]);
|
||||
gotFolder = true;
|
||||
addQueryParameter('folder', u.path);
|
||||
}
|
||||
if (!gotFolder) {
|
||||
// request empty window
|
||||
addQueryParameter('ew', 'true');
|
||||
}
|
||||
|
||||
const ep = args['extensionDevelopmentPath'];
|
||||
if (ep) {
|
||||
let u = ep[0];
|
||||
addQueryParameter('edp', u);
|
||||
}
|
||||
|
||||
const di = args['debugId'];
|
||||
if (di) {
|
||||
addQueryParameter('di', di);
|
||||
}
|
||||
|
||||
const ibe = args['inspect-brk-extensions'];
|
||||
if (ibe) {
|
||||
addQueryParameter('ibe', ibe);
|
||||
}
|
||||
|
||||
window.open(newAddress);
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IExtensionHostDebugService, BrowserExtensionHostDebugService);
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="#C5C5C5"/>
|
||||
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="#C5C5C5"/>
|
||||
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="#C5C5C5"/>
|
||||
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="#C5C5C5"/>
|
||||
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 484 B |
@@ -1,7 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="white"/>
|
||||
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="white"/>
|
||||
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="white"/>
|
||||
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="white"/>
|
||||
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 474 B |
@@ -1,7 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="#424242"/>
|
||||
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="#424242"/>
|
||||
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="#424242"/>
|
||||
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="#424242"/>
|
||||
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 484 B |
@@ -17,12 +17,20 @@
|
||||
}
|
||||
|
||||
.debug-breakpoint-disabled,
|
||||
.monaco-editor .debug-breakpoint-column.debug-breakpoint-disabled-column::before {
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-disabled {
|
||||
background: url('breakpoint-disabled.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-disabled:hover {
|
||||
background: url('breakpoint-hint.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .inline-breakpoint-widget.line-start {
|
||||
left: -0.45em !important;
|
||||
}
|
||||
|
||||
.debug-breakpoint-unverified,
|
||||
.monaco-editor .debug-breakpoint-column.debug-breakpoint-unverified-column::before {
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-unverified {
|
||||
background: url('breakpoint-unverified.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
@@ -35,21 +43,31 @@
|
||||
}
|
||||
|
||||
.debug-breakpoint,
|
||||
.monaco-editor .debug-breakpoint-column::before {
|
||||
.monaco-editor .inline-breakpoint-widget {
|
||||
background: url('breakpoint.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-breakpoint-column::before,
|
||||
.monaco-editor .debug-breakpoint-placeholder::before,
|
||||
.monaco-editor .debug-top-stack-frame-column::before {
|
||||
content: " ";
|
||||
width: 1.3em;
|
||||
height: 1.3em;
|
||||
display: inline-block;
|
||||
vertical-align: text-bottom;
|
||||
margin-right: 2px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame-column::before {
|
||||
height: 1.3em;
|
||||
}
|
||||
|
||||
.monaco-editor .inline-breakpoint-widget {
|
||||
width: 1.3em;
|
||||
height: 1.3em;
|
||||
margin-left: 0.61em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.debug-function-breakpoint {
|
||||
background: url('breakpoint-function.svg') center center no-repeat;
|
||||
}
|
||||
@@ -75,34 +93,34 @@
|
||||
}
|
||||
|
||||
.debug-breakpoint-conditional,
|
||||
.monaco-editor .debug-breakpoint-column.debug-breakpoint-conditional-column::before {
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-conditional {
|
||||
background: url('breakpoint-conditional.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-breakpoint-log,
|
||||
.monaco-editor .debug-breakpoint-column.debug-breakpoint-log-column::before {
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log {
|
||||
background: url('breakpoint-log.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-breakpoint-log-disabled,
|
||||
.monaco-editor .debug-breakpoint-log-disabled-column::before {
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log-disabled {
|
||||
background: url('breakpoint-log-disabled.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-breakpoint-log-unverified,
|
||||
.monaco-editor .debug-breakpoint-log-unverified-column::before {
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log-unverified {
|
||||
background: url('breakpoint-log-unverified.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-breakpoint-unsupported,
|
||||
.monaco-editor .debug-breakpoint-column.debug-breakpoint-unsupported-column::before {
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-unsupported {
|
||||
background: url('breakpoint-unsupported.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame.debug-breakpoint,
|
||||
.monaco-editor .debug-top-stack-frame.debug-breakpoint-conditional,
|
||||
.monaco-editor .debug-top-stack-frame.debug-breakpoint-log,
|
||||
.monaco-editor .debug-breakpoint-column.debug-breakpoint-column.debug-top-stack-frame-column::before {
|
||||
.monaco-editor .inline-breakpoint-widget.debug-top-stack-frame-column {
|
||||
background: url('current-and-breakpoint.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,19 +88,6 @@
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
/* Actions */
|
||||
.debug-action.clear-repl {
|
||||
background: url('clear-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-action.clear-repl {
|
||||
background: url('clear-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.hc-black .debug-action.clear-repl {
|
||||
background: url('clear-hc.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
/* Output coloring and styling */
|
||||
.repl .repl-tree .output.expression > .ignore {
|
||||
font-style: italic;
|
||||
|
||||
@@ -13,7 +13,7 @@ import { formatPII, isUri } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { IDebugAdapter, IConfig, AdapterEndEvent, IDebugger } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { env as processEnv } from 'vs/base/common/process';
|
||||
@@ -79,7 +79,7 @@ export class RawDebugSession implements IDisposable {
|
||||
dbgr: IDebugger,
|
||||
private readonly telemetryService: ITelemetryService,
|
||||
public readonly customTelemetryService: ITelemetryService | undefined,
|
||||
private readonly windowsService: IWindowsService,
|
||||
private readonly extensionHostDebugService: IExtensionHostDebugService,
|
||||
private readonly openerService: IOpenerService
|
||||
|
||||
) {
|
||||
@@ -381,6 +381,13 @@ export class RawDebugSession implements IDisposable {
|
||||
return this.send<DebugProtocol.SetExceptionBreakpointsResponse>('setExceptionBreakpoints', args);
|
||||
}
|
||||
|
||||
breakpointLocations(args: DebugProtocol.BreakpointLocationsArguments): Promise<DebugProtocol.BreakpointLocationsResponse> {
|
||||
if (this.capabilities.supportsBreakpointLocationsRequest) {
|
||||
return this.send('breakpointLocations', args);
|
||||
}
|
||||
return Promise.reject(new Error('breakpointLocations is not supported'));
|
||||
}
|
||||
|
||||
configurationDone(): Promise<DebugProtocol.ConfigurationDoneResponse> {
|
||||
if (this.capabilities.supportsConfigurationDoneRequest) {
|
||||
return this.send('configurationDone', null);
|
||||
@@ -594,7 +601,7 @@ export class RawDebugSession implements IDisposable {
|
||||
} else {
|
||||
args[key] = [value];
|
||||
}
|
||||
} else if (key === 'extensionDevelopmentPath') {
|
||||
} else if (key === 'extensionDevelopmentPath' || key === 'enable-proposed-api') {
|
||||
const v = args[key];
|
||||
if (v) {
|
||||
v.push(value);
|
||||
@@ -625,7 +632,7 @@ export class RawDebugSession implements IDisposable {
|
||||
Object.keys(env).filter(k => env[k] === null).forEach(key => delete env[key]);
|
||||
}
|
||||
|
||||
return this.windowsService.openExtensionDevelopmentHostWindow(args, env);
|
||||
return this.extensionHostDebugService.openExtensionDevelopmentHostWindow(args, env);
|
||||
}
|
||||
|
||||
private send<R extends DebugProtocol.Response>(command: string, args: any, token?: CancellationToken, timeout?: number): Promise<R> {
|
||||
|
||||
@@ -1008,7 +1008,7 @@ export class ClearReplAction extends Action {
|
||||
constructor(id: string, label: string,
|
||||
@IPanelService private readonly panelService: IPanelService
|
||||
) {
|
||||
super(id, label, 'debug-action clear-repl');
|
||||
super(id, label, 'debug-action codicon-clear-all');
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel as EditorIModel } from 'vs/editor/common/model';
|
||||
import { IEditor, ITextEditor } from 'vs/workbench/common/editor';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Position, IPosition } from 'vs/editor/common/core/position';
|
||||
import { CompletionItem } from 'vs/editor/common/modes';
|
||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { Range, IRange } from 'vs/editor/common/core/range';
|
||||
@@ -58,6 +58,7 @@ export const CONTEXT_RESTART_FRAME_SUPPORTED = new RawContextKey<boolean>('resta
|
||||
export const CONTEXT_JUMP_TO_CURSOR_SUPPORTED = new RawContextKey<boolean>('jumpToCursorSupported', false);
|
||||
|
||||
export const EDITOR_CONTRIBUTION_ID = 'editor.contrib.debug';
|
||||
export const BREAKPOINT_EDITOR_CONTRIBUTION_ID = 'editor.contrib.breakpoint';
|
||||
export const DEBUG_SCHEME = 'debug';
|
||||
export const INTERNAL_CONSOLE_OPTIONS_SCHEMA = {
|
||||
enum: ['neverOpen', 'openOnSessionStart', 'openOnFirstSessionStart'],
|
||||
@@ -207,6 +208,7 @@ export interface IDebugSession extends ITreeElement {
|
||||
dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean }>;
|
||||
sendDataBreakpoints(dbps: IDataBreakpoint[]): Promise<void>;
|
||||
sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): Promise<void>;
|
||||
breakpointsLocations(uri: uri, lineNumber: number): Promise<IPosition[]>;
|
||||
|
||||
stackTrace(threadId: number, startFrame: number, levels: number): Promise<DebugProtocol.StackTraceResponse>;
|
||||
exceptionInfo(threadId: number): Promise<IExceptionInfo | undefined>;
|
||||
@@ -850,9 +852,12 @@ export const enum BreakpointWidgetContext {
|
||||
|
||||
export interface IDebugEditorContribution extends IEditorContribution {
|
||||
showHover(range: Range, focus: boolean): Promise<void>;
|
||||
addLaunchConfiguration(): Promise<any>;
|
||||
}
|
||||
|
||||
export interface IBreakpointEditorContribution extends IEditorContribution {
|
||||
showBreakpointWidget(lineNumber: number, column: number | undefined, context?: BreakpointWidgetContext): void;
|
||||
closeBreakpointWidget(): void;
|
||||
addLaunchConfiguration(): Promise<any>;
|
||||
}
|
||||
|
||||
// temporary debug helper service
|
||||
|
||||
@@ -7,13 +7,22 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
|
||||
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
|
||||
import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
|
||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
|
||||
export class ExtensionHostDebugService extends ExtensionHostDebugChannelClient {
|
||||
|
||||
constructor(
|
||||
@IMainProcessService readonly windowService: IMainProcessService,
|
||||
@IMainProcessService readonly mainProcessService: IMainProcessService,
|
||||
@IWindowsService private readonly windowsService: IWindowsService
|
||||
) {
|
||||
super(windowService.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName));
|
||||
super(mainProcessService.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName));
|
||||
}
|
||||
|
||||
openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void> {
|
||||
// TODO@Isidor use debug IPC channel
|
||||
return this.windowsService.openExtensionDevelopmentHostWindow(args, env);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { URI as uri } from 'vs/base/common/uri';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Position, IPosition } from 'vs/editor/common/core/position';
|
||||
import { ILaunch, IDebugService, State, IDebugSession, IConfigurationManager, IStackFrame, IBreakpointData, IBreakpointUpdateData, IConfig, IDebugModel, IViewModel, IBreakpoint, LoadedSourceEvent, IThread, IRawModelUpdate, IFunctionBreakpoint, IExceptionBreakpoint, IDebugger, IExceptionInfo, AdapterEndEvent, IReplElement, IExpression, IReplElementSource, IDataBreakpoint } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { CompletionItem } from 'vs/editor/common/modes';
|
||||
@@ -132,6 +132,11 @@ export class MockDebugService implements IDebugService {
|
||||
}
|
||||
|
||||
export class MockSession implements IDebugSession {
|
||||
|
||||
breakpointsLocations(uri: uri, lineNumber: number): Promise<IPosition[]> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
dataBreakpointInfo(name: string, variablesReference?: number | undefined): Promise<{ dataId: string | null; description: string; canPersist?: boolean | undefined; }> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import { ITextFileService, StateChange } from 'vs/workbench/services/textfile/co
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { distinct } from 'vs/base/common/arrays';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IWorkspaceStatsService } from 'vs/workbench/contrib/stats/common/workspaceStats';
|
||||
|
||||
export const enum ExperimentState {
|
||||
|
||||
@@ -42,7 +42,7 @@ import { IExperimentService, ExperimentActionType, ExperimentState } from 'vs/wo
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { extname } from 'vs/base/common/resources';
|
||||
import { IExeBasedExtensionTip, IProductService } from 'vs/platform/product/common/product';
|
||||
import { IExeBasedExtensionTip, IProductService } from 'vs/platform/product/common/productService';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry'; // {{SQL CARBON EDIT}}
|
||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys'; // {{SQL CARBON EDIT}}
|
||||
|
||||
@@ -20,7 +20,7 @@ import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/brow
|
||||
import {
|
||||
OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowPopularExtensionsAction,
|
||||
ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, ShowBuiltInExtensionsAction, UpdateAllAction,
|
||||
EnableAllAction, EnableAllWorkpsaceAction, DisableAllAction, DisableAllWorkpsaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, ShowAzureExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ConfigureRecommendedExtensionsCommandsContributor, OpenExtensionsFolderAction, InstallVSIXAction, ReinstallAction, InstallSpecificVersionOfExtensionAction
|
||||
EnableAllAction, EnableAllWorkpsaceAction, DisableAllAction, DisableAllWorkpsaceAction, CheckForUpdatesAction, ShowLanguageExtensionsAction, ShowAzureExtensionsAction, EnableAutoUpdateAction, DisableAutoUpdateAction, ConfigureRecommendedExtensionsCommandsContributor, InstallVSIXAction, ReinstallAction, InstallSpecificVersionOfExtensionAction
|
||||
} from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
|
||||
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet';
|
||||
@@ -43,7 +43,6 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { ExtensionDependencyChecker } from 'vs/workbench/contrib/extensions/browser/extensionsDependencyChecker';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { RemoteExtensionsInstaller } from 'vs/workbench/contrib/extensions/browser/remoteExtensionsInstaller';
|
||||
import { ExtensionTipsService } from 'vs/workbench/contrib/extensions/browser/extensionTipsService';
|
||||
|
||||
@@ -351,7 +350,6 @@ const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(Workbench
|
||||
class ExtensionsContributions implements IWorkbenchContribution {
|
||||
|
||||
constructor(
|
||||
@IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
||||
@IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService
|
||||
) {
|
||||
|
||||
@@ -369,14 +367,7 @@ class ExtensionsContributions implements IWorkbenchContribution {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (workbenchEnvironmentService.extensionsPath) {
|
||||
const openExtensionsFolderActionDescriptor = new SyncActionDescriptor(OpenExtensionsFolderAction, OpenExtensionsFolderAction.ID, OpenExtensionsFolderAction.LABEL);
|
||||
actionRegistry.registerWorkbenchAction(openExtensionsFolderActionDescriptor, 'Extensions: Open Extensions Folder', ExtensionsLabel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Starting);
|
||||
|
||||
@@ -26,7 +26,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { Query } from 'vs/workbench/contrib/extensions/common/extensionQuery';
|
||||
import { IFileService, IFileContent } from 'vs/platform/files/common/files';
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
|
||||
@@ -45,7 +45,6 @@ import { PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/w
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
|
||||
@@ -59,7 +58,7 @@ import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil';
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
@@ -2073,13 +2072,13 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
|
||||
removeFrom = removeFrom.filter(x => x.toLowerCase() !== extensionIdLowerCase);
|
||||
|
||||
return this.jsonEditingService.write(workspaceConfigurationFile,
|
||||
{
|
||||
[{
|
||||
key: 'extensions',
|
||||
value: {
|
||||
recommendations: shouldRecommend ? insertInto : removeFrom,
|
||||
unwantedRecommendations: shouldRecommend ? removeFrom : insertInto
|
||||
}
|
||||
},
|
||||
}],
|
||||
true);
|
||||
});
|
||||
}
|
||||
@@ -2102,19 +2101,19 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
|
||||
if (removeFrom.some(e => e.toLowerCase() === extensionIdLowerCase)) {
|
||||
removeFrom = removeFrom.filter(x => x.toLowerCase() !== extensionIdLowerCase);
|
||||
removeFromPromise = this.jsonEditingService.write(extensionsFileResource,
|
||||
{
|
||||
[{
|
||||
key: shouldRecommend ? 'unwantedRecommendations' : 'recommendations',
|
||||
value: removeFrom
|
||||
},
|
||||
}],
|
||||
true);
|
||||
}
|
||||
|
||||
return removeFromPromise.then(() =>
|
||||
this.jsonEditingService.write(extensionsFileResource,
|
||||
{
|
||||
[{
|
||||
key: shouldRecommend ? 'recommendations' : 'unwantedRecommendations',
|
||||
value: insertInto
|
||||
},
|
||||
}],
|
||||
true)
|
||||
);
|
||||
});
|
||||
@@ -2139,7 +2138,7 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
|
||||
.then(content => {
|
||||
const workspaceRecommendations = <IExtensionsConfigContent>json.parse(content.value.toString())['extensions'];
|
||||
if (!workspaceRecommendations || !workspaceRecommendations.recommendations) {
|
||||
return this.jsonEditingService.write(workspaceConfigurationFile, { key: 'extensions', value: { recommendations: [] } }, true)
|
||||
return this.jsonEditingService.write(workspaceConfigurationFile, [{ key: 'extensions', value: { recommendations: [] } }], true)
|
||||
.then(() => this.fileService.readFile(workspaceConfigurationFile));
|
||||
}
|
||||
return content;
|
||||
@@ -2801,41 +2800,6 @@ export class EnableAllWorkpsaceAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
export class OpenExtensionsFolderAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.openExtensionsFolder';
|
||||
static LABEL = localize('openExtensionsFolder', "Open Extensions Folder");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IWindowsService private readonly windowsService: IWindowsService,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService
|
||||
) {
|
||||
super(id, label, undefined, true);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
if (this.environmentService.extensionsPath) {
|
||||
|
||||
const extensionsHome = URI.file(this.environmentService.extensionsPath);
|
||||
|
||||
return Promise.resolve(this.fileService.resolve(extensionsHome)).then(file => {
|
||||
let itemToShow: URI;
|
||||
if (file.children && file.children.length > 0) {
|
||||
itemToShow = file.children[0].resource;
|
||||
} else {
|
||||
itemToShow = extensionsHome;
|
||||
}
|
||||
|
||||
return this.windowsService.showItemInFolder(itemToShow);
|
||||
});
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
export class InstallVSIXAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.installVSIX';
|
||||
|
||||
@@ -44,7 +44,7 @@ import { IAction } from 'vs/base/common/actions';
|
||||
import { ExtensionType, ExtensionIdentifier, IExtensionDescription, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IExtensionManifest, ExtensionType, IExtension as IPlatformExtension, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { asDomUri } from 'vs/base/browser/dom';
|
||||
|
||||
import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator'; // {{SQL CARBON EDIT}}
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
margin: 0.15em;
|
||||
}
|
||||
|
||||
.monaco-action-bar .action-item .action-label.system-disable.icon {
|
||||
.monaco-action-bar .action-item .action-label.system-disable.codicon {
|
||||
opacity: 1;
|
||||
height: 18px;
|
||||
width: 10px;
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .extension > .details > .header-container > .header > .install-count > .octicon {
|
||||
font-size: 100%;
|
||||
font-size: 120%;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { randomPort } from 'vs/base/node/ports';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler';
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -22,6 +22,9 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler';
|
||||
import { registerAndGetAmdImageURL } from 'vs/base/common/amd';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { OpenExtensionsFolderAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { ExtensionsLabel } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
|
||||
// Singletons
|
||||
registerSingleton(IExtensionHostProfileService, ExtensionHostProfileService, true);
|
||||
@@ -57,6 +60,20 @@ const actionRegistry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExte
|
||||
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowRuntimeExtensionsAction, ShowRuntimeExtensionsAction.ID, ShowRuntimeExtensionsAction.LABEL), 'Show Running Extensions', localize('developer', "Developer"));
|
||||
|
||||
class ExtensionsContributions implements IWorkbenchContribution {
|
||||
|
||||
constructor(
|
||||
@IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
if (workbenchEnvironmentService.extensionsPath) {
|
||||
const openExtensionsFolderActionDescriptor = new SyncActionDescriptor(OpenExtensionsFolderAction, OpenExtensionsFolderAction.ID, OpenExtensionsFolderAction.LABEL);
|
||||
actionRegistry.registerWorkbenchAction(openExtensionsFolderActionDescriptor, 'Extensions: Open Extensions Folder', ExtensionsLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Starting);
|
||||
|
||||
// Register Commands
|
||||
|
||||
CommandsRegistry.registerCommand(DebugExtensionHostAction.ID, (accessor: ServicesAccessor) => {
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
export class OpenExtensionsFolderAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.openExtensionsFolder';
|
||||
static LABEL = localize('openExtensionsFolder', "Open Extensions Folder");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IElectronService private readonly electronService: IElectronService,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService
|
||||
) {
|
||||
super(id, label, undefined, true);
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
if (this.environmentService.extensionsPath) {
|
||||
const extensionsHome = URI.file(this.environmentService.extensionsPath);
|
||||
const file = await this.fileService.resolve(extensionsHome);
|
||||
|
||||
let itemToShow: URI;
|
||||
if (file.children && file.children.length > 0) {
|
||||
itemToShow = file.children[0].resource;
|
||||
} else {
|
||||
itemToShow = extensionsHome;
|
||||
}
|
||||
|
||||
if (itemToShow.scheme === Schemas.file) {
|
||||
return this.electronService.showItemInFolder(itemToShow.fsPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as os from 'os';
|
||||
import pkg from 'vs/platform/product/node/package';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -139,7 +139,7 @@ class ReportExtensionSlowAction extends Action {
|
||||
- Extension Name: \`${this.extension.name}\`
|
||||
- Extension Version: \`${this.extension.version}\`
|
||||
- OS Version: \`${osVersion}\`
|
||||
- VSCode version: \`${pkg.version}\`\n\n${message}`);
|
||||
- VSCode version: \`${product.version}\`\n\n${message}`);
|
||||
|
||||
const url = `${this.repoInfo.base}/${this.repoInfo.owner}/${this.repoInfo.repo}/issues/new/?body=${body}&title=${title}`;
|
||||
this._openerService.open(URI.parse(url));
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
import 'vs/css!./media/runtimeExtensionsEditor';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as os from 'os';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import pkg from 'vs/platform/product/node/package';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
@@ -523,7 +522,7 @@ export class ReportExtensionIssueAction extends Action {
|
||||
- Extension Name: \`${extension.description.name}\`
|
||||
- Extension Version: \`${extension.description.version}\`
|
||||
- OS Version: \`${osVersion}\`
|
||||
- VSCode version: \`${pkg.version}\`\n\n${message}`
|
||||
- VSCode version: \`${product.version}\`\n\n${message}`
|
||||
);
|
||||
|
||||
return `${baseUrl}${queryStringPrefix}body=${body}&title=${encodeURIComponent(title)}`;
|
||||
|
||||
@@ -41,7 +41,7 @@ import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedPr
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { ExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
@@ -51,7 +51,7 @@ import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
|
||||
const mockExtensionGallery: IGalleryExtension[] = [
|
||||
aGalleryExtension('MockExtension1', {
|
||||
|
||||
@@ -41,7 +41,7 @@ import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browse
|
||||
import { ExtensionIdentifier, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
|
||||
import { ExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
||||
|
||||
@@ -19,7 +19,7 @@ import { Button } from 'vs/base/browser/ui/button/button';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
|
||||
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
|
||||
export interface IFeedback {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { FeedbackDropdown, IFeedback, IFeedbackDelegate } from 'vs/workbench/contrib/feedback/browser/feedback';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IStatusbarService, StatusbarAlignment, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
@@ -10,11 +10,11 @@ import { revertLocalChangesCommand, acceptLocalChangesCommand, CONFLICT_RESOLUTI
|
||||
import { SyncActionDescriptor, MenuId, MenuRegistry, ILocalizedString } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { openWindowCommand, REVEAL_IN_OS_COMMAND_ID, COPY_PATH_COMMAND_ID, REVEAL_IN_EXPLORER_COMMAND_ID, OPEN_TO_SIDE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_COMMAND_ID, SAVE_FILE_LABEL, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL, SAVE_ALL_IN_GROUP_COMMAND_ID, OpenEditorsGroupContext, COMPARE_WITH_SAVED_COMMAND_ID, COMPARE_RESOURCE_COMMAND_ID, SELECT_FOR_COMPARE_COMMAND_ID, ResourceSelectedForCompareContext, REVEAL_IN_OS_LABEL, DirtyEditorContext, COMPARE_SELECTED_COMMAND_ID, REMOVE_ROOT_FOLDER_COMMAND_ID, REMOVE_ROOT_FOLDER_LABEL, SAVE_FILES_COMMAND_ID, COPY_RELATIVE_PATH_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_LABEL, newWindowCommand } from 'vs/workbench/contrib/files/browser/fileCommands';
|
||||
import { openWindowCommand, COPY_PATH_COMMAND_ID, REVEAL_IN_EXPLORER_COMMAND_ID, OPEN_TO_SIDE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_COMMAND_ID, SAVE_FILE_LABEL, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL, SAVE_ALL_IN_GROUP_COMMAND_ID, OpenEditorsGroupContext, COMPARE_WITH_SAVED_COMMAND_ID, COMPARE_RESOURCE_COMMAND_ID, SELECT_FOR_COMPARE_COMMAND_ID, ResourceSelectedForCompareContext, DirtyEditorContext, COMPARE_SELECTED_COMMAND_ID, REMOVE_ROOT_FOLDER_COMMAND_ID, REMOVE_ROOT_FOLDER_LABEL, SAVE_FILES_COMMAND_ID, COPY_RELATIVE_PATH_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_COMMAND_ID, SAVE_FILE_WITHOUT_FORMATTING_LABEL, newWindowCommand } from 'vs/workbench/contrib/files/browser/fileCommands';
|
||||
import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { isWindows, isMacintosh, isWeb } from 'vs/base/common/platform';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { FilesExplorerFocusCondition, ExplorerRootContext, ExplorerFolderContext, ExplorerResourceNotReadonlyContext, ExplorerResourceCut, IExplorerService, ExplorerResourceMoveableToTrash, ExplorerViewletVisibleContext } from 'vs/workbench/contrib/files/common/files';
|
||||
import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL } from 'vs/workbench/browser/actions/workspaceCommands';
|
||||
import { CLOSE_SAVED_EDITORS_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands';
|
||||
@@ -23,9 +23,9 @@ import { ResourceContextKey } from 'vs/workbench/common/resources';
|
||||
import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { SupportsWorkspacesContext, IsWebContext, RemoteFileDialogContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { SupportsWorkspacesContext, IsWebContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { OpenFileFolderAction, OpenLocalFileFolderCommand, OpenFileAction, OpenFolderAction, OpenLocalFileCommand, OpenLocalFolderCommand, OpenWorkspaceAction, SaveLocalFileCommand } from 'vs/workbench/browser/actions/workspaceActions';
|
||||
import { OpenFileFolderAction, OpenFileAction, OpenFolderAction, OpenWorkspaceAction } from 'vs/workbench/browser/actions/workspaceActions';
|
||||
import { ActiveEditorIsSaveableContext } from 'vs/workbench/common/editor';
|
||||
import { SidebarFocusContext } from 'vs/workbench/common/viewlet';
|
||||
import { registerAndGetAmdImageURL } from 'vs/base/common/amd';
|
||||
@@ -48,57 +48,17 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(CompareWithClipboardAc
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleAutoSaveAction, ToggleAutoSaveAction.ID, ToggleAutoSaveAction.LABEL), 'File: Toggle Auto Save', category.value);
|
||||
|
||||
|
||||
const fileCategory = nls.localize('file', "File");
|
||||
const workspacesCategory = nls.localize('workspaces', "Workspaces");
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory);
|
||||
|
||||
const fileCategory = nls.localize('file', "File");
|
||||
if (isMacintosh) {
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', fileCategory);
|
||||
if (!isWeb) {
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: OpenLocalFileFolderCommand.ID,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_O,
|
||||
when: RemoteFileDialogContext,
|
||||
description: { description: OpenLocalFileFolderCommand.LABEL, args: [] },
|
||||
handler: OpenLocalFileFolderCommand.handler()
|
||||
});
|
||||
}
|
||||
} else {
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', fileCategory);
|
||||
if (!isWeb) {
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: OpenLocalFileCommand.ID,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_O,
|
||||
when: RemoteFileDialogContext,
|
||||
description: { description: OpenLocalFileCommand.LABEL, args: [] },
|
||||
handler: OpenLocalFileCommand.handler()
|
||||
});
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: OpenLocalFolderCommand.ID,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O),
|
||||
when: RemoteFileDialogContext,
|
||||
description: { description: OpenLocalFolderCommand.LABEL, args: [] },
|
||||
handler: OpenLocalFolderCommand.handler()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!isWeb) {
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: SaveLocalFileCommand.ID,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_S,
|
||||
when: RemoteFileDialogContext,
|
||||
description: { description: SaveLocalFileCommand.LABEL, args: [] },
|
||||
handler: SaveLocalFileCommand.handler()
|
||||
});
|
||||
}
|
||||
|
||||
const workspacesCategory = nls.localize('workspaces', "Workspaces");
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory, SupportsWorkspacesContext);
|
||||
|
||||
// Commands
|
||||
CommandsRegistry.registerCommand('_files.windowOpen', openWindowCommand);
|
||||
CommandsRegistry.registerCommand('_files.newWindow', newWindowCommand);
|
||||
@@ -212,11 +172,9 @@ const copyRelativePathCommand = {
|
||||
// Editor Title Context Menu
|
||||
appendEditorTitleContextMenuItem(COPY_PATH_COMMAND_ID, copyPathCommand.title, ResourceContextKey.IsFileSystemResource, '1_cutcopypaste');
|
||||
appendEditorTitleContextMenuItem(COPY_RELATIVE_PATH_COMMAND_ID, copyRelativePathCommand.title, ResourceContextKey.IsFileSystemResource, '1_cutcopypaste');
|
||||
appendEditorTitleContextMenuItem(REVEAL_IN_OS_COMMAND_ID, REVEAL_IN_OS_LABEL, ResourceContextKey.Scheme.isEqualTo(Schemas.file));
|
||||
appendEditorTitleContextMenuItem(REVEAL_IN_OS_COMMAND_ID, REVEAL_IN_OS_LABEL, ContextKeyExpr.and(IsWebContext.toNegated(), ResourceContextKey.Scheme.isEqualTo(Schemas.userData)));
|
||||
appendEditorTitleContextMenuItem(REVEAL_IN_EXPLORER_COMMAND_ID, nls.localize('revealInSideBar', "Reveal in Side Bar"), ResourceContextKey.IsFileSystemResource);
|
||||
|
||||
function appendEditorTitleContextMenuItem(id: string, title: string, when: ContextKeyExpr | undefined, group?: string): void {
|
||||
export function appendEditorTitleContextMenuItem(id: string, title: string, when: ContextKeyExpr | undefined, group?: string): void {
|
||||
|
||||
// Menu
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, {
|
||||
@@ -252,7 +210,7 @@ function appendSaveConflictEditorTitleAction(id: string, title: string, iconLoca
|
||||
|
||||
// Menu registration - command palette
|
||||
|
||||
function appendToCommandPalette(id: string, title: ILocalizedString, category: ILocalizedString, when?: ContextKeyExpr): void {
|
||||
export function appendToCommandPalette(id: string, title: ILocalizedString, category: ILocalizedString, when?: ContextKeyExpr): void {
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: {
|
||||
id,
|
||||
@@ -272,7 +230,6 @@ appendToCommandPalette(SAVE_ALL_IN_GROUP_COMMAND_ID, { value: nls.localize('save
|
||||
appendToCommandPalette(SAVE_FILES_COMMAND_ID, { value: nls.localize('saveFiles', "Save All Files"), original: 'Save All Files' }, category);
|
||||
appendToCommandPalette(REVERT_FILE_COMMAND_ID, { value: nls.localize('revert', "Revert File"), original: 'Revert File' }, category);
|
||||
appendToCommandPalette(COMPARE_WITH_SAVED_COMMAND_ID, { value: nls.localize('compareActiveWithSaved', "Compare Active File with Saved"), original: 'Compare Active File with Saved' }, category);
|
||||
appendToCommandPalette(REVEAL_IN_OS_COMMAND_ID, { value: REVEAL_IN_OS_LABEL, original: isWindows ? 'Reveal in Explorer' : isMacintosh ? 'Reveal in Finder' : 'Open Containing Folder' }, category);
|
||||
appendToCommandPalette(SAVE_FILE_AS_COMMAND_ID, { value: SAVE_FILE_AS_LABEL, original: 'Save As...' }, category);
|
||||
appendToCommandPalette(CLOSE_EDITOR_COMMAND_ID, { value: nls.localize('closeEditor', "Close Editor"), original: 'Close Editor' }, { value: nls.localize('view', "View"), original: 'View' });
|
||||
appendToCommandPalette(NEW_FILE_COMMAND_ID, { value: NEW_FILE_LABEL, original: 'New File' }, category, WorkspaceFolderCountContext.notEqualsTo('0'));
|
||||
@@ -292,17 +249,6 @@ MenuRegistry.appendMenuItem(MenuId.OpenEditorsContext, {
|
||||
when: ResourceContextKey.IsFileSystemResource
|
||||
});
|
||||
|
||||
const revealInOsCommand = {
|
||||
id: REVEAL_IN_OS_COMMAND_ID,
|
||||
title: isWindows ? nls.localize('revealInWindows', "Reveal in Explorer") : isMacintosh ? nls.localize('revealInMac', "Reveal in Finder") : nls.localize('openContainer', "Open Containing Folder")
|
||||
};
|
||||
MenuRegistry.appendMenuItem(MenuId.OpenEditorsContext, {
|
||||
group: 'navigation',
|
||||
order: 20,
|
||||
command: revealInOsCommand,
|
||||
when: ResourceContextKey.IsFileSystemResource
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.OpenEditorsContext, {
|
||||
group: '1_cutcopypaste',
|
||||
order: 10,
|
||||
@@ -470,13 +416,6 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, {
|
||||
when: ContextKeyExpr.and(ExplorerFolderContext.toNegated(), ResourceContextKey.HasResource)
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.ExplorerContext, {
|
||||
group: 'navigation',
|
||||
order: 20,
|
||||
command: revealInOsCommand,
|
||||
when: ResourceContextKey.Scheme.isEqualTo(Schemas.file)
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.ExplorerContext, {
|
||||
group: '3_compare',
|
||||
order: 20,
|
||||
@@ -570,7 +509,7 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, {
|
||||
id: REMOVE_ROOT_FOLDER_COMMAND_ID,
|
||||
title: REMOVE_ROOT_FOLDER_LABEL
|
||||
},
|
||||
when: ContextKeyExpr.and(ExplorerRootContext, ExplorerFolderContext)
|
||||
when: ContextKeyExpr.and(ExplorerRootContext, ExplorerFolderContext, SupportsWorkspacesContext)
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.ExplorerContext, {
|
||||
@@ -714,8 +653,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
|
||||
id: OpenWorkspaceAction.ID,
|
||||
title: nls.localize({ key: 'miOpenWorkspace', comment: ['&& denotes a mnemonic'] }, "Open Wor&&kspace...")
|
||||
},
|
||||
order: 3,
|
||||
when: SupportsWorkspacesContext
|
||||
order: 3
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
|
||||
|
||||
@@ -26,9 +26,8 @@ import { IEditorViewState } from 'vs/editor/common/editorCommon';
|
||||
import { getCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';
|
||||
import { isWindows, isMacintosh } from 'vs/base/common/platform';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { sequence } from 'vs/base/common/async';
|
||||
import { getResourceForCommand, getMultiSelectedResources } from 'vs/workbench/contrib/files/browser/files';
|
||||
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
|
||||
import { getMultiSelectedEditorContexts } from 'vs/workbench/browser/parts/editor/editorCommands';
|
||||
@@ -50,8 +49,6 @@ import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/q
|
||||
|
||||
// Commands
|
||||
|
||||
export const REVEAL_IN_OS_COMMAND_ID = 'revealFileInOS';
|
||||
export const REVEAL_IN_OS_LABEL = isWindows ? nls.localize('revealInWindows', "Reveal in Explorer") : isMacintosh ? nls.localize('revealInMac', "Reveal in Finder") : nls.localize('openContainer', "Open Containing Folder");
|
||||
export const REVEAL_IN_EXPLORER_COMMAND_ID = 'revealInExplorer';
|
||||
export const REVERT_FILE_COMMAND_ID = 'workbench.action.files.revert';
|
||||
export const OPEN_TO_SIDE_COMMAND_ID = 'explorer.openToSide';
|
||||
@@ -437,44 +434,6 @@ CommandsRegistry.registerCommand({
|
||||
}
|
||||
});
|
||||
|
||||
function revealResourcesInOS(resources: URI[], windowsService: IWindowsService, notificationService: INotificationService, workspaceContextService: IWorkspaceContextService): void {
|
||||
if (resources.length) {
|
||||
sequence(resources.map(r => () => windowsService.showItemInFolder(r.scheme === Schemas.userData ? r.with({ scheme: Schemas.file }) : r)));
|
||||
} else if (workspaceContextService.getWorkspace().folders.length) {
|
||||
windowsService.showItemInFolder(workspaceContextService.getWorkspace().folders[0].uri);
|
||||
} else {
|
||||
notificationService.info(nls.localize('openFileToReveal', "Open a file first to reveal"));
|
||||
}
|
||||
}
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: REVEAL_IN_OS_COMMAND_ID,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: EditorContextKeys.focus.toNegated(),
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R,
|
||||
win: {
|
||||
primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_R
|
||||
},
|
||||
handler: (accessor: ServicesAccessor, resource: URI | object) => {
|
||||
const resources = getMultiSelectedResources(resource, accessor.get(IListService), accessor.get(IEditorService));
|
||||
revealResourcesInOS(resources, accessor.get(IWindowsService), accessor.get(INotificationService), accessor.get(IWorkspaceContextService));
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: undefined,
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_R),
|
||||
id: 'workbench.action.files.revealActiveFileInWindows',
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const activeInput = editorService.activeEditor;
|
||||
const resource = activeInput ? activeInput.getResource() : null;
|
||||
const resources = resource ? [resource] : [];
|
||||
revealResourcesInOS(resources, accessor.get(IWindowsService), accessor.get(INotificationService), accessor.get(IWorkspaceContextService));
|
||||
}
|
||||
});
|
||||
|
||||
async function resourcesToClipboard(resources: URI[], relative: boolean, clipboardService: IClipboardService, notificationService: INotificationService, labelService: ILabelService): Promise<void> {
|
||||
if (resources.length) {
|
||||
const lineDelimiter = isWindows ? '\r\n' : '\n';
|
||||
|
||||
@@ -381,13 +381,16 @@ export class OpenEditorsView extends ViewletPanel {
|
||||
private focusActiveEditor(): void {
|
||||
if (this.list.length && this.editorGroupService.activeGroup) {
|
||||
const index = this.getIndex(this.editorGroupService.activeGroup, this.editorGroupService.activeGroup.activeEditor);
|
||||
this.list.setFocus([index]);
|
||||
this.list.setSelection([index]);
|
||||
this.list.reveal(index);
|
||||
} else {
|
||||
this.list.setFocus([]);
|
||||
this.list.setSelection([]);
|
||||
if (index >= 0) {
|
||||
this.list.setFocus([index]);
|
||||
this.list.setSelection([index]);
|
||||
this.list.reveal(index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.list.setFocus([]);
|
||||
this.list.setSelection([]);
|
||||
}
|
||||
|
||||
private onConfigurationChange(event: IConfigurationChangeEvent): void {
|
||||
|
||||
@@ -111,7 +111,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
|
||||
|
||||
setPreferredEncoding(encoding: string): void {
|
||||
this.preferredEncoding = encoding;
|
||||
this.forceOpenAs = ForceOpenAs.Text; // encoding is a good hint to open the file as text
|
||||
this.setForceOpenAsText(); // encoding is a good hint to open the file as text
|
||||
}
|
||||
|
||||
getPreferredMode(): string | undefined {
|
||||
@@ -129,7 +129,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
|
||||
|
||||
setPreferredMode(mode: string): void {
|
||||
this.preferredMode = mode;
|
||||
this.forceOpenAs = ForceOpenAs.Text; // mode is a good hint to open the file as text
|
||||
this.setForceOpenAsText(); // mode is a good hint to open the file as text
|
||||
}
|
||||
|
||||
setForceOpenAsText(): void {
|
||||
@@ -165,21 +165,15 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
|
||||
}
|
||||
|
||||
getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string {
|
||||
let description: string;
|
||||
switch (verbosity) {
|
||||
case Verbosity.SHORT:
|
||||
description = this.shortDescription;
|
||||
break;
|
||||
return this.shortDescription;
|
||||
case Verbosity.LONG:
|
||||
description = this.longDescription;
|
||||
break;
|
||||
return this.longDescription;
|
||||
case Verbosity.MEDIUM:
|
||||
default:
|
||||
description = this.mediumDescription;
|
||||
break;
|
||||
return this.mediumDescription;
|
||||
}
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
@memoize
|
||||
@@ -198,24 +192,16 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput {
|
||||
}
|
||||
|
||||
getTitle(verbosity: Verbosity): string {
|
||||
let title: string;
|
||||
switch (verbosity) {
|
||||
case Verbosity.SHORT:
|
||||
title = this.shortTitle;
|
||||
// already decorated by getName()
|
||||
break;
|
||||
return this.shortTitle;
|
||||
default:
|
||||
case Verbosity.MEDIUM:
|
||||
title = this.mediumTitle;
|
||||
title = this.decorateLabel(title);
|
||||
break;
|
||||
return this.decorateLabel(this.mediumTitle);
|
||||
case Verbosity.LONG:
|
||||
title = this.longTitle;
|
||||
title = this.decorateLabel(title);
|
||||
break;
|
||||
return this.decorateLabel(this.longTitle);
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
private decorateLabel(label: string): string {
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { isWindows, isMacintosh } from 'vs/base/common/platform';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { getMultiSelectedResources } from 'vs/workbench/contrib/files/browser/files';
|
||||
import { IListService } from 'vs/platform/list/browser/listService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { revealResourcesInOS } from 'vs/workbench/contrib/files/electron-browser/fileCommands';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { ResourceContextKey } from 'vs/workbench/common/resources';
|
||||
import { appendToCommandPalette, appendEditorTitleContextMenuItem } from 'vs/workbench/contrib/files/browser/fileActions.contribution';
|
||||
|
||||
const REVEAL_IN_OS_COMMAND_ID = 'revealFileInOS';
|
||||
const REVEAL_IN_OS_LABEL = isWindows ? nls.localize('revealInWindows', "Reveal in Explorer") : isMacintosh ? nls.localize('revealInMac', "Reveal in Finder") : nls.localize('openContainer', "Open Containing Folder");
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: REVEAL_IN_OS_COMMAND_ID,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: EditorContextKeys.focus.toNegated(),
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_R,
|
||||
win: {
|
||||
primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_R
|
||||
},
|
||||
handler: (accessor: ServicesAccessor, resource: URI | object) => {
|
||||
const resources = getMultiSelectedResources(resource, accessor.get(IListService), accessor.get(IEditorService));
|
||||
revealResourcesInOS(resources, accessor.get(IElectronService), accessor.get(INotificationService), accessor.get(IWorkspaceContextService));
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
when: undefined,
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_R),
|
||||
id: 'workbench.action.files.revealActiveFileInWindows',
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const activeInput = editorService.activeEditor;
|
||||
const resource = activeInput ? activeInput.getResource() : null;
|
||||
const resources = resource ? [resource] : [];
|
||||
revealResourcesInOS(resources, accessor.get(IElectronService), accessor.get(INotificationService), accessor.get(IWorkspaceContextService));
|
||||
}
|
||||
});
|
||||
|
||||
appendEditorTitleContextMenuItem(REVEAL_IN_OS_COMMAND_ID, REVEAL_IN_OS_LABEL, ResourceContextKey.Scheme.isEqualTo(Schemas.file));
|
||||
|
||||
// Menu registration - open editors
|
||||
|
||||
const revealInOsCommand = {
|
||||
id: REVEAL_IN_OS_COMMAND_ID,
|
||||
title: isWindows ? nls.localize('revealInWindows', "Reveal in Explorer") : isMacintosh ? nls.localize('revealInMac', "Reveal in Finder") : nls.localize('openContainer', "Open Containing Folder")
|
||||
};
|
||||
MenuRegistry.appendMenuItem(MenuId.OpenEditorsContext, {
|
||||
group: 'navigation',
|
||||
order: 20,
|
||||
command: revealInOsCommand,
|
||||
when: ResourceContextKey.IsFileSystemResource
|
||||
});
|
||||
|
||||
// Menu registration - explorer
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.ExplorerContext, {
|
||||
group: 'navigation',
|
||||
order: 20,
|
||||
command: revealInOsCommand,
|
||||
when: ResourceContextKey.Scheme.isEqualTo(Schemas.file)
|
||||
});
|
||||
|
||||
// Command Palette
|
||||
|
||||
const category = { value: nls.localize('filesCategory', "File"), original: 'File' };
|
||||
appendToCommandPalette(REVEAL_IN_OS_COMMAND_ID, { value: REVEAL_IN_OS_LABEL, original: isWindows ? 'Reveal in Explorer' : isMacintosh ? 'Reveal in Finder' : 'Open Containing Folder' }, category);
|
||||
@@ -0,0 +1,31 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { sequence } from 'vs/base/common/async';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
|
||||
// Commands
|
||||
|
||||
export function revealResourcesInOS(resources: URI[], electronService: IElectronService, notificationService: INotificationService, workspaceContextService: IWorkspaceContextService): void {
|
||||
if (resources.length) {
|
||||
sequence(resources.map(r => async () => {
|
||||
if (r.scheme === Schemas.file) {
|
||||
electronService.showItemInFolder(r.fsPath);
|
||||
}
|
||||
}));
|
||||
} else if (workspaceContextService.getWorkspace().folders.length) {
|
||||
const uri = workspaceContextService.getWorkspace().folders[0].uri;
|
||||
if (uri.scheme === Schemas.file) {
|
||||
electronService.showItemInFolder(uri.fsPath);
|
||||
}
|
||||
} else {
|
||||
notificationService.info(nls.localize('openFileToReveal', "Open a file first to reveal"));
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import * as nls from 'vs/nls';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { SyncActionDescriptor, ICommandAction, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
|
||||
import { ReportPerformanceIssueUsingReporterAction, OpenProcessExplorer } from 'vs/workbench/contrib/issue/electron-browser/issueActions';
|
||||
|
||||
@@ -80,7 +80,7 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo
|
||||
[{
|
||||
label: updateAndRestart ? localize('yes', "Yes") : localize('restart now', "Restart Now"),
|
||||
run: () => {
|
||||
const updatePromise = updateAndRestart ? this.jsonEditingService.write(this.environmentService.localeResource, { key: 'locale', value: locale }, true) : Promise.resolve(undefined);
|
||||
const updatePromise = updateAndRestart ? this.jsonEditingService.write(this.environmentService.localeResource, [{ key: 'locale', value: locale }], true) : Promise.resolve(undefined);
|
||||
updatePromise.then(() => this.windowsService.relaunch({}), e => this.notificationService.error(e));
|
||||
}
|
||||
}],
|
||||
|
||||
@@ -65,7 +65,7 @@ export class ConfigureLocaleAction extends Action {
|
||||
}
|
||||
|
||||
if (selectedLanguage) {
|
||||
await this.jsonEditingService.write(this.environmentService.localeResource, { key: 'locale', value: selectedLanguage.label }, true);
|
||||
await this.jsonEditingService.write(this.environmentService.localeResource, [{ key: 'locale', value: selectedLanguage.label }], true);
|
||||
const restart = await this.dialogService.confirm({
|
||||
type: 'info',
|
||||
message: localize('relaunchDisplayLanguageMessage', "A restart is required for the change in display language to take effect."),
|
||||
|
||||
@@ -8,7 +8,7 @@ import { join } from 'vs/base/common/path';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { SetLogLevelAction, OpenLogsFolderAction, OpenWindowSessionLogFileAction } from 'vs/workbench/contrib/logs/common/logsActions';
|
||||
import { SetLogLevelAction, OpenWindowSessionLogFileAction } from 'vs/workbench/contrib/logs/common/logsActions';
|
||||
import * as Constants from 'vs/workbench/contrib/logs/common/logConstants';
|
||||
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
@@ -64,10 +64,6 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution {
|
||||
};
|
||||
registerTelemetryChannel(this.logService.getLevel());
|
||||
this.logService.onDidChangeLogLevel(registerTelemetryChannel);
|
||||
|
||||
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions);
|
||||
const devCategory = nls.localize('developer', "Developer");
|
||||
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenLogsFolderAction, OpenLogsFolderAction.ID, OpenLogsFolderAction.LABEL), 'Developer: Open Logs Folder', devCategory);
|
||||
}
|
||||
|
||||
private async registerLogChannel(id: string, label: string, file: URI): Promise<void> {
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { ILogService, LogLevel, DEFAULT_LOG_LEVEL } from 'vs/platform/log/common/log';
|
||||
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -16,23 +13,6 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
|
||||
import { dirname, basename, isEqual } from 'vs/base/common/resources';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
export class OpenLogsFolderAction extends Action {
|
||||
|
||||
static ID = 'workbench.action.openLogsFolder';
|
||||
static LABEL = nls.localize('openLogsFolder', "Open Logs Folder");
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@IWindowsService private readonly windowsService: IWindowsService,
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
return this.windowsService.showItemInFolder(URI.file(join(this.environmentService.logsPath, 'main.log')));
|
||||
}
|
||||
}
|
||||
|
||||
export class SetLogLevelAction extends Action {
|
||||
|
||||
static ID = 'workbench.action.setLogLevel';
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { OpenLogsFolderAction } from 'vs/workbench/contrib/logs/electron-browser/logsActions';
|
||||
|
||||
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions);
|
||||
const devCategory = nls.localize('developer', "Developer");
|
||||
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenLogsFolderAction, OpenLogsFolderAction.ID, OpenLogsFolderAction.LABEL), 'Developer: Open Logs Folder', devCategory);
|
||||
@@ -0,0 +1,28 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
|
||||
export class OpenLogsFolderAction extends Action {
|
||||
|
||||
static ID = 'workbench.action.openLogsFolder';
|
||||
static LABEL = nls.localize('openLogsFolder', "Open Logs Folder");
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@IElectronService private readonly electronService: IElectronService,
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
return this.electronService.showItemInFolder(URI.file(join(this.environmentService.logsPath, 'main.log')).fsPath);
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
|
||||
this.rangeHighlightDecorations = this._register(this.instantiationService.createInstance(RangeHighlightDecorations));
|
||||
|
||||
// actions
|
||||
this.collapseAllAction = this._register(new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action collapse-all', true, async () => this.collapseAll()));
|
||||
this.collapseAllAction = this._register(new Action('vs.tree.collapse', localize('collapseAll', "Collapse All"), 'monaco-tree-action codicon-collapse-all', true, async () => this.collapseAll()));
|
||||
this.filterAction = this._register(this.instantiationService.createInstance(MarkersFilterAction, { filterText: this.panelState['filter'] || '', filterHistory: this.panelState['filterHistory'] || [], useFilesExclude: !!this.panelState['useFilesExclude'] }));
|
||||
}
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem {
|
||||
|
||||
private createFilesExcludeCheckbox(container: HTMLElement): void {
|
||||
const filesExcludeFilter = this._register(new Checkbox({
|
||||
actionClassName: 'markers-panel-filter-filesExclude',
|
||||
actionClassName: 'codicon codicon-exclude',
|
||||
title: this.action.useFilesExclude ? Messages.MARKERS_PANEL_ACTION_TOOLTIP_DO_NOT_USE_FILES_EXCLUDE : Messages.MARKERS_PANEL_ACTION_TOOLTIP_USE_FILES_EXCLUDE,
|
||||
isChecked: this.action.useFilesExclude
|
||||
}));
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.41155 1L6.58845 1.00002L6.10395 3.42254L4.04837 2.05215L2.05214 4.04839L3.42252 6.10396L1 6.58846V9.41156L3.42253 9.89606L2.05214 11.9516L4.04838 13.9479L6.10395 12.5775L6.58845 15H8.67134C8.31745 14.7136 8.00787 14.3747 7.75447 13.9951H7.41231L7.12404 12.5537C7.09769 12.4439 7.07537 12.3325 7.05724 12.2197L6.94068 11.6369L6.17738 11.3207L4.17643 12.6547L3.34531 11.8236L4.67929 9.82263L4.36309 9.05932L2.00495 8.5877V7.41232L4.36309 6.94069L4.67928 6.17739L3.34531 4.17643L4.17642 3.34532L6.17737 4.67928L6.94069 4.36313L7.41231 2.00497L8.58769 2.00496L9.05931 4.36311L9.82263 4.67927L11.8236 3.3453L12.6547 4.17642L11.3207 6.17737L11.6369 6.94069L12.2194 7.05719C12.3324 7.07535 12.444 7.09771 12.554 7.12411L13.995 7.41232V7.75447C14.3747 8.00786 14.7136 8.31745 15 8.67133V6.58846L12.5775 6.10396L13.9479 4.04837L11.9516 2.05214L9.89605 3.42252L9.41155 1ZM8 6C8.8592 6 9.59185 6.54179 9.87496 7.30237C9.55558 7.42609 9.25385 7.58522 8.97457 7.77493C8.87247 7.33103 8.47489 7 8 7C7.44772 7 7 7.44772 7 8C7 8.47489 7.33103 8.87247 7.77493 8.97457C7.58522 9.25385 7.42609 9.55558 7.30237 9.87496C6.54179 9.59185 6 8.8592 6 8C6 6.89543 6.89543 6 8 6ZM9.27944 8.79462C9.90534 8.28088 10.69 8.00006 11.4998 8C11.9594 7.99997 12.4145 8.09047 12.8392 8.26634C13.2639 8.44221 13.6497 8.7 13.9748 9.025C14.5474 9.59754 14.9037 10.3509 14.9831 11.1568C15.0625 11.9626 14.8601 12.771 14.4103 13.4443C13.9604 14.1176 13.2911 14.6141 12.5162 14.8492C11.7413 15.0843 10.9089 15.0435 10.1608 14.7337C9.41269 14.4238 8.79514 13.8642 8.41339 13.1501C8.03163 12.436 7.90929 11.6116 8.06721 10.8174C8.22513 10.0232 8.65354 9.30836 9.27944 8.79462ZM8.99975 11V12H13.9998V11H8.99975Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.41155 1L6.58845 1.00002L6.10395 3.42254L4.04837 2.05215L2.05214 4.04839L3.42252 6.10396L1 6.58846V9.41156L3.42253 9.89606L2.05214 11.9516L4.04838 13.9479L6.10395 12.5775L6.58845 15H8.67134C8.31745 14.7136 8.00787 14.3747 7.75447 13.9951H7.41231L7.12404 12.5537C7.09769 12.4439 7.07537 12.3325 7.05724 12.2197L6.94068 11.6369L6.17738 11.3207L4.17643 12.6547L3.34531 11.8236L4.67929 9.82263L4.36309 9.05932L2.00495 8.5877V7.41232L4.36309 6.94069L4.67928 6.17739L3.34531 4.17643L4.17642 3.34532L6.17737 4.67928L6.94069 4.36313L7.41231 2.00497L8.58769 2.00496L9.05931 4.36311L9.82263 4.67927L11.8236 3.3453L12.6547 4.17642L11.3207 6.17737L11.6369 6.94069L12.2194 7.05719C12.3324 7.07535 12.444 7.09771 12.554 7.12411L13.995 7.41232V7.75447C14.3747 8.00786 14.7136 8.31745 15 8.67133V6.58846L12.5775 6.10396L13.9479 4.04837L11.9516 2.05214L9.89605 3.42252L9.41155 1ZM8 6C8.8592 6 9.59185 6.54179 9.87496 7.30237C9.55558 7.42609 9.25385 7.58522 8.97457 7.77493C8.87247 7.33103 8.47489 7 8 7C7.44772 7 7 7.44772 7 8C7 8.47489 7.33103 8.87247 7.77493 8.97457C7.58522 9.25385 7.42609 9.55558 7.30237 9.87496C6.54179 9.59185 6 8.8592 6 8C6 6.89543 6.89543 6 8 6ZM9.27944 8.79462C9.90534 8.28088 10.69 8.00006 11.4998 8C11.9594 7.99997 12.4145 8.09047 12.8392 8.26634C13.2639 8.44221 13.6497 8.7 13.9748 9.025C14.5474 9.59754 14.9037 10.3509 14.9831 11.1568C15.0625 11.9626 14.8601 12.771 14.4103 13.4443C13.9604 14.1176 13.2911 14.6141 12.5162 14.8492C11.7413 15.0843 10.9089 15.0435 10.1608 14.7337C9.41269 14.4238 8.79514 13.8642 8.41339 13.1501C8.03163 12.436 7.90929 11.6116 8.06721 10.8174C8.22513 10.0232 8.65354 9.30836 9.27944 8.79462ZM8.99975 11V12H13.9998V11H8.99975Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.41155 1L6.58845 1.00002L6.10395 3.42254L4.04837 2.05215L2.05214 4.04839L3.42252 6.10396L1 6.58846V9.41156L3.42253 9.89606L2.05214 11.9516L4.04838 13.9479L6.10395 12.5775L6.58845 15H8.67134C8.31745 14.7136 8.00787 14.3747 7.75447 13.9951H7.41231L7.12404 12.5537C7.09769 12.4439 7.07537 12.3325 7.05724 12.2197L6.94068 11.6369L6.17738 11.3207L4.17643 12.6547L3.34531 11.8236L4.67929 9.82263L4.36309 9.05932L2.00495 8.5877V7.41232L4.36309 6.94069L4.67928 6.17739L3.34531 4.17643L4.17642 3.34532L6.17737 4.67928L6.94069 4.36313L7.41231 2.00497L8.58769 2.00496L9.05931 4.36311L9.82263 4.67927L11.8236 3.3453L12.6547 4.17642L11.3207 6.17737L11.6369 6.94069L12.2194 7.05719C12.3324 7.07535 12.444 7.09771 12.554 7.12411L13.995 7.41232V7.75447C14.3747 8.00786 14.7136 8.31745 15 8.67133V6.58846L12.5775 6.10396L13.9479 4.04837L11.9516 2.05214L9.89605 3.42252L9.41155 1ZM8 6C8.8592 6 9.59185 6.54179 9.87496 7.30237C9.55558 7.42609 9.25385 7.58522 8.97457 7.77493C8.87247 7.33103 8.47489 7 8 7C7.44772 7 7 7.44772 7 8C7 8.47489 7.33103 8.87247 7.77493 8.97457C7.58522 9.25385 7.42609 9.55558 7.30237 9.87496C6.54179 9.59185 6 8.8592 6 8C6 6.89543 6.89543 6 8 6ZM9.27944 8.79462C9.90534 8.28088 10.69 8.00006 11.4998 8C11.9594 7.99997 12.4145 8.09047 12.8392 8.26634C13.2639 8.44221 13.6497 8.7 13.9748 9.025C14.5474 9.59754 14.9037 10.3509 14.9831 11.1568C15.0625 11.9626 14.8601 12.771 14.4103 13.4443C13.9604 14.1176 13.2911 14.6141 12.5162 14.8492C11.7413 15.0843 10.9089 15.0435 10.1608 14.7337C9.41269 14.4238 8.79514 13.8642 8.41339 13.1501C8.03163 12.436 7.90929 11.6116 8.06721 10.8174C8.22513 10.0232 8.65354 9.30836 9.27944 8.79462ZM8.99975 11V12H13.9998V11H8.99975Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -56,19 +56,6 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vs .markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-filesExclude {
|
||||
background: url('exclude-settings-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-filesExclude,
|
||||
.hc-black .markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-filesExclude {
|
||||
background: url('exclude-settings-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.hc-black .markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-filesExclude {
|
||||
background: url('exclude-settings-hc.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.markers-panel .markers-panel-container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="#C5C5C5"/>
|
||||
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="#C5C5C5"/>
|
||||
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="#C5C5C5"/>
|
||||
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="#C5C5C5"/>
|
||||
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 484 B |
@@ -1,7 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="white"/>
|
||||
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="white"/>
|
||||
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="white"/>
|
||||
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="white"/>
|
||||
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 474 B |
@@ -1,7 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="#424242"/>
|
||||
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="#424242"/>
|
||||
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="#424242"/>
|
||||
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="#424242"/>
|
||||
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 484 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 5V7H5V5C5 3.34315 6.34315 2 8 2C9.65685 2 11 3.34315 11 5ZM4 7V5C4 2.79086 5.79086 1 8 1C10.2091 1 12 2.79086 12 5V7H13L14 8V14L13 15H3L2 14V8L3 7H4ZM3 14V8H4H5H11H12H13V14H3Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 350 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 5V7H5V5C5 3.34315 6.34315 2 8 2C9.65685 2 11 3.34315 11 5ZM4 7V5C4 2.79086 5.79086 1 8 1C10.2091 1 12 2.79086 12 5V7H13L14 8V14L13 15H3L2 14V8L3 7H4ZM3 14V8H4H5H11H12H13V14H3Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 348 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 5V7H5V5C5 3.34315 6.34315 2 8 2C9.65685 2 11 3.34315 11 5ZM4 7V5C4 2.79086 5.79086 1 8 1C10.2091 1 12 2.79086 12 5V7H13L14 8V14L13 15H3L2 14V8L3 7H4ZM3 14V8H4H5H11H12H13V14H3Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 350 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.06065 3.85356L5.91421 6L5.2071 5.29289L6.49999 4H3.5C3.10218 4 2.72064 4.15804 2.43934 4.43934C2.15804 4.72065 2 5.10218 2 5.5C2 5.89783 2.15804 6.27936 2.43934 6.56066C2.72064 6.84197 3.10218 7 3.5 7H4V8H3.5C2.83696 8 2.20107 7.73661 1.73223 7.26777C1.26339 6.79893 1 6.16305 1 5.5C1 4.83696 1.26339 4.20108 1.73223 3.73224C2.20107 3.2634 2.83696 3 3.5 3H6.49999L6.49999 3H6.49996L6 2.50004V2.50001L5.2071 1.70711L5.91421 1L8.06065 3.14645L8.06065 3.85356ZM5 6.50003L5.91421 7.41424L6 7.32845V14H14V7H10V3H9.06065V2.73227L8.32838 2H11.2L11.5 2.1L14.9 5.6L15 6V14.5L14.5 15H5.5L5 14.5V9.00003V6.50003ZM11 3V6H13.9032L11 3Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 796 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.06065 3.85356L5.91421 6L5.2071 5.29289L6.49999 4H3.5C3.10218 4 2.72064 4.15804 2.43934 4.43934C2.15804 4.72065 2 5.10218 2 5.5C2 5.89783 2.15804 6.27936 2.43934 6.56066C2.72064 6.84197 3.10218 7 3.5 7H4V8H3.5C2.83696 8 2.20107 7.73661 1.73223 7.26777C1.26339 6.79893 1 6.16305 1 5.5C1 4.83696 1.26339 4.20108 1.73223 3.73224C2.20107 3.2634 2.83696 3 3.5 3H6.49999L6.49999 3H6.49996L6 2.50004V2.50001L5.2071 1.70711L5.91421 1L8.06065 3.14645L8.06065 3.85356ZM5 6.50003L5.91421 7.41424L6 7.32845V14H14V7H10V3H9.06065V2.73227L8.32838 2H11.2L11.5 2.1L14.9 5.6L15 6V14.5L14.5 15H5.5L5 14.5V9.00003V6.50003ZM11 3V6H13.9032L11 3Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 794 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.06065 3.85356L5.91421 6L5.2071 5.29289L6.49999 4H3.5C3.10218 4 2.72064 4.15804 2.43934 4.43934C2.15804 4.72065 2 5.10218 2 5.5C2 5.89783 2.15804 6.27936 2.43934 6.56066C2.72064 6.84197 3.10218 7 3.5 7H4V8H3.5C2.83696 8 2.20107 7.73661 1.73223 7.26777C1.26339 6.79893 1 6.16305 1 5.5C1 4.83696 1.26339 4.20108 1.73223 3.73224C2.20107 3.2634 2.83696 3 3.5 3H6.49999L6.49999 3H6.49996L6 2.50004V2.50001L5.2071 1.70711L5.91421 1L8.06065 3.14645L8.06065 3.85356ZM5 6.50003L5.91421 7.41424L6 7.32845V14H14V7H10V3H9.06065V2.73227L8.32838 2H11.2L11.5 2.1L14.9 5.6L15 6V14.5L14.5 15H5.5L5 14.5V9.00003V6.50003ZM11 3V6H13.9032L11 3Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 796 B |
@@ -1,52 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-workbench .output-action.clear-output {
|
||||
background: url('clear-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .output-action.clear-output {
|
||||
background: url('clear-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .output-action.clear-output {
|
||||
background: url('clear-hc.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-workbench .output-action.output-scroll-lock {
|
||||
background: url('locked-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .output-action.output-scroll-lock {
|
||||
background: url('locked-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .output-action.output-scroll-lock {
|
||||
background: url('locked-hc.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-workbench .output-action.output-scroll-unlock {
|
||||
background: url('unlocked-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .output-action.output-scroll-unlock {
|
||||
background: url('unlocked-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .output-action.output-scroll-unlock {
|
||||
background: url('unlocked-hc.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-workbench .output-action.open-log-file {
|
||||
background: url('open-file-light.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .output-action.open-log-file {
|
||||
background: url('open-file-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .output-action.open-log-file {
|
||||
background: url('open-file-hc.svg') center center no-repeat;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 7H5V5C5 3.34315 6.34315 2 8 2C9.30622 2 10.4175 2.83481 10.8293 4H11.874C11.4299 2.27477 9.86384 1 8 1C5.79086 1 4 2.79086 4 5V7H3L2 8V14L3 15H13L14 14V8L13 7H12H11H10ZM3 8V14H13V8H12H11H5H4H3Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 368 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 7H5V5C5 3.34315 6.34315 2 8 2C9.30622 2 10.4175 2.83481 10.8293 4H11.874C11.4299 2.27477 9.86384 1 8 1C5.79086 1 4 2.79086 4 5V7H3L2 8V14L3 15H13L14 14V8L13 7H12H11H10ZM3 8V14H13V8H12H11H5H4H3Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 366 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 7H5V5C5 3.34315 6.34315 2 8 2C9.30622 2 10.4175 2.83481 10.8293 4H11.874C11.4299 2.27477 9.86384 1 8 1C5.79086 1 4 2.79086 4 5V7H3L2 8V14L3 15H13L14 14V8L13 7H12H11H10ZM3 8V14H13V8H12H11H5H4H3Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 368 B |
@@ -45,7 +45,7 @@ export class ClearOutputAction extends Action {
|
||||
id: string, label: string,
|
||||
@IOutputService private readonly outputService: IOutputService
|
||||
) {
|
||||
super(id, label, 'output-action clear-output');
|
||||
super(id, label, 'output-action codicon-clear-all');
|
||||
}
|
||||
|
||||
public run(): Promise<boolean> {
|
||||
@@ -67,7 +67,7 @@ export class ToggleOrSetOutputScrollLockAction extends Action {
|
||||
public static readonly LABEL = nls.localize({ key: 'toggleOutputScrollLock', comment: ['Turn on / off automatic output scrolling'] }, "Toggle Output Scroll Lock");
|
||||
|
||||
constructor(id: string, label: string, @IOutputService private readonly outputService: IOutputService) {
|
||||
super(id, label, 'output-action output-scroll-unlock');
|
||||
super(id, label, 'output-action codicon-unlock');
|
||||
this._register(this.outputService.onActiveOutputChannel(channel => {
|
||||
const activeChannel = this.outputService.getActiveChannel();
|
||||
if (activeChannel) {
|
||||
@@ -94,10 +94,10 @@ export class ToggleOrSetOutputScrollLockAction extends Action {
|
||||
|
||||
private setClassAndLabel(locked: boolean) {
|
||||
if (locked) {
|
||||
this.class = 'output-action output-scroll-lock';
|
||||
this.class = 'output-action codicon-lock';
|
||||
this.label = nls.localize('outputScrollOn', "Turn Auto Scrolling On");
|
||||
} else {
|
||||
this.class = 'output-action output-scroll-unlock';
|
||||
this.class = 'output-action codicon-unlock';
|
||||
this.label = nls.localize('outputScrollOff', "Turn Auto Scrolling Off");
|
||||
}
|
||||
}
|
||||
@@ -185,7 +185,7 @@ export class OpenLogOutputFile extends Action {
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||
) {
|
||||
super(OpenLogOutputFile.ID, OpenLogOutputFile.LABEL, 'output-action open-log-file');
|
||||
super(OpenLogOutputFile.ID, OpenLogOutputFile.LABEL, 'output-action codicon-go-to-file');
|
||||
this._register(this.outputService.onActiveOutputChannel(this.update, this));
|
||||
this.update();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/output';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
|
||||
@@ -20,8 +20,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { writeTransientState } from 'vs/workbench/contrib/codeEditor/browser/toggleWordWrap';
|
||||
import { mergeSort } from 'vs/base/common/arrays';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import pkg from 'vs/platform/product/node/package';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
|
||||
export class PerfviewContrib {
|
||||
|
||||
@@ -127,7 +126,7 @@ class PerfModelContentProvider implements ITextModelContentProvider {
|
||||
|
||||
private _addSummary(md: MarkdownBuilder, metrics: IStartupMetrics): void {
|
||||
md.heading(2, 'System Info');
|
||||
md.li(`${product.nameShort}: ${pkg.version} (${product.commit || '0000000'})`);
|
||||
md.li(`${product.nameShort}: ${product.version} (${product.commit || '0000000'})`);
|
||||
md.li(`OS: ${metrics.platform}(${metrics.release})`);
|
||||
if (metrics.cpus) {
|
||||
md.li(`CPUs: ${metrics.cpus.model}(${metrics.cpus.count} x ${metrics.cpus.speed})`);
|
||||
|
||||
@@ -10,7 +10,7 @@ import { localize } from 'vs/nls';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { PerfviewInput } from 'vs/workbench/contrib/performance/electron-browser/perfviewEditor';
|
||||
@@ -18,6 +18,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
|
||||
export class StartupProfiler implements IWorkbenchContribution {
|
||||
|
||||
@@ -29,7 +30,8 @@ export class StartupProfiler implements IWorkbenchContribution {
|
||||
@IClipboardService private readonly _clipboardService: IClipboardService,
|
||||
@ILifecycleService lifecycleService: ILifecycleService,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IOpenerService private readonly _openerService: IOpenerService
|
||||
@IOpenerService private readonly _openerService: IOpenerService,
|
||||
@IElectronService private readonly _electronService: IElectronService
|
||||
) {
|
||||
// wait for everything to be ready
|
||||
Promise.all([
|
||||
@@ -81,7 +83,7 @@ export class StartupProfiler implements IWorkbenchContribution {
|
||||
}).then(res => {
|
||||
if (res.confirmed) {
|
||||
Promise.all<any>([
|
||||
this._windowsService.showItemInFolder(URI.file(join(dir, files[0]))),
|
||||
this._electronService.showItemInFolder(URI.file(join(dir, files[0])).fsPath),
|
||||
this._createPerfIssue(files)
|
||||
]).then(() => {
|
||||
// keep window stable until restart is selected
|
||||
|
||||
@@ -10,7 +10,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ILifecycleService, StartupKind } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IUpdateService } from 'vs/platform/update/common/update';
|
||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
@@ -21,6 +21,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { didUseCachedData, ITimerService } from 'vs/workbench/services/timer/electron-browser/timerService';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { getEntries } from 'vs/base/common/performance';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
|
||||
export class StartupTimings implements IWorkbenchContribution {
|
||||
|
||||
@@ -34,6 +35,7 @@ export class StartupTimings implements IWorkbenchContribution {
|
||||
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
|
||||
@IUpdateService private readonly _updateService: IUpdateService,
|
||||
@IEnvironmentService private readonly _envService: IEnvironmentService,
|
||||
@IHostService private readonly _hostService: IHostService
|
||||
) {
|
||||
//
|
||||
this._report().catch(onUnexpectedError);
|
||||
@@ -91,7 +93,7 @@ export class StartupTimings implements IWorkbenchContribution {
|
||||
if (this._lifecycleService.startupKind !== StartupKind.NewWindow) {
|
||||
return false;
|
||||
}
|
||||
if (await this._windowsService.getWindowCount() !== 1) {
|
||||
if (await this._hostService.windowCount !== 1) {
|
||||
return false;
|
||||
}
|
||||
const activeViewlet = this._viewletService.getActiveViewlet();
|
||||
|
||||
@@ -24,7 +24,7 @@ import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { nullRange } from 'vs/workbench/services/preferences/common/preferencesModels';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
|
||||
export interface IEndpointDetails {
|
||||
|
||||
@@ -195,6 +195,11 @@ export const tocData: ITOCEntry = {
|
||||
id: 'application/telemetry',
|
||||
label: localize('telemetry', "Telemetry"),
|
||||
settings: ['telemetry.*']
|
||||
},
|
||||
{
|
||||
id: 'application/sync',
|
||||
label: localize('sync', "Sync"),
|
||||
settings: ['userConfiguration.*']
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -218,3 +223,5 @@ export const knownAcronyms = new Set<string>();
|
||||
export const knownTermMappings = new Map<string, string>();
|
||||
knownTermMappings.set('power shell', 'PowerShell');
|
||||
knownTermMappings.set('powershell', 'PowerShell');
|
||||
knownTermMappings.set('javascript', 'JavaScript');
|
||||
knownTermMappings.set('typescript', 'TypeScript');
|
||||
|
||||
@@ -171,7 +171,7 @@ export class WorkspaceChangeExtHostRelauncher extends Disposable implements IWor
|
||||
|
||||
if (environmentService.configuration.remoteAuthority) {
|
||||
windowService.reloadWindow(); // TODO@aeschli, workaround
|
||||
} else {
|
||||
} else if (isNative) {
|
||||
extensionService.restartExtensionHost();
|
||||
}
|
||||
}, 10));
|
||||
|
||||
@@ -38,6 +38,15 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { IProgress, IProgressStep, IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { ReconnectionWaitEvent, PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { ReloadWindowAction } from 'vs/workbench/browser/actions/windowActions';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
|
||||
interface HelpInformation {
|
||||
extensionDescription: IExtensionDescription;
|
||||
@@ -126,7 +135,7 @@ class HelpDataSource implements IAsyncDataSource<any, any> {
|
||||
}
|
||||
|
||||
getChildren(element: any) {
|
||||
if (element instanceof HelpModel) {
|
||||
if (element instanceof HelpModel && element.items) {
|
||||
return element.items;
|
||||
}
|
||||
|
||||
@@ -201,7 +210,7 @@ class IssueReporterItem implements IHelpItem {
|
||||
}
|
||||
|
||||
class HelpModel {
|
||||
items: IHelpItem[];
|
||||
items: IHelpItem[] | undefined;
|
||||
|
||||
constructor(
|
||||
viewModel: IViewModel,
|
||||
@@ -445,3 +454,189 @@ Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions
|
||||
'View: Show Remote Explorer',
|
||||
nls.localize('view', "View")
|
||||
);
|
||||
|
||||
|
||||
class ProgressReporter {
|
||||
private _currentProgress: IProgress<IProgressStep> | null = null;
|
||||
private lastReport: string | null = null;
|
||||
|
||||
constructor(currentProgress: IProgress<IProgressStep> | null) {
|
||||
this._currentProgress = currentProgress;
|
||||
}
|
||||
|
||||
set currentProgress(progress: IProgress<IProgressStep>) {
|
||||
this._currentProgress = progress;
|
||||
}
|
||||
|
||||
report(message?: string) {
|
||||
if (message) {
|
||||
this.lastReport = message;
|
||||
}
|
||||
|
||||
if (this.lastReport && this._currentProgress) {
|
||||
this._currentProgress.report({ message: this.lastReport });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
|
||||
constructor(
|
||||
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
|
||||
@IProgressService progressService: IProgressService,
|
||||
@IDialogService dialogService: IDialogService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
) {
|
||||
const connection = remoteAgentService.getConnection();
|
||||
if (connection) {
|
||||
let currentProgressPromiseResolve: (() => void) | null = null;
|
||||
let progressReporter: ProgressReporter | null = null;
|
||||
let lastLocation: ProgressLocation | null = null;
|
||||
let currentTimer: ReconnectionTimer | null = null;
|
||||
let reconnectWaitEvent: ReconnectionWaitEvent | null = null;
|
||||
let disposableListener: IDisposable | null = null;
|
||||
|
||||
function showProgress(location: ProgressLocation, buttons?: string[]) {
|
||||
if (currentProgressPromiseResolve) {
|
||||
currentProgressPromiseResolve();
|
||||
}
|
||||
|
||||
const promise = new Promise<void>((resolve) => currentProgressPromiseResolve = resolve);
|
||||
lastLocation = location;
|
||||
|
||||
if (location === ProgressLocation.Dialog) {
|
||||
// Show dialog
|
||||
progressService!.withProgress(
|
||||
{ location: ProgressLocation.Dialog, buttons },
|
||||
(progress) => { if (progressReporter) { progressReporter.currentProgress = progress; } return promise; },
|
||||
(choice?) => {
|
||||
// Handle choice from dialog
|
||||
if (choice === 0 && buttons && reconnectWaitEvent) {
|
||||
reconnectWaitEvent.skipWait();
|
||||
} else {
|
||||
showProgress(ProgressLocation.Notification, buttons);
|
||||
}
|
||||
|
||||
progressReporter!.report();
|
||||
});
|
||||
} else {
|
||||
// Show notification
|
||||
progressService!.withProgress(
|
||||
{ location: ProgressLocation.Notification, buttons },
|
||||
(progress) => { if (progressReporter) { progressReporter.currentProgress = progress; } return promise; },
|
||||
(choice?) => {
|
||||
// Handle choice from notification
|
||||
if (choice === 0 && buttons && reconnectWaitEvent) {
|
||||
reconnectWaitEvent.skipWait();
|
||||
} else {
|
||||
hideProgress();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function hideProgress() {
|
||||
if (currentProgressPromiseResolve) {
|
||||
currentProgressPromiseResolve();
|
||||
}
|
||||
|
||||
currentProgressPromiseResolve = null;
|
||||
}
|
||||
|
||||
connection.onDidStateChange((e) => {
|
||||
if (currentTimer) {
|
||||
currentTimer.dispose();
|
||||
currentTimer = null;
|
||||
}
|
||||
|
||||
if (disposableListener) {
|
||||
disposableListener.dispose();
|
||||
disposableListener = null;
|
||||
}
|
||||
switch (e.type) {
|
||||
case PersistentConnectionEventType.ConnectionLost:
|
||||
if (!currentProgressPromiseResolve) {
|
||||
progressReporter = new ProgressReporter(null);
|
||||
showProgress(ProgressLocation.Dialog, [nls.localize('reconnectNow', "Reconnect Now")]);
|
||||
}
|
||||
|
||||
progressReporter!.report(nls.localize('connectionLost', "Connection Lost"));
|
||||
break;
|
||||
case PersistentConnectionEventType.ReconnectionWait:
|
||||
hideProgress();
|
||||
reconnectWaitEvent = e;
|
||||
showProgress(lastLocation || ProgressLocation.Notification, [nls.localize('reconnectNow', "Reconnect Now")]);
|
||||
currentTimer = new ReconnectionTimer(progressReporter!, Date.now() + 1000 * e.durationSeconds);
|
||||
break;
|
||||
case PersistentConnectionEventType.ReconnectionRunning:
|
||||
hideProgress();
|
||||
showProgress(lastLocation || ProgressLocation.Notification);
|
||||
progressReporter!.report(nls.localize('reconnectionRunning', "Attempting to reconnect..."));
|
||||
|
||||
// Register to listen for quick input is opened
|
||||
disposableListener = contextKeyService.onDidChangeContext((contextKeyChangeEvent) => {
|
||||
const reconnectInteraction = new Set<string>(['inQuickOpen']);
|
||||
if (contextKeyChangeEvent.affectsSome(reconnectInteraction)) {
|
||||
// Need to move from dialog if being shown and user needs to type in a prompt
|
||||
if (lastLocation === ProgressLocation.Dialog && progressReporter !== null) {
|
||||
hideProgress();
|
||||
showProgress(ProgressLocation.Notification);
|
||||
progressReporter.report();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
case PersistentConnectionEventType.ReconnectionPermanentFailure:
|
||||
hideProgress();
|
||||
progressReporter = null;
|
||||
|
||||
dialogService.show(Severity.Error, nls.localize('reconnectionPermanentFailure', "Cannot reconnect. Please reload the window."), [nls.localize('reloadWindow', "Reload Window"), nls.localize('cancel', "Cancel")], { cancelId: 1 }).then(result => {
|
||||
// Reload the window
|
||||
if (result.choice === 0) {
|
||||
commandService.executeCommand(ReloadWindowAction.ID);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case PersistentConnectionEventType.ConnectionGain:
|
||||
hideProgress();
|
||||
progressReporter = null;
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ReconnectionTimer implements IDisposable {
|
||||
private readonly _progressReporter: ProgressReporter;
|
||||
private readonly _completionTime: number;
|
||||
private readonly _token: any;
|
||||
|
||||
constructor(progressReporter: ProgressReporter, completionTime: number) {
|
||||
this._progressReporter = progressReporter;
|
||||
this._completionTime = completionTime;
|
||||
this._token = setInterval(() => this._render(), 1000);
|
||||
this._render();
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
clearInterval(this._token);
|
||||
}
|
||||
|
||||
private _render() {
|
||||
const remainingTimeMs = this._completionTime - Date.now();
|
||||
if (remainingTimeMs < 0) {
|
||||
return;
|
||||
}
|
||||
const remainingTime = Math.ceil(remainingTimeMs / 1000);
|
||||
if (remainingTime === 1) {
|
||||
this._progressReporter.report(nls.localize('reconnectionWaitOne', "Attempting to reconnect in {0} second...", remainingTime));
|
||||
} else {
|
||||
this._progressReporter.report(nls.localize('reconnectionWaitMany', "Attempting to reconnect in {0} seconds...", remainingTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentConnectionStatusListener, LifecyclePhase.Eventually);
|
||||
|
||||
@@ -11,7 +11,7 @@ import { OperatingSystem, isWeb } from 'vs/base/common/platform';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IRemoteAgentService, RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { LogLevelSetterChannelClient } from 'vs/platform/log/common/logIpc';
|
||||
import { LoggerChannelClient } from 'vs/platform/log/common/logIpc';
|
||||
import { IOutputChannelRegistry, Extensions as OutputExt, } from 'vs/workbench/contrib/output/common/output';
|
||||
import { localize } from 'vs/nls';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
@@ -79,9 +79,9 @@ class RemoteChannelsContribution extends Disposable implements IWorkbenchContrib
|
||||
super();
|
||||
const connection = remoteAgentService.getConnection();
|
||||
if (connection) {
|
||||
const logLevelClient = new LogLevelSetterChannelClient(connection.getChannel('loglevel'));
|
||||
logLevelClient.setLevel(logService.getLevel());
|
||||
this._register(logService.onDidChangeLogLevel(level => logLevelClient.setLevel(level)));
|
||||
const loggerClient = new LoggerChannelClient(connection.getChannel('logger'));
|
||||
loggerClient.setLevel(logService.getLevel());
|
||||
this._register(logService.onDidChangeLogLevel(level => loggerClient.setLevel(level)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
import * as nls from 'vs/nls';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { STATUS_BAR_HOST_NAME_BACKGROUND, STATUS_BAR_HOST_NAME_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
|
||||
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { MenuId, IMenuService, MenuItemAction, IMenu, MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchContributionsExtensions } from 'vs/workbench/common/contributions';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
@@ -23,22 +24,20 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
||||
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc';
|
||||
import { DialogChannel } from 'vs/platform/dialogs/electron-browser/dialogIpc';
|
||||
import { DownloadServiceChannel } from 'vs/platform/download/common/downloadIpc';
|
||||
import { LogLevelSetterChannel } from 'vs/platform/log/common/logIpc';
|
||||
import { LoggerChannel } from 'vs/platform/log/common/logIpc';
|
||||
import { ipcRenderer as ipc } from 'electron';
|
||||
import { IDiagnosticInfoOptions, IRemoteDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IProgressService, IProgress, IProgressStep, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { PersistentConnectionEventType, ReconnectionWaitEvent } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { ReloadWindowAction } from 'vs/workbench/browser/actions/windowActions';
|
||||
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { RemoteConnectionState, Deprecated_RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { RemoteConnectionState, Deprecated_RemoteAuthorityContext, RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys';
|
||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||
import { OpenLocalFileFolderCommand, OpenLocalFileCommand, OpenLocalFolderCommand, SaveLocalFileCommand } from 'vs/workbench/services/dialogs/browser/remoteFileDialog';
|
||||
|
||||
const WINDOW_ACTIONS_COMMAND_ID = 'remote.showActions';
|
||||
const CLOSE_REMOTE_COMMAND_ID = 'remote.closeRemote';
|
||||
@@ -228,7 +227,7 @@ class RemoteChannelsContribution implements IWorkbenchContribution {
|
||||
if (connection) {
|
||||
connection.registerChannel('dialog', new DialogChannel(dialogService));
|
||||
connection.registerChannel('download', new DownloadServiceChannel(downloadService));
|
||||
connection.registerChannel('loglevel', new LogLevelSetterChannel(logService));
|
||||
connection.registerChannel('logger', new LoggerChannel(logService));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -261,29 +260,6 @@ class RemoteAgentDiagnosticListener implements IWorkbenchContribution {
|
||||
}
|
||||
}
|
||||
|
||||
class ProgressReporter {
|
||||
private _currentProgress: IProgress<IProgressStep> | null = null;
|
||||
private lastReport: string | null = null;
|
||||
|
||||
constructor(currentProgress: IProgress<IProgressStep> | null) {
|
||||
this._currentProgress = currentProgress;
|
||||
}
|
||||
|
||||
set currentProgress(progress: IProgress<IProgressStep>) {
|
||||
this._currentProgress = progress;
|
||||
}
|
||||
|
||||
report(message?: string) {
|
||||
if (message) {
|
||||
this.lastReport = message;
|
||||
}
|
||||
|
||||
if (this.lastReport && this._currentProgress) {
|
||||
this._currentProgress.report({ message: this.lastReport });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteExtensionHostEnvironmentUpdater implements IWorkbenchContribution {
|
||||
constructor(
|
||||
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
|
||||
@@ -304,165 +280,6 @@ class RemoteExtensionHostEnvironmentUpdater implements IWorkbenchContribution {
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteAgentConnectionStatusListener implements IWorkbenchContribution {
|
||||
constructor(
|
||||
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
|
||||
@IProgressService progressService: IProgressService,
|
||||
@IDialogService dialogService: IDialogService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
) {
|
||||
const connection = remoteAgentService.getConnection();
|
||||
if (connection) {
|
||||
let currentProgressPromiseResolve: (() => void) | null = null;
|
||||
let progressReporter: ProgressReporter | null = null;
|
||||
let lastLocation: ProgressLocation | null = null;
|
||||
let currentTimer: ReconnectionTimer | null = null;
|
||||
let reconnectWaitEvent: ReconnectionWaitEvent | null = null;
|
||||
let disposableListener: IDisposable | null = null;
|
||||
|
||||
function showProgress(location: ProgressLocation, buttons?: string[]) {
|
||||
if (currentProgressPromiseResolve) {
|
||||
currentProgressPromiseResolve();
|
||||
}
|
||||
|
||||
const promise = new Promise<void>((resolve) => currentProgressPromiseResolve = resolve);
|
||||
lastLocation = location;
|
||||
|
||||
if (location === ProgressLocation.Dialog) {
|
||||
// Show dialog
|
||||
progressService!.withProgress(
|
||||
{ location: ProgressLocation.Dialog, buttons },
|
||||
(progress) => { if (progressReporter) { progressReporter.currentProgress = progress; } return promise; },
|
||||
(choice?) => {
|
||||
// Handle choice from dialog
|
||||
if (choice === 0 && buttons && reconnectWaitEvent) {
|
||||
reconnectWaitEvent.skipWait();
|
||||
} else {
|
||||
showProgress(ProgressLocation.Notification, buttons);
|
||||
}
|
||||
|
||||
progressReporter!.report();
|
||||
});
|
||||
} else {
|
||||
// Show notification
|
||||
progressService!.withProgress(
|
||||
{ location: ProgressLocation.Notification, buttons },
|
||||
(progress) => { if (progressReporter) { progressReporter.currentProgress = progress; } return promise; },
|
||||
(choice?) => {
|
||||
// Handle choice from notification
|
||||
if (choice === 0 && buttons && reconnectWaitEvent) {
|
||||
reconnectWaitEvent.skipWait();
|
||||
} else {
|
||||
hideProgress();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function hideProgress() {
|
||||
if (currentProgressPromiseResolve) {
|
||||
currentProgressPromiseResolve();
|
||||
}
|
||||
|
||||
currentProgressPromiseResolve = null;
|
||||
}
|
||||
|
||||
connection.onDidStateChange((e) => {
|
||||
if (currentTimer) {
|
||||
currentTimer.dispose();
|
||||
currentTimer = null;
|
||||
}
|
||||
|
||||
if (disposableListener) {
|
||||
disposableListener.dispose();
|
||||
disposableListener = null;
|
||||
}
|
||||
switch (e.type) {
|
||||
case PersistentConnectionEventType.ConnectionLost:
|
||||
if (!currentProgressPromiseResolve) {
|
||||
progressReporter = new ProgressReporter(null);
|
||||
showProgress(ProgressLocation.Dialog, [nls.localize('reconnectNow', "Reconnect Now")]);
|
||||
}
|
||||
|
||||
progressReporter!.report(nls.localize('connectionLost', "Connection Lost"));
|
||||
break;
|
||||
case PersistentConnectionEventType.ReconnectionWait:
|
||||
hideProgress();
|
||||
reconnectWaitEvent = e;
|
||||
showProgress(lastLocation || ProgressLocation.Notification, [nls.localize('reconnectNow', "Reconnect Now")]);
|
||||
currentTimer = new ReconnectionTimer(progressReporter!, Date.now() + 1000 * e.durationSeconds);
|
||||
break;
|
||||
case PersistentConnectionEventType.ReconnectionRunning:
|
||||
hideProgress();
|
||||
showProgress(lastLocation || ProgressLocation.Notification);
|
||||
progressReporter!.report(nls.localize('reconnectionRunning', "Attempting to reconnect..."));
|
||||
|
||||
// Register to listen for quick input is opened
|
||||
disposableListener = contextKeyService.onDidChangeContext((contextKeyChangeEvent) => {
|
||||
const reconnectInteraction = new Set<string>(['inQuickOpen']);
|
||||
if (contextKeyChangeEvent.affectsSome(reconnectInteraction)) {
|
||||
// Need to move from dialog if being shown and user needs to type in a prompt
|
||||
if (lastLocation === ProgressLocation.Dialog && progressReporter !== null) {
|
||||
hideProgress();
|
||||
showProgress(ProgressLocation.Notification);
|
||||
progressReporter.report();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
case PersistentConnectionEventType.ReconnectionPermanentFailure:
|
||||
hideProgress();
|
||||
progressReporter = null;
|
||||
|
||||
dialogService.show(Severity.Error, nls.localize('reconnectionPermanentFailure', "Cannot reconnect. Please reload the window."), [nls.localize('reloadWindow', "Reload Window"), nls.localize('cancel', "Cancel")], { cancelId: 1 }).then(result => {
|
||||
// Reload the window
|
||||
if (result.choice === 0) {
|
||||
commandService.executeCommand(ReloadWindowAction.ID);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case PersistentConnectionEventType.ConnectionGain:
|
||||
hideProgress();
|
||||
progressReporter = null;
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ReconnectionTimer implements IDisposable {
|
||||
private readonly _progressReporter: ProgressReporter;
|
||||
private readonly _completionTime: number;
|
||||
private readonly _token: NodeJS.Timeout;
|
||||
|
||||
constructor(progressReporter: ProgressReporter, completionTime: number) {
|
||||
this._progressReporter = progressReporter;
|
||||
this._completionTime = completionTime;
|
||||
this._token = setInterval(() => this._render(), 1000);
|
||||
this._render();
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
clearInterval(this._token);
|
||||
}
|
||||
|
||||
private _render() {
|
||||
const remainingTimeMs = this._completionTime - Date.now();
|
||||
if (remainingTimeMs < 0) {
|
||||
return;
|
||||
}
|
||||
const remainingTime = Math.ceil(remainingTimeMs / 1000);
|
||||
if (remainingTime === 1) {
|
||||
this._progressReporter.report(nls.localize('reconnectionWaitOne', "Attempting to reconnect in {0} second...", remainingTime));
|
||||
} else {
|
||||
this._progressReporter.report(nls.localize('reconnectionWaitMany', "Attempting to reconnect in {0} seconds...", remainingTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteTelemetryEnablementUpdater extends Disposable implements IWorkbenchContribution {
|
||||
constructor(
|
||||
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
|
||||
@@ -523,7 +340,6 @@ class RemoteEmptyWorkbenchPresentation extends Disposable implements IWorkbenchC
|
||||
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchContributionsExtensions.Workbench);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteChannelsContribution, LifecyclePhase.Starting);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentDiagnosticListener, LifecyclePhase.Eventually);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteAgentConnectionStatusListener, LifecyclePhase.Eventually);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteExtensionHostEnvironmentUpdater, LifecyclePhase.Eventually);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteWindowActiveIndicator, LifecyclePhase.Starting);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RemoteTelemetryEnablementUpdater, LifecyclePhase.Ready);
|
||||
@@ -558,3 +374,40 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (isMacintosh) {
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: OpenLocalFileFolderCommand.ID,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_O,
|
||||
when: RemoteFileDialogContext,
|
||||
description: { description: OpenLocalFileFolderCommand.LABEL, args: [] },
|
||||
handler: OpenLocalFileFolderCommand.handler()
|
||||
});
|
||||
} else {
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: OpenLocalFileCommand.ID,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_O,
|
||||
when: RemoteFileDialogContext,
|
||||
description: { description: OpenLocalFileCommand.LABEL, args: [] },
|
||||
handler: OpenLocalFileCommand.handler()
|
||||
});
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: OpenLocalFolderCommand.ID,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O),
|
||||
when: RemoteFileDialogContext,
|
||||
description: { description: OpenLocalFolderCommand.LABEL, args: [] },
|
||||
handler: OpenLocalFolderCommand.handler()
|
||||
});
|
||||
}
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: SaveLocalFileCommand.ID,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_S,
|
||||
when: RemoteFileDialogContext,
|
||||
description: { description: SaveLocalFileCommand.LABEL, args: [] },
|
||||
handler: SaveLocalFileCommand.handler()
|
||||
});
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.search-view .search-widget .replace-container .monaco-action-bar .action-item .icon {
|
||||
.search-view .search-widget .replace-container .monaco-action-bar .action-item .codicon {
|
||||
background-repeat: no-repeat;
|
||||
width: 20px;
|
||||
height: 25px;
|
||||
|
||||
@@ -364,11 +364,12 @@ export class SearchWidget extends Widget {
|
||||
}
|
||||
}));
|
||||
|
||||
let controls = document.createElement('div');
|
||||
const controls = document.createElement('div');
|
||||
controls.className = 'controls';
|
||||
controls.style.display = 'block';
|
||||
controls.appendChild(this._preserveCase.domNode);
|
||||
replaceBox.appendChild(controls);
|
||||
this.replaceInput.paddingRight = this._preserveCase.width();
|
||||
|
||||
this._register(attachInputBoxStyler(this.replaceInput, this.themeService));
|
||||
this.onkeydown(this.replaceInput.inputElement, (keyboardEvent) => this.onReplaceInputKeyDown(keyboardEvent));
|
||||
|
||||
@@ -10,14 +10,13 @@ import { IWorkbenchContributionsRegistry, IWorkbenchContribution, Extensions as
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import pkg from 'vs/platform/product/node/package';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { ISurveyData } from 'vs/platform/product/common/product';
|
||||
import { ISurveyData, IProductService } from 'vs/platform/product/common/productService';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { Severity, INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { ITextFileService, StateChange } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { platform } from 'vs/base/common/process';
|
||||
|
||||
class LanguageSurvey {
|
||||
|
||||
@@ -28,7 +27,8 @@ class LanguageSurvey {
|
||||
telemetryService: ITelemetryService,
|
||||
modelService: IModelService,
|
||||
textFileService: ITextFileService,
|
||||
openerService: IOpenerService
|
||||
openerService: IOpenerService,
|
||||
productService: IProductService
|
||||
) {
|
||||
const SESSION_COUNT_KEY = `${data.surveyId}.sessionCount`;
|
||||
const LAST_SESSION_DATE_KEY = `${data.surveyId}.lastSessionDate`;
|
||||
@@ -82,7 +82,7 @@ class LanguageSurvey {
|
||||
storageService.store(IS_CANDIDATE_KEY, isCandidate, StorageScope.GLOBAL);
|
||||
|
||||
if (!isCandidate) {
|
||||
storageService.store(SKIP_VERSION_KEY, pkg.version, StorageScope.GLOBAL);
|
||||
storageService.store(SKIP_VERSION_KEY, productService.version, StorageScope.GLOBAL);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -97,9 +97,9 @@ class LanguageSurvey {
|
||||
run: () => {
|
||||
telemetryService.publicLog(`${data.surveyId}.survey/takeShortSurvey`);
|
||||
telemetryService.getTelemetryInfo().then(info => {
|
||||
openerService.open(URI.parse(`${data.surveyUrl}?o=${encodeURIComponent(process.platform)}&v=${encodeURIComponent(pkg.version)}&m=${encodeURIComponent(info.machineId)}`));
|
||||
openerService.open(URI.parse(`${data.surveyUrl}?o=${encodeURIComponent(platform)}&v=${encodeURIComponent(productService.version)}&m=${encodeURIComponent(info.machineId)}`));
|
||||
storageService.store(IS_CANDIDATE_KEY, false, StorageScope.GLOBAL);
|
||||
storageService.store(SKIP_VERSION_KEY, pkg.version, StorageScope.GLOBAL);
|
||||
storageService.store(SKIP_VERSION_KEY, productService.version, StorageScope.GLOBAL);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
@@ -114,7 +114,7 @@ class LanguageSurvey {
|
||||
run: () => {
|
||||
telemetryService.publicLog(`${data.surveyId}.survey/dontShowAgain`);
|
||||
storageService.store(IS_CANDIDATE_KEY, false, StorageScope.GLOBAL);
|
||||
storageService.store(SKIP_VERSION_KEY, pkg.version, StorageScope.GLOBAL);
|
||||
storageService.store(SKIP_VERSION_KEY, productService.version, StorageScope.GLOBAL);
|
||||
}
|
||||
}],
|
||||
{ sticky: true }
|
||||
@@ -130,15 +130,20 @@ class LanguageSurveysContribution implements IWorkbenchContribution {
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IModelService modelService: IModelService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IOpenerService openerService: IOpenerService
|
||||
@IOpenerService openerService: IOpenerService,
|
||||
@IProductService productService: IProductService
|
||||
) {
|
||||
product.surveys!
|
||||
if (!productService.surveys) {
|
||||
return;
|
||||
}
|
||||
|
||||
productService.surveys
|
||||
.filter(surveyData => surveyData.surveyId && surveyData.editCount && surveyData.languageId && surveyData.surveyUrl && surveyData.userProbability)
|
||||
.map(surveyData => new LanguageSurvey(surveyData, storageService, notificationService, telemetryService, modelService, textFileService, openerService));
|
||||
.map(surveyData => new LanguageSurvey(surveyData, storageService, notificationService, telemetryService, modelService, textFileService, openerService, productService));
|
||||
}
|
||||
}
|
||||
|
||||
if (language === 'en' && product.surveys && product.surveys.length) {
|
||||
if (language === 'en') {
|
||||
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
workbenchRegistry.registerWorkbenchContribution(LanguageSurveysContribution, LifecyclePhase.Restored);
|
||||
}
|
||||
@@ -9,12 +9,12 @@ import { IWorkbenchContributionsRegistry, IWorkbenchContribution, Extensions as
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import pkg from 'vs/platform/product/node/package';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { Severity, INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { platform } from 'vs/base/common/process';
|
||||
|
||||
const PROBABILITY = 0.15;
|
||||
const SESSION_COUNT_KEY = 'nps/sessionCount';
|
||||
@@ -28,8 +28,13 @@ class NPSContribution implements IWorkbenchContribution {
|
||||
@IStorageService storageService: IStorageService,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IOpenerService openerService: IOpenerService
|
||||
@IOpenerService openerService: IOpenerService,
|
||||
@IProductService productService: IProductService
|
||||
) {
|
||||
if (!productService.npsSurveyUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const skipVersion = storageService.get(SKIP_VERSION_KEY, StorageScope.GLOBAL, '');
|
||||
if (skipVersion) {
|
||||
return;
|
||||
@@ -56,7 +61,7 @@ class NPSContribution implements IWorkbenchContribution {
|
||||
storageService.store(IS_CANDIDATE_KEY, isCandidate, StorageScope.GLOBAL);
|
||||
|
||||
if (!isCandidate) {
|
||||
storageService.store(SKIP_VERSION_KEY, pkg.version, StorageScope.GLOBAL);
|
||||
storageService.store(SKIP_VERSION_KEY, productService.version, StorageScope.GLOBAL);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -67,9 +72,9 @@ class NPSContribution implements IWorkbenchContribution {
|
||||
label: nls.localize('takeSurvey', "Take Survey"),
|
||||
run: () => {
|
||||
telemetryService.getTelemetryInfo().then(info => {
|
||||
openerService.open(URI.parse(`${product.npsSurveyUrl}?o=${encodeURIComponent(process.platform)}&v=${encodeURIComponent(pkg.version)}&m=${encodeURIComponent(info.machineId)}`));
|
||||
openerService.open(URI.parse(`${productService.npsSurveyUrl}?o=${encodeURIComponent(platform)}&v=${encodeURIComponent(productService.version)}&m=${encodeURIComponent(info.machineId)}`));
|
||||
storageService.store(IS_CANDIDATE_KEY, false, StorageScope.GLOBAL);
|
||||
storageService.store(SKIP_VERSION_KEY, pkg.version, StorageScope.GLOBAL);
|
||||
storageService.store(SKIP_VERSION_KEY, productService.version, StorageScope.GLOBAL);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
@@ -79,7 +84,7 @@ class NPSContribution implements IWorkbenchContribution {
|
||||
label: nls.localize('neverAgain', "Don't Show Again"),
|
||||
run: () => {
|
||||
storageService.store(IS_CANDIDATE_KEY, false, StorageScope.GLOBAL);
|
||||
storageService.store(SKIP_VERSION_KEY, pkg.version, StorageScope.GLOBAL);
|
||||
storageService.store(SKIP_VERSION_KEY, productService.version, StorageScope.GLOBAL);
|
||||
}
|
||||
}],
|
||||
{ sticky: true }
|
||||
@@ -87,7 +92,7 @@ class NPSContribution implements IWorkbenchContribution {
|
||||
}
|
||||
}
|
||||
|
||||
if (language === 'en' && product.npsSurveyUrl) {
|
||||
if (language === 'en') {
|
||||
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
workbenchRegistry.registerWorkbenchContribution(NPSContribution, LifecyclePhase.Restored);
|
||||
}
|
||||
@@ -188,6 +188,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
protected _taskSystemInfos: Map<string, TaskSystemInfo>;
|
||||
|
||||
protected _workspaceTasksPromise?: Promise<Map<string, WorkspaceFolderTaskResult>>;
|
||||
protected _areJsonTasksSupportedPromise: Promise<boolean> = Promise.resolve(false);
|
||||
|
||||
protected _taskSystem?: ITaskSystem;
|
||||
protected _taskSystemListener?: IDisposable;
|
||||
@@ -1416,6 +1417,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
}
|
||||
}
|
||||
|
||||
public setJsonTasksSupported(areSupported: Promise<boolean>) {
|
||||
this._areJsonTasksSupportedPromise = areSupported;
|
||||
}
|
||||
|
||||
private computeWorkspaceFolderTasks(workspaceFolder: IWorkspaceFolder, runSource: TaskRunSource = TaskRunSource.User): Promise<WorkspaceFolderTaskResult> {
|
||||
return (this.executionEngine === ExecutionEngine.Process
|
||||
? this.computeLegacyConfiguration(workspaceFolder)
|
||||
@@ -1424,7 +1429,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
if (!workspaceFolderConfiguration || !workspaceFolderConfiguration.config || workspaceFolderConfiguration.hasErrors) {
|
||||
return Promise.resolve({ workspaceFolder, set: undefined, configurations: undefined, hasErrors: workspaceFolderConfiguration ? workspaceFolderConfiguration.hasErrors : false });
|
||||
}
|
||||
return ProblemMatcherRegistry.onReady().then((): WorkspaceFolderTaskResult => {
|
||||
return ProblemMatcherRegistry.onReady().then(async (): Promise<WorkspaceFolderTaskResult> => {
|
||||
let taskSystemInfo: TaskSystemInfo | undefined = this._taskSystemInfos.get(workspaceFolder.uri.scheme);
|
||||
let problemReporter = new ProblemReporter(this._outputChannel);
|
||||
let parseResult = TaskConfig.parse(workspaceFolder, taskSystemInfo ? taskSystemInfo.platform : Platform.platform, workspaceFolderConfiguration.config!, problemReporter);
|
||||
@@ -1446,7 +1451,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
customizedTasks.byIdentifier[task.configures._key] = task;
|
||||
}
|
||||
}
|
||||
return { workspaceFolder, set: { tasks: parseResult.custom }, configurations: customizedTasks, hasErrors };
|
||||
if (!(await this._areJsonTasksSupportedPromise) && (parseResult.custom.length > 0)) {
|
||||
console.warn('Custom workspace tasks are not supported.');
|
||||
}
|
||||
return { workspaceFolder, set: { tasks: await this._areJsonTasksSupportedPromise ? parseResult.custom : [] }, configurations: customizedTasks, hasErrors };
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ export interface ITaskService {
|
||||
registerTaskProvider(taskProvider: ITaskProvider, type: string): IDisposable;
|
||||
|
||||
registerTaskSystem(scheme: string, taskSystemInfo: TaskSystemInfo): void;
|
||||
setJsonTasksSupported(areSuppored: Promise<boolean>): void;
|
||||
|
||||
extensionCallbackTaskComplete(task: Task, result: number | undefined): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 2H9V3H6V2ZM11 3H10V2C10 1.44772 9.55228 1 9 1H6C5.44772 1 5 1.44772 5 2V3H4H3H2V4H3V13L4 14H11L12 13V4H13V3H12H11ZM4 4V13H11V4H4ZM6 5H5V12H6V5ZM7 5H8V12H7V5ZM10 5H9V12H10V5Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 347 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 2H9V3H6V2ZM11 3H10V2C10 1.44772 9.55228 1 9 1H6C5.44772 1 5 1.44772 5 2V3H4H3H2V4H3V13L4 14H11L12 13V4H13V3H12H11ZM4 4V13H11V4H4ZM6 5H5V12H6V5ZM7 5H8V12H7V5ZM10 5H9V12H10V5Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 345 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 2H9V3H6V2ZM11 3H10V2C10 1.44772 9.55228 1 9 1H6C5.44772 1 5 1.44772 5 2V3H4H3H2V4H3V13L4 14H11L12 13V4H13V3H12H11ZM4 4V13H11V4H4ZM6 5H5V12H6V5ZM7 5H8V12H7V5ZM10 5H9V12H10V5Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 347 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 7V8H8V14H7V8H1V7H7V1H8V7H14Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 163 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 7V8H8V14H7V8H1V7H7V1H8V7H14Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 161 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 7V8H8V14H7V8H1V7H7V1H8V7H14Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 163 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 2L14 1L3 0.999999L2 2L2 13L3 14L14 14L15 13L15 2ZM9 2L14 2L14 13L9 13L9 2ZM8 2L3 2L3 13L8 13L8 2Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 272 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 2L14 1L3 0.999999L2 2L2 13L3 14L14 14L15 13L15 2ZM9 2L14 2L14 13L9 13L9 2ZM8 2L3 2L3 13L8 13L8 2Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 270 B |