mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-30 08:40:29 -04:00
Merge from vscode 79a1f5a5ca0c6c53db617aa1fa5a2396d2caebe2
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { NativeBackupTracker } from 'vs/workbench/contrib/backup/electron-browser/backupTracker';
|
||||
import { NativeBackupTracker } from 'vs/workbench/contrib/backup/electron-sandbox/backupTracker';
|
||||
|
||||
// Register Backup Tracker
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NativeBackupTracker, LifecyclePhase.Starting);
|
||||
@@ -14,7 +14,7 @@ import Severity from 'vs/base/common/severity';
|
||||
import { WorkbenchState, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { HotExitConfiguration } from 'vs/platform/files/common/files';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
import { IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
|
||||
import { BackupTracker } from 'vs/workbench/contrib/backup/common/backupTracker';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
@@ -13,7 +13,7 @@ import { createTextBufferFactory } from 'vs/editor/common/model/textModel';
|
||||
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
||||
import { DefaultEndOfLine } from 'vs/editor/common/model';
|
||||
import { hashPath } from 'vs/workbench/services/backup/node/backupFileService';
|
||||
import { NativeBackupTracker } from 'vs/workbench/contrib/backup/electron-browser/backupTracker';
|
||||
import { NativeBackupTracker } from 'vs/workbench/contrib/backup/electron-sandbox/backupTracker';
|
||||
import { workbenchInstantiationService } from 'vs/workbench/test/electron-browser/workbenchTestServices';
|
||||
import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as pfs from 'vs/base/node/pfs';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
||||
import { hashPath } from 'vs/workbench/services/backup/node/backupFileService';
|
||||
import { NativeBackupTracker } from 'vs/workbench/contrib/backup/electron-browser/backupTracker';
|
||||
import { NativeBackupTracker } from 'vs/workbench/contrib/backup/electron-sandbox/backupTracker';
|
||||
import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
|
||||
@@ -34,7 +34,7 @@ import { HotExitConfiguration } from 'vs/platform/files/common/files';
|
||||
import { ShutdownReason, ILifecycleService, BeforeShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IFileDialogService, ConfirmResult, IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IWorkspaceContextService, Workspace } from 'vs/platform/workspace/common/workspace';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
import { IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
|
||||
import { BackupTracker } from 'vs/workbench/contrib/backup/common/backupTracker';
|
||||
import { workbenchInstantiationService, TestServiceAccessor } from 'vs/workbench/test/electron-browser/workbenchTestServices';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
@@ -70,10 +70,10 @@
|
||||
min-width: 16px;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .bulk-edit-panel .monaco-tl-contents.category .uri-icon,
|
||||
.hc-black .monaco-workbench .bulk-edit-panel .monaco-tl-contents.category .uri-icon,
|
||||
.vs-dark .monaco-workbench .bulk-edit-panel .monaco-tl-contents.textedit .uri-icon,
|
||||
.hc-black .monaco-workbench .bulk-edit-panel .monaco-tl-contents.textedit .uri-icon
|
||||
.monaco-workbench.vs-dark .bulk-edit-panel .monaco-tl-contents.category .uri-icon,
|
||||
.monaco-workbench.hc-black .bulk-edit-panel .monaco-tl-contents.category .uri-icon,
|
||||
.monaco-workbench.vs-dark .bulk-edit-panel .monaco-tl-contents.textedit .uri-icon,
|
||||
.monaco-workbench.hc-black .bulk-edit-panel .monaco-tl-contents.textedit .uri-icon
|
||||
{
|
||||
background-image: var(--background-dark);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import { IIdentifiedSingleEditOperation } from 'vs/editor/common/model';
|
||||
import { ConflictDetector } from 'vs/workbench/services/bulkEdit/browser/conflicts';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { localize } from 'vs/nls';
|
||||
import { extUri } from 'vs/base/common/resources';
|
||||
|
||||
export class CheckedStates<T extends object> {
|
||||
|
||||
@@ -209,13 +210,13 @@ export class BulkFileOperations {
|
||||
}
|
||||
|
||||
const insert = (uri: URI, map: Map<string, BulkFileOperation>) => {
|
||||
let key = uri.toString();
|
||||
let key = extUri.getComparisonKey(uri, true);
|
||||
let operation = map.get(key);
|
||||
|
||||
// rename
|
||||
if (!operation && newToOldUri.has(uri)) {
|
||||
uri = newToOldUri.get(uri)!;
|
||||
key = uri.toString();
|
||||
key = extUri.getComparisonKey(uri, true);
|
||||
operation = map.get(key);
|
||||
}
|
||||
|
||||
|
||||
@@ -350,6 +350,10 @@ export abstract class SimpleFindReplaceWidget extends Widget {
|
||||
}, 0);
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
this._findInput.focus();
|
||||
}
|
||||
|
||||
public show(initialInput?: string): void {
|
||||
if (initialInput && !this._isVisible) {
|
||||
this._findInput.setValue(initialInput);
|
||||
@@ -361,6 +365,8 @@ export abstract class SimpleFindReplaceWidget extends Widget {
|
||||
dom.addClass(this._domNode, 'visible');
|
||||
dom.addClass(this._domNode, 'visible-transition');
|
||||
this._domNode.setAttribute('aria-hidden', 'false');
|
||||
|
||||
this.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,17 +14,18 @@ import { AbstractGotoSymbolQuickAccessProvider, IGotoSymbolQuickPickItem } from
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWorkbenchEditorConfiguration, IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { DisposableStore, IDisposable, toDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { registerAction2, Action2 } from 'vs/platform/actions/common/actions';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { prepareQuery } from 'vs/base/common/fuzzyScorer';
|
||||
import { SymbolKind } from 'vs/editor/common/modes';
|
||||
import { fuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
|
||||
export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccessProvider {
|
||||
|
||||
@@ -41,6 +42,13 @@ export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccess
|
||||
|
||||
//#region DocumentSymbols (text editor required)
|
||||
|
||||
protected provideWithTextEditor(editor: IEditor, picker: IQuickPick<IGotoSymbolQuickPickItem>, token: CancellationToken): IDisposable {
|
||||
if (this.canPickFromTableOfContents()) {
|
||||
return this.doGetTableOfContentsPicks(picker);
|
||||
}
|
||||
return super.provideWithTextEditor(editor, picker, token);
|
||||
}
|
||||
|
||||
private get configuration() {
|
||||
const editorConfig = this.configurationService.getValue<IWorkbenchEditorConfiguration>().workbench.editor;
|
||||
|
||||
@@ -106,12 +114,21 @@ export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccess
|
||||
//#endregion
|
||||
|
||||
protected provideWithoutTextEditor(picker: IQuickPick<IGotoSymbolQuickPickItem>): IDisposable {
|
||||
const pane = this.editorService.activeEditorPane;
|
||||
if (!pane || !TableOfContentsProviderRegistry.has(pane.getId())) {
|
||||
//
|
||||
return super.provideWithoutTextEditor(picker);
|
||||
if (this.canPickFromTableOfContents()) {
|
||||
return this.doGetTableOfContentsPicks(picker);
|
||||
}
|
||||
return super.provideWithoutTextEditor(picker);
|
||||
}
|
||||
|
||||
private canPickFromTableOfContents(): boolean {
|
||||
return this.editorService.activeEditorPane ? TableOfContentsProviderRegistry.has(this.editorService.activeEditorPane.getId()) : false;
|
||||
}
|
||||
|
||||
private doGetTableOfContentsPicks(picker: IQuickPick<IGotoSymbolQuickPickItem>): IDisposable {
|
||||
const pane = this.editorService.activeEditorPane;
|
||||
if (!pane) {
|
||||
return Disposable.None;
|
||||
}
|
||||
const provider = TableOfContentsProviderRegistry.get(pane.getId())!;
|
||||
const cts = new CancellationTokenSource();
|
||||
|
||||
@@ -133,7 +150,8 @@ export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccess
|
||||
kind: SymbolKind.File,
|
||||
index: idx,
|
||||
score: 0,
|
||||
label: entry.label,
|
||||
label: entry.icon ? `$(${entry.icon.id}) ${entry.label}` : entry.label,
|
||||
ariaLabel: entry.detail ? `${entry.label}, ${entry.detail}` : entry.label,
|
||||
detail: entry.detail,
|
||||
description: entry.description,
|
||||
};
|
||||
@@ -142,7 +160,7 @@ export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccess
|
||||
disposables.add(picker.onDidAccept(() => {
|
||||
picker.hide();
|
||||
const [entry] = picker.selectedItems;
|
||||
entries[entry.index]?.reveal();
|
||||
entries[entry.index]?.pick();
|
||||
}));
|
||||
|
||||
const updatePickerItems = () => {
|
||||
@@ -175,14 +193,11 @@ export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccess
|
||||
let ignoreFirstActiveEvent = true;
|
||||
disposables.add(picker.onDidChangeActive(() => {
|
||||
const [entry] = picker.activeItems;
|
||||
|
||||
if (entry && entries[entry.index]) {
|
||||
if (ignoreFirstActiveEvent) {
|
||||
ignoreFirstActiveEvent = false;
|
||||
return;
|
||||
if (!ignoreFirstActiveEvent) {
|
||||
entries[entry.index]?.preview();
|
||||
}
|
||||
|
||||
entries[entry.index]?.reveal();
|
||||
ignoreFirstActiveEvent = false;
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -206,36 +221,38 @@ Registry.as<IQuickAccessRegistry>(QuickaccessExtensions.Quickaccess).registerQui
|
||||
]
|
||||
});
|
||||
|
||||
export class GotoSymbolAction extends Action {
|
||||
registerAction2(class GotoSymbolAction extends Action2 {
|
||||
|
||||
static readonly ID = 'workbench.action.gotoSymbol';
|
||||
static readonly LABEL = localize('gotoSymbol', "Go to Symbol in Editor...");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService
|
||||
) {
|
||||
super(id, label);
|
||||
constructor() {
|
||||
super({
|
||||
id: 'workbench.action.gotoSymbol',
|
||||
title: {
|
||||
value: localize('gotoSymbol', "Go to Symbol in Editor..."),
|
||||
original: 'Go to Symbol in Editor...'
|
||||
},
|
||||
f1: true,
|
||||
keybinding: {
|
||||
when: undefined,
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_O
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
this.quickInputService.quickAccess.show(GotoSymbolQuickAccessProvider.PREFIX);
|
||||
run(accessor: ServicesAccessor) {
|
||||
accessor.get(IQuickInputService).quickAccess.show(GotoSymbolQuickAccessProvider.PREFIX);
|
||||
}
|
||||
}
|
||||
|
||||
Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions).registerWorkbenchAction(SyncActionDescriptor.from(GotoSymbolAction, {
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_O
|
||||
}), 'Go to Symbol in Editor...');
|
||||
|
||||
});
|
||||
|
||||
//#region toc definition and logic
|
||||
|
||||
export interface ITableOfContentsEntry {
|
||||
icon?: ThemeIcon;
|
||||
label: string;
|
||||
detail?: string;
|
||||
description?: string;
|
||||
reveal(): any;
|
||||
pick(): any;
|
||||
preview(): any;
|
||||
}
|
||||
|
||||
export interface ITableOfContentsProvider<T extends IEditorPane = IEditorPane> {
|
||||
|
||||
@@ -311,7 +311,7 @@ function getSuggestEnabledInputOptions(ariaLabel?: string): IEditorOptions {
|
||||
roundedSelection: false,
|
||||
renderIndentGuides: false,
|
||||
cursorWidth: 1,
|
||||
fontFamily: ' -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif',
|
||||
fontFamily: ' system-ui, -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif',
|
||||
ariaLabel: ariaLabel || '',
|
||||
|
||||
snippetSuggestions: 'none',
|
||||
|
||||
@@ -47,31 +47,31 @@ export class ToggleColumnSelectionAction extends Action {
|
||||
if (!codeEditor || codeEditor !== this._getCodeEditor() || oldValue === newValue || !codeEditor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
const cursors = codeEditor._getCursors();
|
||||
const viewModel = codeEditor._getViewModel();
|
||||
if (codeEditor.getOption(EditorOption.columnSelection)) {
|
||||
const selection = codeEditor.getSelection();
|
||||
const modelSelectionStart = new Position(selection.selectionStartLineNumber, selection.selectionStartColumn);
|
||||
const viewSelectionStart = cursors.context.convertModelPositionToViewPosition(modelSelectionStart);
|
||||
const viewSelectionStart = viewModel.coordinatesConverter.convertModelPositionToViewPosition(modelSelectionStart);
|
||||
const modelPosition = new Position(selection.positionLineNumber, selection.positionColumn);
|
||||
const viewPosition = cursors.context.convertModelPositionToViewPosition(modelPosition);
|
||||
const viewPosition = viewModel.coordinatesConverter.convertModelPositionToViewPosition(modelPosition);
|
||||
|
||||
CoreNavigationCommands.MoveTo.runCoreEditorCommand(cursors, {
|
||||
CoreNavigationCommands.MoveTo.runCoreEditorCommand(viewModel, {
|
||||
position: modelSelectionStart,
|
||||
viewPosition: viewSelectionStart
|
||||
});
|
||||
const visibleColumn = CursorColumns.visibleColumnFromColumn2(cursors.context.config, cursors.context.viewModel, viewPosition);
|
||||
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursors, {
|
||||
const visibleColumn = CursorColumns.visibleColumnFromColumn2(viewModel.cursorConfig, viewModel, viewPosition);
|
||||
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(viewModel, {
|
||||
position: modelPosition,
|
||||
viewPosition: viewPosition,
|
||||
doColumnSelect: true,
|
||||
mouseColumn: visibleColumn + 1
|
||||
});
|
||||
} else {
|
||||
const columnSelectData = cursors.getColumnSelectData();
|
||||
const fromViewColumn = CursorColumns.columnFromVisibleColumn2(cursors.context.config, cursors.context.viewModel, columnSelectData.fromViewLineNumber, columnSelectData.fromViewVisualColumn);
|
||||
const fromPosition = cursors.context.convertViewPositionToModelPosition(columnSelectData.fromViewLineNumber, fromViewColumn);
|
||||
const toViewColumn = CursorColumns.columnFromVisibleColumn2(cursors.context.config, cursors.context.viewModel, columnSelectData.toViewLineNumber, columnSelectData.toViewVisualColumn);
|
||||
const toPosition = cursors.context.convertViewPositionToModelPosition(columnSelectData.toViewLineNumber, toViewColumn);
|
||||
const columnSelectData = viewModel.getCursorColumnSelectData();
|
||||
const fromViewColumn = CursorColumns.columnFromVisibleColumn2(viewModel.cursorConfig, viewModel, columnSelectData.fromViewLineNumber, columnSelectData.fromViewVisualColumn);
|
||||
const fromPosition = viewModel.coordinatesConverter.convertViewPositionToModelPosition(new Position(columnSelectData.fromViewLineNumber, fromViewColumn));
|
||||
const toViewColumn = CursorColumns.columnFromVisibleColumn2(viewModel.cursorConfig, viewModel, columnSelectData.toViewLineNumber, columnSelectData.toViewVisualColumn);
|
||||
const toPosition = viewModel.coordinatesConverter.convertViewPositionToModelPosition(new Position(columnSelectData.toViewLineNumber, toViewColumn));
|
||||
|
||||
codeEditor.setSelection(new Selection(fromPosition.lineNumber, fromPosition.column, toPosition.lineNumber, toPosition.column));
|
||||
}
|
||||
|
||||
@@ -3,7 +3,4 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import './inputClipboardActions';
|
||||
import './sleepResumeRepaintMinimap';
|
||||
import './selectionClipboard';
|
||||
import './startDebugTextMate';
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
@@ -22,6 +21,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { join } from 'vs/base/common/path';
|
||||
|
||||
class StartDebugTextMate extends Action {
|
||||
|
||||
@@ -59,7 +59,7 @@ class StartDebugTextMate extends Action {
|
||||
}
|
||||
|
||||
public async run(): Promise<any> {
|
||||
const pathInTemp = path.join(os.tmpdir(), `vcode-tm-log-${generateUuid()}.txt`);
|
||||
const pathInTemp = join(os.tmpdir(), `vcode-tm-log-${generateUuid()}.txt`);
|
||||
const logger = createRotatingLogger(`tm-log`, pathInTemp, 1024 * 1024 * 30, 1);
|
||||
const model = this._getOrCreateModel();
|
||||
const append = (str: string) => {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import './inputClipboardActions';
|
||||
import './selectionClipboard';
|
||||
import './sleepResumeRepaintMinimap';
|
||||
@@ -6,7 +6,7 @@
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { ipcRenderer as ipc } from 'electron';
|
||||
import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
|
||||
class SleepResumeRepaintMinimap implements IWorkbenchContribution {
|
||||
@@ -14,7 +14,7 @@ class SleepResumeRepaintMinimap implements IWorkbenchContribution {
|
||||
constructor(
|
||||
@ICodeEditorService codeEditorService: ICodeEditorService
|
||||
) {
|
||||
ipc.on('vscode:osResume', () => {
|
||||
ipcRenderer.on('vscode:osResume', () => {
|
||||
codeEditorService.listCodeEditors().forEach(editor => editor.render(true));
|
||||
});
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { CommentFormActions } from 'vs/workbench/contrib/comments/browser/commentFormActions';
|
||||
import { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';
|
||||
|
||||
export class CommentNode extends Disposable {
|
||||
private _domNode: HTMLElement;
|
||||
@@ -100,7 +101,7 @@ export class CommentNode extends Disposable {
|
||||
|
||||
this.createHeader(this._commentDetailsContainer);
|
||||
|
||||
this._body = dom.append(this._commentDetailsContainer, dom.$('div.comment-body'));
|
||||
this._body = dom.append(this._commentDetailsContainer, dom.$(`div.comment-body.${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME}`));
|
||||
this._md = this.markdownRenderer.render(comment.body).element;
|
||||
this._body.appendChild(this._md);
|
||||
|
||||
@@ -120,7 +121,7 @@ export class CommentNode extends Disposable {
|
||||
}
|
||||
|
||||
private createHeader(commentDetailsContainer: HTMLElement): void {
|
||||
const header = dom.append(commentDetailsContainer, dom.$('div.comment-title'));
|
||||
const header = dom.append(commentDetailsContainer, dom.$(`div.comment-title.${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME}`));
|
||||
const author = dom.append(header, dom.$('strong.author'));
|
||||
author.innerText = this.comment.userName;
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';
|
||||
|
||||
export const COMMENTEDITOR_DECORATION_KEY = 'commenteditordecoration';
|
||||
const COLLAPSE_ACTION_CLASS = 'expand-review-action codicon-chevron-up';
|
||||
@@ -720,7 +721,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
||||
}
|
||||
|
||||
private createReplyButton() {
|
||||
this._reviewThreadReplyButton = <HTMLButtonElement>dom.append(this._commentForm, dom.$('button.review-thread-reply-button'));
|
||||
this._reviewThreadReplyButton = <HTMLButtonElement>dom.append(this._commentForm, dom.$(`button.review-thread-reply-button.${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME}`));
|
||||
this._reviewThreadReplyButton.title = this._commentOptions?.prompt || nls.localize('reply', "Reply...");
|
||||
|
||||
this._reviewThreadReplyButton.textContent = this._commentOptions?.prompt || nls.localize('reply', "Reply...");
|
||||
|
||||
@@ -257,7 +257,6 @@
|
||||
line-height: 20px;
|
||||
white-space: nowrap;
|
||||
border: 0px;
|
||||
cursor: text;
|
||||
outline: 1px solid transparent;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,8 @@ export class DefaultConfigurationExportHelper {
|
||||
|
||||
const processProperty = (name: string, prop: IConfigurationPropertySchema) => {
|
||||
if (processedNames.has(name)) {
|
||||
throw new Error('Setting is registered twice: ' + name);
|
||||
console.warn('Setting is registered twice: ' + name);
|
||||
return;
|
||||
}
|
||||
|
||||
processedNames.add(name);
|
||||
|
||||
@@ -97,9 +97,8 @@ export class CustomEditorInputFactory extends WebviewEditorInputFactory {
|
||||
const webview = webviewService.createWebviewOverlay(data.id, {
|
||||
enableFindWidget: data.options.enableFindWidget,
|
||||
retainContextWhenHidden: data.options.retainContextWhenHidden
|
||||
}, data.options);
|
||||
}, data.options, data.extension);
|
||||
webview.state = data.state;
|
||||
webview.extension = data.extension;
|
||||
return webview;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ import { EditorActivation, IEditorOptions, ITextEditorOptions } from 'vs/platfor
|
||||
import { FileOperation, IFileService } from 'vs/platform/files/common/files';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import * as colorRegistry from 'vs/platform/theme/common/colorRegistry';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { EditorInput, EditorOptions, GroupIdentifier, IEditorInput, IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
@@ -37,7 +37,7 @@ import { CustomEditorInput } from './customEditorInput';
|
||||
export class CustomEditorService extends Disposable implements ICustomEditorService, ICustomEditorViewTypesHandler {
|
||||
_serviceBrand: any;
|
||||
|
||||
private readonly _contributedEditors = this._register(new ContributedCustomEditors());
|
||||
private readonly _contributedEditors: ContributedCustomEditors;
|
||||
private readonly _editorCapabilities = new Map<string, CustomEditorCapabilities>();
|
||||
|
||||
private readonly _models = new CustomEditorModelManager();
|
||||
@@ -51,6 +51,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
constructor(
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IFileService fileService: IFileService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
|
||||
@@ -64,11 +65,13 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
this._focusedCustomEditorIsEditable = CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE.bindTo(contextKeyService);
|
||||
this._webviewHasOwnEditFunctions = webviewHasOwnEditFunctionsContext.bindTo(contextKeyService);
|
||||
|
||||
this._register(this.editorService.registerCustomEditorViewTypesHandler('Custom Editor', this));
|
||||
|
||||
this._contributedEditors = this._register(new ContributedCustomEditors(storageService));
|
||||
this._register(this._contributedEditors.onChange(() => {
|
||||
this.updateContexts();
|
||||
this._onDidChangeViewTypes.fire();
|
||||
}));
|
||||
this._register(this.editorService.registerCustomEditorViewTypesHandler('Custom Editor', this));
|
||||
this._register(this.editorService.onDidActiveEditorChange(() => this.updateContexts()));
|
||||
|
||||
this._register(fileService.onDidRunOperation(e => {
|
||||
@@ -231,7 +234,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
|
||||
const id = generateUuid();
|
||||
const webview = new Lazy(() => {
|
||||
return this.webviewService.createWebviewOverlay(id, { customClasses: options?.customClasses }, {});
|
||||
return this.webviewService.createWebviewOverlay(id, { customClasses: options?.customClasses }, {}, undefined);
|
||||
});
|
||||
const input = this.instantiationService.createInstance(CustomEditorInput, resource, viewType, id, webview, {});
|
||||
if (typeof group !== 'undefined') {
|
||||
@@ -418,19 +421,23 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
|
||||
export class CustomEditorContribution extends Disposable implements IWorkbenchContribution {
|
||||
constructor(
|
||||
@IEditorService private readonly editorService: EditorServiceImpl,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@ICustomEditorService private readonly customEditorService: ICustomEditorService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._register(this.editorService.overrideOpenEditor({
|
||||
open: (editor, options, group, id) => {
|
||||
open: (editor, options, group, context, id) => {
|
||||
return this.onEditorOpening(editor, options, group, id);
|
||||
},
|
||||
getEditorOverrides: (resource: URI, _options: IEditorOptions | undefined, group: IEditorGroup | undefined): IOpenEditorOverrideEntry[] => {
|
||||
const currentEditor = group?.editors.find(editor => isEqual(editor.resource, resource));
|
||||
|
||||
const customEditors = this.customEditorService.getAllCustomEditors(resource);
|
||||
if (!customEditors.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
...defaultEditorOverrideEntry,
|
||||
|
||||
@@ -8,9 +8,12 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { CustomEditorInfo, CustomEditorPriority } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { Memento } from 'vs/workbench/common/memento';
|
||||
import { CustomEditorDescriptor, CustomEditorInfo, CustomEditorPriority } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { customEditorsExtensionPoint, ICustomEditorsExtensionPoint } from 'vs/workbench/contrib/customEditor/common/extensionPoint';
|
||||
import { DEFAULT_EDITOR_ID } from 'vs/workbench/contrib/files/common/files';
|
||||
import { IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
|
||||
const builtinProviderDisplayName = nls.localize('builtinProviderDisplayName', "Built-in");
|
||||
|
||||
@@ -26,32 +29,52 @@ export const defaultCustomEditor = new CustomEditorInfo({
|
||||
|
||||
export class ContributedCustomEditors extends Disposable {
|
||||
|
||||
private readonly _editors = new Map<string, CustomEditorInfo>();
|
||||
private static readonly CUSTOM_EDITORS_STORAGE_ID = 'customEditors';
|
||||
private static readonly CUSTOM_EDITORS_ENTRY_ID = 'editors';
|
||||
|
||||
constructor() {
|
||||
private readonly _editors = new Map<string, CustomEditorInfo>();
|
||||
private readonly _memento: Memento;
|
||||
|
||||
constructor(storageService: IStorageService) {
|
||||
super();
|
||||
|
||||
customEditorsExtensionPoint.setHandler(extensions => {
|
||||
this._editors.clear();
|
||||
this._memento = new Memento(ContributedCustomEditors.CUSTOM_EDITORS_STORAGE_ID, storageService);
|
||||
|
||||
for (const extension of extensions) {
|
||||
for (const webviewEditorContribution of extension.value) {
|
||||
this.add(new CustomEditorInfo({
|
||||
id: webviewEditorContribution.viewType,
|
||||
displayName: webviewEditorContribution.displayName,
|
||||
providerDisplayName: extension.description.isBuiltin ? builtinProviderDisplayName : extension.description.displayName || extension.description.identifier.value,
|
||||
selector: webviewEditorContribution.selector || [],
|
||||
priority: getPriorityFromContribution(webviewEditorContribution, extension.description),
|
||||
}));
|
||||
}
|
||||
}
|
||||
this._onChange.fire();
|
||||
const mementoObject = this._memento.getMemento(StorageScope.GLOBAL);
|
||||
for (const info of (mementoObject[ContributedCustomEditors.CUSTOM_EDITORS_ENTRY_ID] || []) as CustomEditorDescriptor[]) {
|
||||
this.add(new CustomEditorInfo(info));
|
||||
}
|
||||
|
||||
customEditorsExtensionPoint.setHandler(extensions => {
|
||||
this.update(extensions);
|
||||
});
|
||||
}
|
||||
|
||||
private readonly _onChange = this._register(new Emitter<void>());
|
||||
public readonly onChange = this._onChange.event;
|
||||
|
||||
private update(extensions: readonly IExtensionPointUser<ICustomEditorsExtensionPoint[]>[]) {
|
||||
this._editors.clear();
|
||||
|
||||
for (const extension of extensions) {
|
||||
for (const webviewEditorContribution of extension.value) {
|
||||
this.add(new CustomEditorInfo({
|
||||
id: webviewEditorContribution.viewType,
|
||||
displayName: webviewEditorContribution.displayName,
|
||||
providerDisplayName: extension.description.isBuiltin ? builtinProviderDisplayName : extension.description.displayName || extension.description.identifier.value,
|
||||
selector: webviewEditorContribution.selector || [],
|
||||
priority: getPriorityFromContribution(webviewEditorContribution, extension.description),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
const mementoObject = this._memento.getMemento(StorageScope.GLOBAL);
|
||||
mementoObject[ContributedCustomEditors.CUSTOM_EDITORS_ENTRY_ID] = Array.from(this._editors.values());
|
||||
this._memento.saveMemento();
|
||||
|
||||
this._onChange.fire();
|
||||
}
|
||||
|
||||
public [Symbol.iterator](): Iterator<CustomEditorInfo> {
|
||||
return this._editors.values();
|
||||
}
|
||||
|
||||
@@ -79,7 +79,15 @@ export interface CustomEditorSelector {
|
||||
readonly filenamePattern?: string;
|
||||
}
|
||||
|
||||
export class CustomEditorInfo {
|
||||
export interface CustomEditorDescriptor {
|
||||
readonly id: string;
|
||||
readonly displayName: string;
|
||||
readonly providerDisplayName: string;
|
||||
readonly priority: CustomEditorPriority;
|
||||
readonly selector: readonly CustomEditorSelector[];
|
||||
}
|
||||
|
||||
export class CustomEditorInfo implements CustomEditorDescriptor {
|
||||
|
||||
public readonly id: string;
|
||||
public readonly displayName: string;
|
||||
@@ -87,13 +95,7 @@ export class CustomEditorInfo {
|
||||
public readonly priority: CustomEditorPriority;
|
||||
public readonly selector: readonly CustomEditorSelector[];
|
||||
|
||||
constructor(descriptor: {
|
||||
readonly id: string;
|
||||
readonly displayName: string;
|
||||
readonly providerDisplayName: string;
|
||||
readonly priority: CustomEditorPriority;
|
||||
readonly selector: readonly CustomEditorSelector[];
|
||||
}) {
|
||||
constructor(descriptor: CustomEditorDescriptor) {
|
||||
this.id = descriptor.id;
|
||||
this.displayName = descriptor.displayName;
|
||||
this.providerDisplayName = descriptor.providerDisplayName;
|
||||
|
||||
@@ -61,6 +61,7 @@ export class BreakpointsView extends ViewPane {
|
||||
|
||||
private list!: WorkbenchList<BreakpointItem>;
|
||||
private needsRefresh = false;
|
||||
private ignoreLayout = false;
|
||||
|
||||
constructor(
|
||||
options: IViewletViewOptions,
|
||||
@@ -79,7 +80,6 @@ export class BreakpointsView extends ViewPane {
|
||||
) {
|
||||
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
|
||||
|
||||
this.updateSize();
|
||||
this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange()));
|
||||
}
|
||||
|
||||
@@ -164,10 +164,20 @@ export class BreakpointsView extends ViewPane {
|
||||
}
|
||||
|
||||
protected layoutBody(height: number, width: number): void {
|
||||
if (this.ignoreLayout) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.layoutBody(height, width);
|
||||
if (this.list) {
|
||||
this.list.layout(height, width);
|
||||
}
|
||||
try {
|
||||
this.ignoreLayout = true;
|
||||
this.updateSize();
|
||||
} finally {
|
||||
this.ignoreLayout = false;
|
||||
}
|
||||
}
|
||||
|
||||
private onListContextMenu(e: IListContextMenuEvent<IEnablement>): void {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import 'vs/css!./media/debug.contribution';
|
||||
import 'vs/css!./media/debugHover';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
@@ -37,14 +38,14 @@ import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { launchSchemaId } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { LoadedScriptsView } from 'vs/workbench/contrib/debug/browser/loadedScriptsView';
|
||||
import { TOGGLE_LOG_POINT_ID, TOGGLE_CONDITIONAL_BREAKPOINT_ID, TOGGLE_BREAKPOINT_ID, RunToCursorAction } from 'vs/workbench/contrib/debug/browser/debugEditorActions';
|
||||
import { ADD_LOG_POINT_ID, TOGGLE_CONDITIONAL_BREAKPOINT_ID, TOGGLE_BREAKPOINT_ID, RunToCursorAction } from 'vs/workbench/contrib/debug/browser/debugEditorActions';
|
||||
import { WatchExpressionsView } from 'vs/workbench/contrib/debug/browser/watchExpressionsView';
|
||||
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 { WelcomeView } from 'vs/workbench/contrib/debug/browser/welcomeView';
|
||||
import { ThemeIcon, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { registerColor, foreground, badgeBackground, badgeForeground, listDeemphasizedForeground, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { registerColor, foreground, badgeBackground, badgeForeground, listDeemphasizedForeground, contrastBorder, inputBorder, editorWarningForeground, errorForeground, editorInfoForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { DebugViewPaneContainer, OpenDebugConsoleAction } from 'vs/workbench/contrib/debug/browser/debugViewlet';
|
||||
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { CallStackEditorContribution } from 'vs/workbench/contrib/debug/browser/callStackEditorContribution';
|
||||
@@ -55,6 +56,7 @@ import { IQuickAccessRegistry, Extensions as QuickAccessExtensions } from 'vs/pl
|
||||
import { StartDebugQuickAccessProvider } from 'vs/workbench/contrib/debug/browser/debugQuickAccess';
|
||||
import { DebugProgressContribution } from 'vs/workbench/contrib/debug/browser/debugProgress';
|
||||
import { DebugTitleContribution } from 'vs/workbench/contrib/debug/browser/debugTitle';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
class OpenDebugViewletAction extends ShowViewletAction {
|
||||
public static readonly ID = VIEWLET_ID;
|
||||
@@ -75,7 +77,7 @@ const viewContainer = Registry.as<IViewContainersRegistry>(ViewExtensions.ViewCo
|
||||
id: VIEWLET_ID,
|
||||
name: nls.localize('run', "Run"),
|
||||
ctorDescriptor: new SyncDescriptor(DebugViewPaneContainer),
|
||||
icon: 'codicon-debug-alt-2',
|
||||
icon: Codicon.debugAlt.classNames,
|
||||
alwaysUseContainerInfo: true,
|
||||
order: 13 // {{SQL CARBON EDIT}}
|
||||
}, ViewContainerLocation.Sidebar);
|
||||
@@ -92,21 +94,21 @@ const openPanelKb: IKeybindings = {
|
||||
const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewExtensions.ViewContainersRegistry).registerViewContainer({
|
||||
id: DEBUG_PANEL_ID,
|
||||
name: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugPanel' }, 'Debug Console'),
|
||||
icon: 'codicon-debug-console',
|
||||
icon: Codicon.debugConsole.classNames,
|
||||
ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [DEBUG_PANEL_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]),
|
||||
storageId: DEBUG_PANEL_ID,
|
||||
focusCommand: {
|
||||
id: OpenDebugConsoleAction.ID,
|
||||
keybindings: openPanelKb
|
||||
},
|
||||
order: 3,
|
||||
order: 2,
|
||||
hideIfEmpty: true
|
||||
}, ViewContainerLocation.Panel);
|
||||
|
||||
Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry).registerViews([{
|
||||
id: REPL_VIEW_ID,
|
||||
name: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugPanel' }, 'Debug Console'),
|
||||
containerIcon: 'codicon-debug-console',
|
||||
containerIcon: Codicon.debugConsole.classNames,
|
||||
canToggleVisibility: false,
|
||||
canMoveView: true,
|
||||
ctorDescriptor: new SyncDescriptor(Repl),
|
||||
@@ -114,12 +116,12 @@ Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry).registerViews([{
|
||||
|
||||
// Register default debug views
|
||||
const viewsRegistry = Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry);
|
||||
viewsRegistry.registerViews([{ id: VARIABLES_VIEW_ID, name: nls.localize('variables', "Variables"), containerIcon: 'codicon-debug-alt-2', ctorDescriptor: new SyncDescriptor(VariablesView), order: 10, weight: 40, canToggleVisibility: true, canMoveView: true, focusCommand: { id: 'workbench.debug.action.focusVariablesView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], viewContainer);
|
||||
viewsRegistry.registerViews([{ id: WATCH_VIEW_ID, name: nls.localize('watch', "Watch"), containerIcon: 'codicon-debug-alt-2', ctorDescriptor: new SyncDescriptor(WatchExpressionsView), order: 20, weight: 10, canToggleVisibility: true, canMoveView: true, focusCommand: { id: 'workbench.debug.action.focusWatchView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], viewContainer);
|
||||
viewsRegistry.registerViews([{ id: CALLSTACK_VIEW_ID, name: nls.localize('callStack', "Call Stack"), containerIcon: 'codicon-debug-alt-2', ctorDescriptor: new SyncDescriptor(CallStackView), order: 30, weight: 30, canToggleVisibility: true, canMoveView: true, focusCommand: { id: 'workbench.debug.action.focusCallStackView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], viewContainer);
|
||||
viewsRegistry.registerViews([{ id: BREAKPOINTS_VIEW_ID, name: nls.localize('breakpoints', "Breakpoints"), containerIcon: 'codicon-debug-alt-2', ctorDescriptor: new SyncDescriptor(BreakpointsView), order: 40, weight: 20, canToggleVisibility: true, canMoveView: true, focusCommand: { id: 'workbench.debug.action.focusBreakpointsView' }, when: ContextKeyExpr.or(CONTEXT_BREAKPOINTS_EXIST, CONTEXT_DEBUG_UX.isEqualTo('default')) }], viewContainer);
|
||||
viewsRegistry.registerViews([{ id: WelcomeView.ID, name: WelcomeView.LABEL, containerIcon: 'codicon-debug-alt-2', ctorDescriptor: new SyncDescriptor(WelcomeView), order: 1, weight: 40, canToggleVisibility: true, when: CONTEXT_DEBUG_UX.isEqualTo('simple') }], viewContainer);
|
||||
viewsRegistry.registerViews([{ id: LOADED_SCRIPTS_VIEW_ID, name: nls.localize('loadedScripts', "Loaded Scripts"), containerIcon: 'codicon-debug-alt-2', ctorDescriptor: new SyncDescriptor(LoadedScriptsView), order: 35, weight: 5, canToggleVisibility: true, canMoveView: true, collapsed: true, when: ContextKeyExpr.and(CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_DEBUG_UX.isEqualTo('default')) }], viewContainer);
|
||||
viewsRegistry.registerViews([{ id: VARIABLES_VIEW_ID, name: nls.localize('variables', "Variables"), containerIcon: Codicon.debugAlt.classNames, ctorDescriptor: new SyncDescriptor(VariablesView), order: 10, weight: 40, canToggleVisibility: true, canMoveView: true, focusCommand: { id: 'workbench.debug.action.focusVariablesView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], viewContainer);
|
||||
viewsRegistry.registerViews([{ id: WATCH_VIEW_ID, name: nls.localize('watch', "Watch"), containerIcon: Codicon.debugAlt.classNames, ctorDescriptor: new SyncDescriptor(WatchExpressionsView), order: 20, weight: 10, canToggleVisibility: true, canMoveView: true, focusCommand: { id: 'workbench.debug.action.focusWatchView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], viewContainer);
|
||||
viewsRegistry.registerViews([{ id: CALLSTACK_VIEW_ID, name: nls.localize('callStack', "Call Stack"), containerIcon: Codicon.debugAlt.classNames, ctorDescriptor: new SyncDescriptor(CallStackView), order: 30, weight: 30, canToggleVisibility: true, canMoveView: true, focusCommand: { id: 'workbench.debug.action.focusCallStackView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], viewContainer);
|
||||
viewsRegistry.registerViews([{ id: BREAKPOINTS_VIEW_ID, name: nls.localize('breakpoints', "Breakpoints"), containerIcon: Codicon.debugAlt.classNames, ctorDescriptor: new SyncDescriptor(BreakpointsView), order: 40, weight: 20, canToggleVisibility: true, canMoveView: true, focusCommand: { id: 'workbench.debug.action.focusBreakpointsView' }, when: ContextKeyExpr.or(CONTEXT_BREAKPOINTS_EXIST, CONTEXT_DEBUG_UX.isEqualTo('default')) }], viewContainer);
|
||||
viewsRegistry.registerViews([{ id: WelcomeView.ID, name: WelcomeView.LABEL, containerIcon: Codicon.debugAlt.classNames, ctorDescriptor: new SyncDescriptor(WelcomeView), order: 1, weight: 40, canToggleVisibility: true, when: CONTEXT_DEBUG_UX.isEqualTo('simple') }], viewContainer);
|
||||
viewsRegistry.registerViews([{ id: LOADED_SCRIPTS_VIEW_ID, name: nls.localize('loadedScripts', "Loaded Scripts"), containerIcon: Codicon.debugAlt.classNames, ctorDescriptor: new SyncDescriptor(LoadedScriptsView), order: 35, weight: 5, canToggleVisibility: true, canMoveView: true, collapsed: true, when: ContextKeyExpr.and(CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_DEBUG_UX.isEqualTo('default')) }], viewContainer);
|
||||
|
||||
registerCommands();
|
||||
|
||||
@@ -512,7 +514,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarNewBreakpointMenu, {
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarNewBreakpointMenu, {
|
||||
group: '1_breakpoints',
|
||||
command: {
|
||||
id: TOGGLE_LOG_POINT_ID,
|
||||
id: ADD_LOG_POINT_ID,
|
||||
title: nls.localize({ key: 'miLogPoint', comment: ['&& denotes a mnemonic'] }, "&&Logpoint...")
|
||||
},
|
||||
order: 4
|
||||
@@ -599,12 +601,18 @@ const debugTokenExpressionBoolean = registerColor('debugTokenExpression.boolean'
|
||||
const debugTokenExpressionNumber = registerColor('debugTokenExpression.number', { dark: '#b5cea8', light: '#098658', hc: '#89d185' }, 'Foreground color for numbers in the debug views (ie. the Variables or Watch view).');
|
||||
const debugTokenExpressionError = registerColor('debugTokenExpression.error', { dark: '#f48771', light: '#e51400', hc: '#f48771' }, 'Foreground color for expression errors in the debug views (ie. the Variables or Watch view) and for error logs shown in the debug console.');
|
||||
|
||||
const debugViewExceptionLabelForeground = registerColor('debugView.exceptionLabelForeground', { dark: foreground, light: foreground, hc: foreground }, 'Foreground color for a label shown in the CALL STACK view when the debugger breaks on an exception.');
|
||||
const debugViewExceptionLabelForeground = registerColor('debugView.exceptionLabelForeground', { dark: foreground, light: '#FFF', hc: foreground }, 'Foreground color for a label shown in the CALL STACK view when the debugger breaks on an exception.');
|
||||
const debugViewExceptionLabelBackground = registerColor('debugView.exceptionLabelBackground', { dark: '#6C2022', light: '#A31515', hc: '#6C2022' }, 'Background color for a label shown in the CALL STACK view when the debugger breaks on an exception.');
|
||||
const debugViewStateLabelForeground = registerColor('debugView.stateLabelForeground', { dark: foreground, light: foreground, hc: foreground }, 'Foreground color for a label in the CALL STACK view showing the current session\'s or thread\'s state.');
|
||||
const debugViewStateLabelBackground = registerColor('debugView.stateLabelBackground', { dark: '#88888844', light: '#88888844', hc: '#88888844' }, 'Background color for a label in the CALL STACK view showing the current session\'s or thread\'s state.');
|
||||
const debugViewValueChangedHighlight = registerColor('debugView.valueChangedHighlight', { dark: '#569CD6', light: '#569CD6', hc: '#569CD6' }, 'Color used to highlight value changes in the debug views (ie. in the Variables view).');
|
||||
|
||||
const debugConsoleInfoForeground = registerColor('debugConsole.infoForeground', { dark: editorInfoForeground, light: editorInfoForeground, hc: foreground }, 'Foreground color for info messages in debug REPL console.');
|
||||
const debugConsoleWarningForeground = registerColor('debugConsole.warningForeground', { dark: editorWarningForeground, light: editorWarningForeground, hc: '#008000' }, 'Foreground color for warning messages in debug REPL console.');
|
||||
const debugConsoleErrorForeground = registerColor('debugConsole.errorForeground', { dark: errorForeground, light: errorForeground, hc: errorForeground }, 'Foreground color for error messages in debug REPL console.');
|
||||
const debugConsoleSourceForeground = registerColor('debugConsole.sourceForeground', { dark: foreground, light: foreground, hc: foreground }, 'Foreground color for source filenames in debug REPL console.');
|
||||
const debugConsoleInputIconForeground = registerColor('debugConsoleInputIcon.foreground', { dark: foreground, light: foreground, hc: foreground }, 'Foreground color for debug console input marker icon.');
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
// All these colours provide a default value so they will never be undefined, hence the `!`
|
||||
const badgeBackgroundColor = theme.getColor(badgeBackground)!;
|
||||
@@ -714,4 +722,53 @@ registerThemingParticipant((theme, collector) => {
|
||||
color: ${tokenNumberColor};
|
||||
}
|
||||
`);
|
||||
|
||||
const debugConsoleInputBorderColor = theme.getColor(inputBorder) || Color.fromHex('#80808060');
|
||||
const debugConsoleInfoForegroundColor = theme.getColor(debugConsoleInfoForeground)!;
|
||||
const debugConsoleWarningForegroundColor = theme.getColor(debugConsoleWarningForeground)!;
|
||||
const debugConsoleErrorForegroundColor = theme.getColor(debugConsoleErrorForeground)!;
|
||||
const debugConsoleSourceForegroundColor = theme.getColor(debugConsoleSourceForeground)!;
|
||||
const debugConsoleInputIconForegroundColor = theme.getColor(debugConsoleInputIconForeground)!;
|
||||
|
||||
collector.addRule(`
|
||||
.repl .repl-input-wrapper {
|
||||
border-top: 1px solid ${debugConsoleInputBorderColor};
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-tree .output .expression .value.info {
|
||||
color: ${debugConsoleInfoForegroundColor};
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-tree .output .expression .value.warn {
|
||||
color: ${debugConsoleWarningForegroundColor};
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-tree .output .expression .value.error {
|
||||
color: ${debugConsoleErrorForegroundColor};
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-tree .output .expression .source {
|
||||
color: ${debugConsoleSourceForegroundColor};
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-tree .monaco-tl-contents .arrow {
|
||||
color: ${debugConsoleInputIconForegroundColor};
|
||||
}
|
||||
`);
|
||||
|
||||
if (!theme.defines(debugConsoleInputIconForeground)) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench.vs .repl .repl-tree .monaco-tl-contents .arrow {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.monaco-workbench.vs-dark .repl .repl-tree .monaco-tl-contents .arrow {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.monaco-workbench.hc-black .repl .repl-tree .monaco-tl-contents .arrow {
|
||||
opacity: 1;
|
||||
}
|
||||
`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -20,7 +20,6 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ADD_CONFIGURATION_ID } from 'vs/workbench/contrib/debug/browser/debugCommands';
|
||||
import { StartAction } from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -32,7 +31,7 @@ export class StartDebugActionViewItem implements IActionViewItem {
|
||||
private container!: HTMLElement;
|
||||
private start!: HTMLElement;
|
||||
private selectBox: SelectBox;
|
||||
private options: { label: string, handler?: (() => boolean) }[] = [];
|
||||
private options: { label: string, handler: (() => Promise<boolean>) }[] = [];
|
||||
private toDispose: IDisposable[];
|
||||
private selected = 0;
|
||||
private providers: { label: string, pick: () => Promise<{ launch: ILaunch, config: IConfig } | undefined> }[] = [];
|
||||
@@ -101,9 +100,9 @@ export class StartDebugActionViewItem implements IActionViewItem {
|
||||
event.stopPropagation();
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(this.selectBox.onDidSelect(e => {
|
||||
this.toDispose.push(this.selectBox.onDidSelect(async e => {
|
||||
const target = this.options[e.index];
|
||||
const shouldBeSelected = target.handler ? target.handler() : false;
|
||||
const shouldBeSelected = target.handler ? await target.handler() : false;
|
||||
if (shouldBeSelected) {
|
||||
this.selected = e.index;
|
||||
} else {
|
||||
@@ -126,7 +125,6 @@ export class StartDebugActionViewItem implements IActionViewItem {
|
||||
selectBoxContainer.style.borderLeft = colors.selectBorder ? `1px solid ${colors.selectBorder}` : '';
|
||||
const selectBackgroundColor = colors.selectBackground ? `${colors.selectBackground}` : '';
|
||||
this.container.style.backgroundColor = selectBackgroundColor;
|
||||
this.start.style.backgroundColor = selectBackgroundColor;
|
||||
}));
|
||||
this.debugService.getConfigurationManager().getDynamicProviders().then(providers => {
|
||||
this.providers = providers;
|
||||
@@ -173,7 +171,7 @@ export class StartDebugActionViewItem implements IActionViewItem {
|
||||
if (lastGroup !== presentation?.group) {
|
||||
lastGroup = presentation?.group;
|
||||
if (this.options.length) {
|
||||
this.options.push({ label: StartDebugActionViewItem.SEPARATOR, handler: undefined });
|
||||
this.options.push({ label: StartDebugActionViewItem.SEPARATOR, handler: () => Promise.resolve(false) });
|
||||
disabledIdxs.push(this.options.length - 1);
|
||||
}
|
||||
}
|
||||
@@ -183,8 +181,7 @@ export class StartDebugActionViewItem implements IActionViewItem {
|
||||
|
||||
const label = inWorkspace ? `${name} (${launch.name})` : name;
|
||||
this.options.push({
|
||||
label, handler: () => {
|
||||
StartAction.GET_CONFIG_AND_LAUNCH = undefined;
|
||||
label, handler: async () => {
|
||||
manager.selectConfiguration(launch, name);
|
||||
return true;
|
||||
}
|
||||
@@ -192,31 +189,39 @@ export class StartDebugActionViewItem implements IActionViewItem {
|
||||
});
|
||||
|
||||
if (this.options.length === 0) {
|
||||
this.options.push({ label: nls.localize('noConfigurations', "No Configurations"), handler: () => false });
|
||||
this.options.push({ label: nls.localize('noConfigurations', "No Configurations"), handler: async () => false });
|
||||
} else {
|
||||
this.options.push({ label: StartDebugActionViewItem.SEPARATOR, handler: undefined });
|
||||
this.options.push({ label: StartDebugActionViewItem.SEPARATOR, handler: () => Promise.resolve(false) });
|
||||
disabledIdxs.push(this.options.length - 1);
|
||||
}
|
||||
|
||||
this.providers.forEach(p => {
|
||||
if (p.label === manager.selectedConfiguration.name) {
|
||||
this.selected = this.options.length;
|
||||
}
|
||||
|
||||
this.options.push({
|
||||
label: `${p.label}...`, handler: () => {
|
||||
StartAction.GET_CONFIG_AND_LAUNCH = p.pick;
|
||||
return true;
|
||||
label: `${p.label}...`, handler: async () => {
|
||||
const picked = await p.pick();
|
||||
if (picked) {
|
||||
manager.selectConfiguration(picked.launch, p.label, picked.config);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (this.providers.length > 0) {
|
||||
this.options.push({ label: StartDebugActionViewItem.SEPARATOR, handler: undefined });
|
||||
this.options.push({ label: StartDebugActionViewItem.SEPARATOR, handler: () => Promise.resolve(false) });
|
||||
disabledIdxs.push(this.options.length - 1);
|
||||
}
|
||||
|
||||
manager.getLaunches().filter(l => !l.hidden).forEach(l => {
|
||||
const label = inWorkspace ? nls.localize("addConfigTo", "Add Config ({0})...", l.name) : nls.localize('addConfiguration', "Add Configuration...");
|
||||
this.options.push({
|
||||
label, handler: () => {
|
||||
this.commandService.executeCommand(ADD_CONFIGURATION_ID, l.uri.toString());
|
||||
label, handler: async () => {
|
||||
await this.commandService.executeCommand(ADD_CONFIGURATION_ID, l.uri.toString());
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -7,8 +7,8 @@ import * as nls from 'vs/nls';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IDebugService, State, IEnablement, IBreakpoint, IDebugSession, ILaunch, IConfig } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Variable, Breakpoint, FunctionBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { IDebugService, State, IEnablement, IBreakpoint, IDebugSession, ILaunch } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Variable, Breakpoint, FunctionBreakpoint, Expression } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
@@ -81,8 +81,8 @@ export class ConfigureAction extends AbstractDebugAction {
|
||||
this.class = configurationManager.selectedConfiguration.name ? 'debug-action codicon codicon-gear' : 'debug-action codicon codicon-gear notification';
|
||||
}
|
||||
|
||||
async run(event?: any): Promise<any> {
|
||||
if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
|
||||
async run(): Promise<any> {
|
||||
if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY || this.contextService.getWorkspace().folders.length === 0) {
|
||||
this.notificationService.info(nls.localize('noFolderDebugConfig', "Please first open a folder in order to do advanced debug configuration."));
|
||||
return;
|
||||
}
|
||||
@@ -92,12 +92,12 @@ export class ConfigureAction extends AbstractDebugAction {
|
||||
if (configurationManager.selectedConfiguration.name) {
|
||||
launch = configurationManager.selectedConfiguration.launch;
|
||||
} else {
|
||||
const launches = configurationManager.getLaunches().filter(l => !!l.workspace);
|
||||
const launches = configurationManager.getLaunches().filter(l => !l.hidden);
|
||||
if (launches.length === 1) {
|
||||
launch = launches[0];
|
||||
} else {
|
||||
const picks = launches.map(l => ({ label: l.name, launch: l }));
|
||||
const picked = await this.quickInputService.pick<{ label: string, launch: ILaunch }>(picks, { activeItem: picks[0], placeHolder: nls.localize('selectWorkspaceFolder', "Select a workspace folder to create a launch.json file in") });
|
||||
const picked = await this.quickInputService.pick<{ label: string, launch: ILaunch }>(picks, { activeItem: picks[0], placeHolder: nls.localize('selectWorkspaceFolder', "Select a workspace folder to create a launch.json file in or add it to the workspace config file") });
|
||||
if (picked) {
|
||||
launch = picked.launch;
|
||||
}
|
||||
@@ -105,8 +105,7 @@ export class ConfigureAction extends AbstractDebugAction {
|
||||
}
|
||||
|
||||
if (launch) {
|
||||
const sideBySide = !!(event && (event.ctrlKey || event.metaKey));
|
||||
return launch.openConfigFile(sideBySide, false);
|
||||
return launch.openConfigFile(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,7 +113,6 @@ export class ConfigureAction extends AbstractDebugAction {
|
||||
export class StartAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.start';
|
||||
static LABEL = nls.localize('startDebug', "Start Debugging");
|
||||
static GET_CONFIG_AND_LAUNCH: (() => Promise<{ config: IConfig, launch: ILaunch } | undefined>) | undefined;
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IDebugService debugService: IDebugService,
|
||||
@@ -130,16 +128,8 @@ export class StartAction extends AbstractDebugAction {
|
||||
}
|
||||
|
||||
async run(): Promise<boolean> {
|
||||
if (StartAction.GET_CONFIG_AND_LAUNCH) {
|
||||
const picked = await StartAction.GET_CONFIG_AND_LAUNCH();
|
||||
if (picked) {
|
||||
return this.debugService.startDebugging(picked.launch, picked.config, { noDebug: this.isNoDebug() });
|
||||
}
|
||||
return Promise.resolve(false);
|
||||
} else {
|
||||
let { launch, name } = this.debugService.getConfigurationManager().selectedConfiguration;
|
||||
return this.debugService.startDebugging(launch, name, { noDebug: this.isNoDebug() });
|
||||
}
|
||||
let { launch, name, config } = this.debugService.getConfigurationManager().selectedConfiguration;
|
||||
return this.debugService.startDebugging(launch, config || name, { noDebug: this.isNoDebug() });
|
||||
}
|
||||
|
||||
protected isNoDebug(): boolean {
|
||||
@@ -152,7 +142,10 @@ export class StartAction extends AbstractDebugAction {
|
||||
if (debugService.state === State.Initializing) {
|
||||
return false;
|
||||
}
|
||||
if ((sessions.length > 0) && !debugService.getConfigurationManager().selectedConfiguration.name) {
|
||||
let { name, config } = debugService.getConfigurationManager().selectedConfiguration;
|
||||
let nameToStart = name || config?.name;
|
||||
|
||||
if (sessions.some(s => s.configuration.name === nameToStart)) {
|
||||
// There is already a debug session running and we do not have any launch configuration selected
|
||||
return false;
|
||||
}
|
||||
@@ -390,12 +383,12 @@ export class CopyValueAction extends Action {
|
||||
static readonly LABEL = nls.localize('copyValue', "Copy Value");
|
||||
|
||||
constructor(
|
||||
id: string, label: string, private value: Variable | string, private context: string,
|
||||
id: string, label: string, private value: Variable | Expression, private context: string,
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
@IClipboardService private readonly clipboardService: IClipboardService
|
||||
) {
|
||||
super(id, label, 'debug-action copy-value');
|
||||
this._enabled = typeof this.value === 'string' || (this.value instanceof Variable && !!this.value.evaluateName);
|
||||
super(id, label);
|
||||
this._enabled = (this.value instanceof Expression) || (this.value instanceof Variable && !!this.value.evaluateName);
|
||||
}
|
||||
|
||||
async run(): Promise<any> {
|
||||
@@ -406,7 +399,7 @@ export class CopyValueAction extends Action {
|
||||
}
|
||||
|
||||
const context = session.capabilities.supportsClipboardContext ? 'clipboard' : this.context;
|
||||
const toEvaluate = typeof this.value === 'string' ? this.value : this.value.evaluateName || this.value.value;
|
||||
const toEvaluate = this.value instanceof Variable ? (this.value.evaluateName || this.value.value) : this.value.name;
|
||||
|
||||
try {
|
||||
const evaluation = await session.evaluate(toEvaluate, stackFrame.frameId, context);
|
||||
|
||||
@@ -504,7 +504,7 @@ export function registerCommands(): void {
|
||||
|
||||
const launch = manager.getLaunches().find(l => l.uri.toString() === launchUri) || manager.selectedConfiguration.launch;
|
||||
if (launch) {
|
||||
const { editor, created } = await launch.openConfigFile(false, false);
|
||||
const { editor, created } = await launch.openConfigFile(false);
|
||||
if (editor && !created) {
|
||||
const codeEditor = <ICodeEditor>editor.getControl();
|
||||
if (codeEditor) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import * as json from 'vs/base/common/json';
|
||||
import { URI as uri } from 'vs/base/common/uri';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
@@ -15,14 +16,14 @@ import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IDebugConfigurationProvider, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IDebugAdapterDescriptorFactory, IDebugAdapter, IDebugSession, IAdapterDescriptor, CONTEXT_DEBUG_CONFIGURATION_TYPE, IDebugAdapterFactory, IConfigPresentation } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { Debugger } from 'vs/workbench/contrib/debug/common/debugger';
|
||||
import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { launchSchemaId } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
@@ -45,6 +46,7 @@ jsonRegistry.registerSchema(launchSchemaId, launchSchema);
|
||||
|
||||
const DEBUG_SELECTED_CONFIG_NAME_KEY = 'debug.selectedconfigname';
|
||||
const DEBUG_SELECTED_ROOT = 'debug.selectedroot';
|
||||
const DEBUG_SELECTED_CONFIG = 'debug.selectedconfig';
|
||||
|
||||
export class ConfigurationManager implements IConfigurationManager {
|
||||
private debuggers: Debugger[];
|
||||
@@ -52,6 +54,7 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
private launches!: ILaunch[];
|
||||
private selectedName: string | undefined;
|
||||
private selectedLaunch: ILaunch | undefined;
|
||||
private selectedConfig: IConfig | undefined;
|
||||
private toDispose: IDisposable[];
|
||||
private readonly _onDidSelectConfigurationName = new Emitter<void>();
|
||||
private configProviders: IDebugConfigurationProvider[];
|
||||
@@ -81,10 +84,12 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
const previousSelectedRoot = this.storageService.get(DEBUG_SELECTED_ROOT, StorageScope.WORKSPACE);
|
||||
const previousSelectedLaunch = this.launches.find(l => l.uri.toString() === previousSelectedRoot);
|
||||
this.debugConfigurationTypeContext = CONTEXT_DEBUG_CONFIGURATION_TYPE.bindTo(contextKeyService);
|
||||
const storedConfig = this.storageService.get(DEBUG_SELECTED_CONFIG, StorageScope.WORKSPACE);
|
||||
const selectedConfig = typeof storedConfig === 'string' ? JSON.parse(storedConfig) : undefined;
|
||||
if (previousSelectedLaunch && previousSelectedLaunch.getConfigurationNames().length) {
|
||||
this.selectConfiguration(previousSelectedLaunch, this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE));
|
||||
this.selectConfiguration(previousSelectedLaunch, this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE), selectedConfig);
|
||||
} else if (this.launches.length > 0) {
|
||||
this.selectConfiguration(undefined);
|
||||
this.selectConfiguration(undefined, selectedConfig ? selectedConfig.name : undefined, selectedConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,7 +262,7 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}).filter(e => typeof e === 'string') as string[];
|
||||
}).filter(type => typeof type === 'string' && !!this.getDebuggerLabel(type)) as string[];
|
||||
|
||||
return debugDynamicExtensionsTypes.map(type => {
|
||||
return {
|
||||
@@ -272,13 +277,27 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
picks.push(provider.provideDebugConfigurations!(launch.workspace.uri, token.token).then(configurations => configurations.map(config => ({
|
||||
label: config.name,
|
||||
config,
|
||||
buttons: [{
|
||||
iconClass: 'codicon-gear',
|
||||
tooltip: nls.localize('editLaunchConfig', "Edit Debug Configuration in launch.json")
|
||||
}],
|
||||
launch
|
||||
}))));
|
||||
}
|
||||
});
|
||||
const promiseOfPicks = Promise.all(picks).then(result => result.reduce((first, second) => first.concat(second), []));
|
||||
|
||||
const result = await this.quickInputService.pick<{ label: string, launch: ILaunch, config: IConfig }>(promiseOfPicks, { placeHolder: nls.localize('selectConfiguration', "Select Debug Configuration") });
|
||||
const result = await this.quickInputService.pick<{ label: string, launch: ILaunch, config: IConfig }>(promiseOfPicks, {
|
||||
placeHolder: nls.localize('selectConfiguration', "Select Launch Configuration"),
|
||||
onDidTriggerItemButton: async (context) => {
|
||||
await this.quickInputService.cancel();
|
||||
const { launch, config } = context.item;
|
||||
await launch.openConfigFile(false, config.type);
|
||||
// Only Launch have a pin trigger button
|
||||
await (launch as Launch).writeConfiguration(config);
|
||||
this.selectConfiguration(launch, config.name);
|
||||
}
|
||||
});
|
||||
if (!result) {
|
||||
// User canceled quick input we should notify the provider to cancel computing configurations
|
||||
token.cancel();
|
||||
@@ -385,9 +404,9 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
private initLaunches(): void {
|
||||
this.launches = this.contextService.getWorkspace().folders.map(folder => this.instantiationService.createInstance(Launch, this, folder));
|
||||
if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
|
||||
this.launches.push(this.instantiationService.createInstance(WorkspaceLaunch));
|
||||
this.launches.push(this.instantiationService.createInstance(WorkspaceLaunch, this));
|
||||
}
|
||||
this.launches.push(this.instantiationService.createInstance(UserLaunch));
|
||||
this.launches.push(this.instantiationService.createInstance(UserLaunch, this));
|
||||
|
||||
if (this.selectedLaunch && this.launches.indexOf(this.selectedLaunch) === -1) {
|
||||
this.selectConfiguration(undefined);
|
||||
@@ -419,10 +438,11 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
return this.launches.find(l => l.workspace && l.workspace.uri.toString() === workspaceUri.toString());
|
||||
}
|
||||
|
||||
get selectedConfiguration(): { launch: ILaunch | undefined, name: string | undefined } {
|
||||
get selectedConfiguration(): { launch: ILaunch | undefined, name: string | undefined, config: IConfig | undefined } {
|
||||
return {
|
||||
launch: this.selectedLaunch,
|
||||
name: this.selectedName
|
||||
name: this.selectedName,
|
||||
config: this.selectedConfig
|
||||
};
|
||||
}
|
||||
|
||||
@@ -438,7 +458,7 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
selectConfiguration(launch: ILaunch | undefined, name?: string): void {
|
||||
selectConfiguration(launch: ILaunch | undefined, name?: string, config?: IConfig): void {
|
||||
if (typeof launch === 'undefined') {
|
||||
const rootUri = this.historyService.getLastActiveWorkspaceRoot();
|
||||
launch = this.getLaunch(rootUri);
|
||||
@@ -457,18 +477,19 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
this.storageService.remove(DEBUG_SELECTED_ROOT, StorageScope.WORKSPACE);
|
||||
}
|
||||
const names = launch ? launch.getConfigurationNames() : [];
|
||||
if (name && names.indexOf(name) >= 0) {
|
||||
if ((name && names.indexOf(name) >= 0) || config) {
|
||||
this.setSelectedLaunchName(name);
|
||||
}
|
||||
if (!this.selectedName || names.indexOf(this.selectedName) === -1) {
|
||||
} else if (!this.selectedName || names.indexOf(this.selectedName) === -1) {
|
||||
this.setSelectedLaunchName(names.length ? names[0] : undefined);
|
||||
}
|
||||
|
||||
const configuration = this.selectedLaunch && this.selectedName ? this.selectedLaunch.getConfiguration(this.selectedName) : undefined;
|
||||
if (configuration) {
|
||||
this.debugConfigurationTypeContext.set(configuration.type);
|
||||
this.selectedConfig = config || (this.selectedLaunch && this.selectedName ? this.selectedLaunch.getConfiguration(this.selectedName) : undefined);
|
||||
if (this.selectedConfig) {
|
||||
this.debugConfigurationTypeContext.set(this.selectedConfig.type);
|
||||
this.storageService.store(DEBUG_SELECTED_CONFIG, JSON.stringify(this.selectedConfig), StorageScope.WORKSPACE);
|
||||
} else {
|
||||
this.debugConfigurationTypeContext.reset();
|
||||
this.storageService.remove(DEBUG_SELECTED_CONFIG, StorageScope.WORKSPACE);
|
||||
}
|
||||
|
||||
if (this.selectedLaunch !== previousLaunch || this.selectedName !== previousName) {
|
||||
@@ -565,6 +586,9 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
abstract class AbstractLaunch {
|
||||
protected abstract getConfig(): IGlobalConfig | undefined;
|
||||
|
||||
constructor(protected configurationManager: ConfigurationManager) {
|
||||
}
|
||||
|
||||
getCompound(name: string): ICompound | undefined {
|
||||
const config = this.getConfig();
|
||||
if (!config || !config.compounds) {
|
||||
@@ -605,6 +629,16 @@ abstract class AbstractLaunch {
|
||||
return config.configurations.find(config => config && config.name === name);
|
||||
}
|
||||
|
||||
async getInitialConfigurationContent(folderUri?: uri, type?: string, token?: CancellationToken): Promise<string> {
|
||||
let content = '';
|
||||
const adapter = await this.configurationManager.guessDebugger(type);
|
||||
if (adapter) {
|
||||
const initialConfigs = await this.configurationManager.provideDebugConfigurations(folderUri, adapter.type, token || CancellationToken.None);
|
||||
content = await adapter.getInitialConfigurationContent(initialConfigs);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
get hidden(): boolean {
|
||||
return false;
|
||||
}
|
||||
@@ -613,14 +647,14 @@ abstract class AbstractLaunch {
|
||||
class Launch extends AbstractLaunch implements ILaunch {
|
||||
|
||||
constructor(
|
||||
private configurationManager: ConfigurationManager,
|
||||
configurationManager: ConfigurationManager,
|
||||
public workspace: IWorkspaceFolder,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@ITextFileService private readonly textFileService: ITextFileService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
) {
|
||||
super();
|
||||
super(configurationManager);
|
||||
}
|
||||
|
||||
get uri(): uri {
|
||||
@@ -635,7 +669,7 @@ class Launch extends AbstractLaunch implements ILaunch {
|
||||
return this.configurationService.inspect<IGlobalConfig>('launch', { resource: this.workspace.uri }).workspaceFolderValue;
|
||||
}
|
||||
|
||||
async openConfigFile(sideBySide: boolean, preserveFocus: boolean, type?: string, token?: CancellationToken): Promise<{ editor: IEditorPane | null, created: boolean }> {
|
||||
async openConfigFile(preserveFocus: boolean, type?: string, token?: CancellationToken): Promise<{ editor: IEditorPane | null, created: boolean }> {
|
||||
const resource = this.uri;
|
||||
let created = false;
|
||||
let content = '';
|
||||
@@ -644,12 +678,7 @@ class Launch extends AbstractLaunch implements ILaunch {
|
||||
content = fileContent.value.toString();
|
||||
} catch {
|
||||
// launch.json not found: create one by collecting launch configs from debugConfigProviders
|
||||
const adapter = await this.configurationManager.guessDebugger(type);
|
||||
|
||||
if (adapter) {
|
||||
const initialConfigs = await this.configurationManager.provideDebugConfigurations(this.workspace.uri, adapter.type, token || CancellationToken.None);
|
||||
content = await adapter.getInitialConfigurationContent(initialConfigs);
|
||||
}
|
||||
content = await this.getInitialConfigurationContent(this.workspace.uri, type, token);
|
||||
if (content) {
|
||||
created = true; // pin only if config file is created #8727
|
||||
try {
|
||||
@@ -681,22 +710,29 @@ class Launch extends AbstractLaunch implements ILaunch {
|
||||
pinned: created,
|
||||
revealIfVisible: true
|
||||
},
|
||||
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
|
||||
}, ACTIVE_GROUP);
|
||||
|
||||
return ({
|
||||
editor: withUndefinedAsNull(editor),
|
||||
created
|
||||
});
|
||||
}
|
||||
|
||||
async writeConfiguration(configuration: IConfig): Promise<void> {
|
||||
const fullConfig = objects.deepClone(this.getConfig()!);
|
||||
fullConfig.configurations.push(configuration);
|
||||
await this.configurationService.updateValue('launch', fullConfig, { resource: this.workspace.uri }, ConfigurationTarget.WORKSPACE_FOLDER);
|
||||
}
|
||||
}
|
||||
|
||||
class WorkspaceLaunch extends AbstractLaunch implements ILaunch {
|
||||
constructor(
|
||||
configurationManager: ConfigurationManager,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService
|
||||
) {
|
||||
super();
|
||||
super(configurationManager);
|
||||
}
|
||||
|
||||
get workspace(): undefined {
|
||||
@@ -715,12 +751,22 @@ class WorkspaceLaunch extends AbstractLaunch implements ILaunch {
|
||||
return this.configurationService.inspect<IGlobalConfig>('launch').workspaceValue;
|
||||
}
|
||||
|
||||
async openConfigFile(sideBySide: boolean, preserveFocus: boolean): Promise<{ editor: IEditorPane | null, created: boolean }> {
|
||||
async openConfigFile(preserveFocus: boolean, type?: string, token?: CancellationToken): Promise<{ editor: IEditorPane | null, created: boolean }> {
|
||||
let launchExistInFile = !!this.getConfig();
|
||||
if (!launchExistInFile) {
|
||||
// Launch property in workspace config not found: create one by collecting launch configs from debugConfigProviders
|
||||
let content = await this.getInitialConfigurationContent(undefined, type, token);
|
||||
if (content) {
|
||||
await this.configurationService.updateValue('launch', json.parse(content), ConfigurationTarget.WORKSPACE);
|
||||
} else {
|
||||
return { editor: null, created: false };
|
||||
}
|
||||
}
|
||||
|
||||
const editor = await this.editorService.openEditor({
|
||||
resource: this.contextService.getWorkspace().configuration!,
|
||||
options: { preserveFocus }
|
||||
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
|
||||
}, ACTIVE_GROUP);
|
||||
|
||||
return ({
|
||||
editor: withUndefinedAsNull(editor),
|
||||
@@ -732,10 +778,11 @@ class WorkspaceLaunch extends AbstractLaunch implements ILaunch {
|
||||
class UserLaunch extends AbstractLaunch implements ILaunch {
|
||||
|
||||
constructor(
|
||||
configurationManager: ConfigurationManager,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IPreferencesService private readonly preferencesService: IPreferencesService
|
||||
) {
|
||||
super();
|
||||
super(configurationManager);
|
||||
}
|
||||
|
||||
get workspace(): undefined {
|
||||
@@ -758,7 +805,7 @@ class UserLaunch extends AbstractLaunch implements ILaunch {
|
||||
return this.configurationService.inspect<IGlobalConfig>('launch').userValue;
|
||||
}
|
||||
|
||||
async openConfigFile(_: boolean, preserveFocus: boolean): Promise<{ editor: IEditorPane | null, created: boolean }> {
|
||||
async openConfigFile(preserveFocus: boolean): Promise<{ editor: IEditorPane | null, created: boolean }> {
|
||||
const editor = await this.preferencesService.openGlobalSettings(true, { preserveFocus });
|
||||
return ({
|
||||
editor: withUndefinedAsNull(editor),
|
||||
|
||||
@@ -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, VIEWLET_ID, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, BreakpointWidgetContext, IBreakpoint, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, REPL_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebugService, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE, State, VIEWLET_ID, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, BreakpointWidgetContext, IBreakpoint, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, REPL_VIEW_ID, CONTEXT_STEP_INTO_TARGETS_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
@@ -17,6 +17,9 @@ import { openBreakpointSource } from 'vs/workbench/contrib/debug/browser/breakpo
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { PanelFocusContext } from 'vs/workbench/common/panel';
|
||||
import { IViewsService } from 'vs/workbench/common/views';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { getDomNodePagePosition } from 'vs/base/browser/dom';
|
||||
|
||||
export const TOGGLE_BREAKPOINT_ID = 'editor.debug.action.toggleBreakpoint';
|
||||
class ToggleBreakpointAction extends EditorAction {
|
||||
@@ -78,12 +81,12 @@ class ConditionalBreakpointAction extends EditorAction {
|
||||
}
|
||||
}
|
||||
|
||||
export const TOGGLE_LOG_POINT_ID = 'editor.debug.action.toggleLogPoint';
|
||||
export const ADD_LOG_POINT_ID = 'editor.debug.action.addLogPoint';
|
||||
class LogPointAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: TOGGLE_LOG_POINT_ID,
|
||||
id: ADD_LOG_POINT_ID,
|
||||
label: nls.localize('logPointEditorAction', "Debug: Add Logpoint..."),
|
||||
alias: 'Debug: Add Logpoint...',
|
||||
precondition: undefined
|
||||
@@ -241,6 +244,48 @@ class ShowDebugHoverAction extends EditorAction {
|
||||
}
|
||||
}
|
||||
|
||||
class StepIntoTargetsAction extends EditorAction {
|
||||
|
||||
public static readonly ID = 'editor.debug.action.stepIntoTargets';
|
||||
public static readonly LABEL = nls.localize('stepIntoTargets', "Step Into Targets...");
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: StepIntoTargetsAction.ID,
|
||||
label: StepIntoTargetsAction.LABEL,
|
||||
alias: 'Debug: Step Into Targets...',
|
||||
precondition: ContextKeyExpr.and(CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), EditorContextKeys.editorTextFocus),
|
||||
contextMenuOpts: {
|
||||
group: 'debug',
|
||||
order: 1.5
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
const contextMenuService = accessor.get(IContextMenuService);
|
||||
const session = debugService.getViewModel().focusedSession;
|
||||
const frame = debugService.getViewModel().focusedStackFrame;
|
||||
|
||||
if (session && frame && editor.hasModel()) {
|
||||
const targets = await session.stepInTargets(frame.frameId);
|
||||
const position = editor.getPosition();
|
||||
const cursorCoords = editor.getScrolledVisiblePosition(position);
|
||||
const editorCoords = getDomNodePagePosition(editor.getDomNode());
|
||||
const x = editorCoords.left + cursorCoords.left;
|
||||
const y = editorCoords.top + cursorCoords.top + cursorCoords.height;
|
||||
|
||||
contextMenuService.showContextMenu({
|
||||
getAnchor: () => ({ x, y }),
|
||||
getActions: () => {
|
||||
return targets.map(t => new Action(`stepIntoTarget:${t.id}`, t.label, undefined, true, () => session.stepIn(frame.thread.threadId, t.id)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GoToBreakpointAction extends EditorAction {
|
||||
constructor(private isNext: boolean, opts: IActionOptions) {
|
||||
super(opts);
|
||||
@@ -307,6 +352,7 @@ registerEditorAction(ToggleBreakpointAction);
|
||||
registerEditorAction(ConditionalBreakpointAction);
|
||||
registerEditorAction(LogPointAction);
|
||||
registerEditorAction(RunToCursorAction);
|
||||
registerEditorAction(StepIntoTargetsAction);
|
||||
registerEditorAction(SelectionToReplAction);
|
||||
registerEditorAction(SelectionToWatchExpressionsAction);
|
||||
registerEditorAction(ShowDebugHoverAction);
|
||||
|
||||
@@ -341,7 +341,7 @@ class DebugHoverAccessibilityProvider implements IListAccessibilityProvider<IExp
|
||||
}
|
||||
|
||||
getAriaLabel(element: IExpression): string {
|
||||
return nls.localize('variableAriaLabel', "{0}, value {1}, variables, debug", element.name, element.value);
|
||||
return nls.localize({ key: 'variableAriaLabel', comment: ['Do not translate placholders. Placeholders are name and value of a variable.'] }, "{0}, value {1}, variables, debug", element.name, element.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
|
||||
tooltip: localize('customizeLaunchConfig', "Configure Launch Configuration")
|
||||
}],
|
||||
trigger: () => {
|
||||
config.launch.openConfigFile(false, false);
|
||||
config.launch.openConfigFile(false);
|
||||
|
||||
return TriggerAction.CLOSE_PICKER;
|
||||
},
|
||||
@@ -81,13 +81,18 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
|
||||
// Entries detected configurations
|
||||
const dynamicProviders = await configManager.getDynamicProviders();
|
||||
if (dynamicProviders.length > 0) {
|
||||
picks.push({ type: 'separator', label: localize('contributed', "contributed") });
|
||||
picks.push({
|
||||
type: 'separator', label: localize({
|
||||
key: 'contributed',
|
||||
comment: ['contributed is lower case because it looks better like that in UI. Nothing preceeds it. It is a name of the grouping of debug configurations.']
|
||||
}, "contributed")
|
||||
});
|
||||
}
|
||||
|
||||
dynamicProviders.forEach(provider => {
|
||||
picks.push({
|
||||
label: `$(folder) ${provider.label}...`,
|
||||
ariaLabel: localize('providerAriaLabel', "{0} contributed configurations", provider.label),
|
||||
ariaLabel: localize({ key: 'providerAriaLabel', comment: ['Placeholder stands for the provider label. For example "NodeJS".'] }, "{0} contributed configurations", provider.label),
|
||||
accept: async () => {
|
||||
const pick = await provider.pick();
|
||||
if (pick) {
|
||||
|
||||
@@ -46,6 +46,7 @@ import { IViewsService } from 'vs/workbench/common/views';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { DebugStorage } from 'vs/workbench/contrib/debug/common/debugStorage';
|
||||
import { DebugTelemetry } from 'vs/workbench/contrib/debug/common/debugTelemetry';
|
||||
import { DebugCompoundRoot } from 'vs/workbench/contrib/debug/common/debugCompoundRoot';
|
||||
|
||||
export class DebugService implements IDebugService {
|
||||
_serviceBrand: undefined;
|
||||
@@ -305,6 +306,9 @@ export class DebugService implements IDebugService {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (compound.stopAll) {
|
||||
options = { ...options, compoundRoot: new DebugCompoundRoot() };
|
||||
}
|
||||
|
||||
const values = await Promise.all(compound.configurations.map(configData => {
|
||||
const name = typeof configData === 'string' ? configData : configData.name;
|
||||
@@ -405,7 +409,7 @@ export class DebugService implements IDebugService {
|
||||
const cfg = await this.configurationManager.resolveDebugConfigurationWithSubstitutedVariables(launch && launch.workspace ? launch.workspace.uri : undefined, type, resolvedConfig, initCancellationToken.token);
|
||||
if (!cfg) {
|
||||
if (launch && type && cfg === null && !initCancellationToken.token.isCancellationRequested) { // show launch.json only for "config" being "null".
|
||||
await launch.openConfigFile(false, true, type, initCancellationToken.token);
|
||||
await launch.openConfigFile(true, type, initCancellationToken.token);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -439,7 +443,7 @@ export class DebugService implements IDebugService {
|
||||
await this.showError(nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved and that you have a debug extension installed for that file type."));
|
||||
}
|
||||
if (launch && !initCancellationToken.token.isCancellationRequested) {
|
||||
await launch.openConfigFile(false, true, undefined, initCancellationToken.token);
|
||||
await launch.openConfigFile(true, undefined, initCancellationToken.token);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -447,7 +451,7 @@ export class DebugService implements IDebugService {
|
||||
}
|
||||
|
||||
if (launch && type && configByProviders === null && !initCancellationToken.token.isCancellationRequested) { // show launch.json only for "config" being "null".
|
||||
await launch.openConfigFile(false, true, type, initCancellationToken.token);
|
||||
await launch.openConfigFile(true, type, initCancellationToken.token);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -35,6 +35,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { localize } from 'vs/nls';
|
||||
import { canceled } from 'vs/base/common/errors';
|
||||
import { filterExceptionsFromTelemetry } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
|
||||
export class DebugSession implements IDebugSession {
|
||||
|
||||
@@ -97,6 +98,11 @@ export class DebugSession implements IDebugSession {
|
||||
dispose(toDispose);
|
||||
}));
|
||||
}
|
||||
|
||||
const compoundRoot = this._options.compoundRoot;
|
||||
if (compoundRoot) {
|
||||
toDispose.push(compoundRoot.onDidSessionStop(() => this.terminate()));
|
||||
}
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
@@ -279,6 +285,10 @@ export class DebugSession implements IDebugSession {
|
||||
} else {
|
||||
await this.raw.disconnect(restart);
|
||||
}
|
||||
|
||||
if (!restart) {
|
||||
this._options.compoundRoot?.sessionStopped();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -291,6 +301,10 @@ export class DebugSession implements IDebugSession {
|
||||
|
||||
this.cancelAllRequests();
|
||||
await this.raw.disconnect(restart);
|
||||
|
||||
if (!restart) {
|
||||
this._options.compoundRoot?.sessionStopped();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -366,7 +380,7 @@ export class DebugSession implements IDebugSession {
|
||||
}
|
||||
}
|
||||
|
||||
async dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean }> {
|
||||
async dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean } | undefined> {
|
||||
if (!this.raw) {
|
||||
throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'data breakpoints info'));
|
||||
}
|
||||
@@ -488,12 +502,12 @@ export class DebugSession implements IDebugSession {
|
||||
await this.raw.next({ threadId });
|
||||
}
|
||||
|
||||
async stepIn(threadId: number): Promise<void> {
|
||||
async stepIn(threadId: number, targetId?: number): Promise<void> {
|
||||
if (!this.raw) {
|
||||
throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'stepIn'));
|
||||
}
|
||||
|
||||
await this.raw.stepIn({ threadId });
|
||||
await this.raw.stepIn({ threadId, targetId });
|
||||
}
|
||||
|
||||
async stepOut(threadId: number): Promise<void> {
|
||||
@@ -592,7 +606,7 @@ export class DebugSession implements IDebugSession {
|
||||
}
|
||||
|
||||
const response = await this.raw.loadedSources({});
|
||||
if (response.body && response.body.sources) {
|
||||
if (response && response.body && response.body.sources) {
|
||||
return response.body.sources.map(src => this.getSource(src));
|
||||
} else {
|
||||
return [];
|
||||
@@ -612,6 +626,15 @@ export class DebugSession implements IDebugSession {
|
||||
}, token);
|
||||
}
|
||||
|
||||
async stepInTargets(frameId: number): Promise<{ id: number, label: string }[]> {
|
||||
if (!this.raw) {
|
||||
return Promise.reject(new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'stepInTargets')));
|
||||
}
|
||||
|
||||
const response = await this.raw.stepInTargets({ frameId });
|
||||
return response.body.targets;
|
||||
}
|
||||
|
||||
async cancel(progressId: string): Promise<DebugProtocol.CancelResponse> {
|
||||
if (!this.raw) {
|
||||
return Promise.reject(new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'cancel')));
|
||||
@@ -735,6 +758,7 @@ export class DebugSession implements IDebugSession {
|
||||
await this.raw.configurationDone();
|
||||
} catch (e) {
|
||||
// Disconnect the debug session on configuration done error #10596
|
||||
this.notificationService.error(e);
|
||||
if (this.raw) {
|
||||
this.raw.disconnect();
|
||||
}
|
||||
@@ -847,7 +871,12 @@ export class DebugSession implements IDebugSession {
|
||||
// and the user opted in telemetry
|
||||
if (this.raw.customTelemetryService && this.telemetryService.isOptedIn) {
|
||||
// __GDPR__TODO__ We're sending events in the name of the debug extension and we can not ensure that those are declared correctly.
|
||||
this.raw.customTelemetryService.publicLog(event.body.output, event.body.data);
|
||||
let data = event.body.data;
|
||||
if (!this.raw.customTelemetryService.sendErrorTelemetry && event.body.data) {
|
||||
data = filterExceptionsFromTelemetry(event.body.data);
|
||||
}
|
||||
|
||||
this.raw.customTelemetryService.publicLog(event.body.output, data);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
.monaco-editor .debug-hover-widget .debug-hover-tree .monaco-list-row .monaco-tl-contents {
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
/* Disable tree highlight in debug hover tree. */
|
||||
@@ -56,7 +57,6 @@
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .value {
|
||||
white-space: pre-wrap;
|
||||
color: rgba(108, 108, 108, 0.8);
|
||||
overflow: auto;
|
||||
font-family: var(--monaco-monospace-font);
|
||||
|
||||
@@ -82,7 +82,8 @@
|
||||
|
||||
/* Call stack */
|
||||
|
||||
.debug-pane .debug-call-stack-title {
|
||||
.debug-pane.expanded .debug-call-stack-title,
|
||||
.debug-pane.vertical .debug-call-stack-title {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -5,19 +5,19 @@
|
||||
|
||||
/* Debug repl */
|
||||
|
||||
.repl {
|
||||
.monaco-workbench .repl {
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.repl .repl-tree .monaco-tl-contents {
|
||||
.monaco-workbench .repl .repl-tree .monaco-tl-contents {
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.repl .repl-tree.word-wrap .monaco-tl-contents {
|
||||
.monaco-workbench .repl .repl-tree.word-wrap .monaco-tl-contents {
|
||||
/* Wrap words but also do not trim whitespace #6275 */
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
@@ -30,25 +30,20 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.repl .repl-tree .output.expression.value-and-source {
|
||||
.monaco-workbench .repl .repl-tree .output.expression.value-and-source {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.repl .repl-tree .output.expression.value-and-source .value {
|
||||
.monaco-workbench .repl .repl-tree .output.expression.value-and-source .value {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.repl .repl-tree .monaco-tl-contents .arrow {
|
||||
.monaco-workbench .repl .repl-tree .monaco-tl-contents .arrow {
|
||||
position:absolute;
|
||||
left: 2px;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.vs-dark .repl .repl-tree .monaco-tl-contents .arrow {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.repl .repl-tree .output.expression.value-and-source .source {
|
||||
.monaco-workbench .repl .repl-tree .output.expression.value-and-source .source {
|
||||
margin-left: 4px;
|
||||
margin-right: 8px;
|
||||
cursor: pointer;
|
||||
@@ -59,36 +54,21 @@
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.repl .repl-tree .monaco-list-row {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.repl .repl-tree .output.expression > .value,
|
||||
.repl .repl-tree .evaluation-result.expression > .value {
|
||||
.monaco-workbench .repl .repl-tree .output.expression > .value,
|
||||
.monaco-workbench .repl .repl-tree .evaluation-result.expression > .value {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.repl .repl-tree .output.expression > .annotation,
|
||||
.repl .repl-tree .evaluation-result.expression > .annotation {
|
||||
font-size: inherit;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
.repl .repl-tree .output.expression .name:not(:empty) {
|
||||
.monaco-workbench .repl .repl-tree .output.expression .name:not(:empty) {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.repl .repl-input-wrapper {
|
||||
.monaco-workbench .repl .repl-input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Only show 'stale expansion' info when the element gets expanded. */
|
||||
.repl .repl-tree .evaluation-result > .annotation::before {
|
||||
content: '';
|
||||
}
|
||||
|
||||
.repl .repl-input-wrapper .repl-input-chevron {
|
||||
.monaco-workbench .repl .repl-input-wrapper .repl-input-chevron {
|
||||
padding: 0 6px 0 8px;
|
||||
width: 16px;
|
||||
height: 100%;
|
||||
@@ -99,34 +79,10 @@
|
||||
}
|
||||
|
||||
/* Output coloring and styling */
|
||||
.repl .repl-tree .output.expression > .ignore {
|
||||
.monaco-workbench .repl .repl-tree .output.expression > .ignore {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.vs .repl .repl-tree .output.expression > .annotation {
|
||||
color: #007ACC;
|
||||
}
|
||||
|
||||
.vs-dark .repl .repl-tree .output.expression > .annotation {
|
||||
color: #1B80B2;
|
||||
}
|
||||
|
||||
.hc-black .repl .repl-tree .output.expression > .annotation {
|
||||
color: #0000FF;
|
||||
}
|
||||
|
||||
.vs .repl .repl-tree .output.expression > .warn {
|
||||
color: #cd9731;
|
||||
}
|
||||
|
||||
.vs-dark .repl .repl-tree .output.expression > .warn {
|
||||
color: #cd9731;
|
||||
}
|
||||
|
||||
.hc-black .repl .repl-tree .output.expression > .warn {
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
/* ANSI Codes */
|
||||
.monaco-workbench .repl .repl-tree .output.expression .code-bold { font-weight: bold; }
|
||||
.monaco-workbench .repl .repl-tree .output.expression .code-italic { font-style: italic; }
|
||||
|
||||
@@ -349,6 +349,13 @@ export class RawDebugSession implements IDisposable {
|
||||
return Promise.reject(new Error('restartFrame not supported'));
|
||||
}
|
||||
|
||||
stepInTargets(args: DebugProtocol.StepInTargetsArguments): Promise<DebugProtocol.StepInTargetsResponse> {
|
||||
if (this.capabilities.supportsStepInTargetsRequest) {
|
||||
return this.send('stepInTargets', args);
|
||||
}
|
||||
return Promise.reject(new Error('stepInTargets not supported'));
|
||||
}
|
||||
|
||||
completions(args: DebugProtocol.CompletionsArguments, token: CancellationToken): Promise<DebugProtocol.CompletionsResponse> {
|
||||
if (this.capabilities.supportsCompletionsRequest) {
|
||||
return this.send<DebugProtocol.CompletionsResponse>('completions', args, token);
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import 'vs/css!./media/repl';
|
||||
import { URI as uri } from 'vs/base/common/uri';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { IAction, IActionViewItem, Action } from 'vs/base/common/actions';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
@@ -21,7 +20,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { dispose, IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
@@ -34,7 +33,7 @@ import { createAndBindHistoryNavigationWidgetScopedContextKeyService } from 'vs/
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { getSimpleEditorOptions, getSimpleCodeEditorWidgetOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions';
|
||||
import { IDecorationOptions } from 'vs/editor/common/editorCommon';
|
||||
import { transparent, editorForeground, inputBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { transparent, editorForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems';
|
||||
import { CompletionContext, CompletionList, CompletionProviderRegistry, CompletionItem, completionKindFromString, CompletionItemKind, CompletionItemInsertTextRule } from 'vs/editor/common/modes';
|
||||
@@ -60,6 +59,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { ReplGroup } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { EDITOR_FONT_DEFAULTS, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -87,7 +87,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
|
||||
private replInputContainer!: HTMLElement;
|
||||
private dimension!: dom.Dimension;
|
||||
private replInputLineCount = 1;
|
||||
private model!: ITextModel;
|
||||
private model: ITextModel | undefined;
|
||||
private historyNavigationEnablement!: IContextKey<boolean>;
|
||||
private scopedInstantiationService!: IInstantiationService;
|
||||
private replElementsChangeListener: IDisposable | undefined;
|
||||
@@ -271,7 +271,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
|
||||
if (isCodeEditor(activeEditorControl)) {
|
||||
this.modelChangeListener.dispose();
|
||||
this.modelChangeListener = activeEditorControl.onDidChangeModelLanguage(() => this.setMode());
|
||||
if (activeEditorControl.hasModel()) {
|
||||
if (this.model && activeEditorControl.hasModel()) {
|
||||
this.model.setMode(activeEditorControl.getModel().getLanguageIdentifier());
|
||||
}
|
||||
}
|
||||
@@ -397,16 +397,18 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
|
||||
|
||||
getVisibleContent(): string {
|
||||
let text = '';
|
||||
const lineDelimiter = this.textResourcePropertiesService.getEOL(this.model.uri);
|
||||
const traverseAndAppend = (node: ITreeNode<IReplElement, FuzzyScore>) => {
|
||||
node.children.forEach(child => {
|
||||
text += child.element.toString().trimRight() + lineDelimiter;
|
||||
if (!child.collapsed && child.children.length) {
|
||||
traverseAndAppend(child);
|
||||
}
|
||||
});
|
||||
};
|
||||
traverseAndAppend(this.tree.getNode());
|
||||
if (this.model) {
|
||||
const lineDelimiter = this.textResourcePropertiesService.getEOL(this.model.uri);
|
||||
const traverseAndAppend = (node: ITreeNode<IReplElement, FuzzyScore>) => {
|
||||
node.children.forEach(child => {
|
||||
text += child.element.toString().trimRight() + lineDelimiter;
|
||||
if (!child.collapsed && child.children.length) {
|
||||
traverseAndAppend(child);
|
||||
}
|
||||
});
|
||||
};
|
||||
traverseAndAppend(this.tree.getNode());
|
||||
}
|
||||
|
||||
return removeAnsiEscapeCodes(text);
|
||||
}
|
||||
@@ -508,7 +510,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
|
||||
super.renderBody(parent);
|
||||
|
||||
this.container = dom.append(parent, $('.repl'));
|
||||
const treeContainer = dom.append(this.container, $('.repl-tree'));
|
||||
const treeContainer = dom.append(this.container, $(`.repl-tree.${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME}`));
|
||||
this.createReplInput(this.container);
|
||||
|
||||
this.replDelegate = new ReplDelegate(this.configurationService);
|
||||
@@ -812,13 +814,3 @@ export class ClearReplAction extends Action {
|
||||
function getReplView(viewsService: IViewsService): Repl | undefined {
|
||||
return viewsService.getActiveViewWithId(REPL_VIEW_ID) as Repl ?? undefined;
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const inputBorderColor = theme.getColor(inputBorder) || Color.fromHex('#80808060');
|
||||
|
||||
collector.addRule(`
|
||||
.repl .repl-input-wrapper {
|
||||
border-top: 1px solid ${inputBorderColor};
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
@@ -23,7 +23,6 @@ import { IReplElementSource, IDebugService, IExpression, IReplElement, IDebugCon
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -37,7 +36,6 @@ interface IReplGroupTemplateData {
|
||||
|
||||
interface IReplEvaluationResultTemplateData {
|
||||
value: HTMLElement;
|
||||
annotation: HTMLElement;
|
||||
}
|
||||
|
||||
interface ISimpleReplElementTemplateData {
|
||||
@@ -53,7 +51,6 @@ interface IRawObjectReplTemplateData {
|
||||
expression: HTMLElement;
|
||||
name: HTMLElement;
|
||||
value: HTMLElement;
|
||||
annotation: HTMLElement;
|
||||
label: HighlightedLabel;
|
||||
}
|
||||
|
||||
@@ -116,9 +113,8 @@ export class ReplEvaluationResultsRenderer implements ITreeRenderer<ReplEvaluati
|
||||
renderTemplate(container: HTMLElement): IReplEvaluationResultTemplateData {
|
||||
const output = dom.append(container, $('.evaluation-result.expression'));
|
||||
const value = dom.append(output, $('span.value'));
|
||||
const annotation = dom.append(output, $('span'));
|
||||
|
||||
return { value, annotation };
|
||||
return { value };
|
||||
}
|
||||
|
||||
renderElement(element: ITreeNode<ReplEvaluationResult, FuzzyScore>, index: number, templateData: IReplEvaluationResultTemplateData): void {
|
||||
@@ -128,10 +124,6 @@ export class ReplEvaluationResultsRenderer implements ITreeRenderer<ReplEvaluati
|
||||
colorize: true,
|
||||
linkDetector: this.linkDetector
|
||||
});
|
||||
if (expression.hasChildren) {
|
||||
templateData.annotation.className = 'annotation ' + Codicon.info.classNames;
|
||||
templateData.annotation.title = localize('stateCapture', "Object state is captured from first evaluation");
|
||||
}
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IReplEvaluationResultTemplateData): void {
|
||||
@@ -240,9 +232,8 @@ export class ReplRawObjectsRenderer implements ITreeRenderer<RawObjectReplElemen
|
||||
const name = dom.append(expression, $('span.name'));
|
||||
const label = new HighlightedLabel(name, false);
|
||||
const value = dom.append(expression, $('span.value'));
|
||||
const annotation = dom.append(expression, $('span'));
|
||||
|
||||
return { container, expression, name, label, value, annotation };
|
||||
return { container, expression, name, label, value };
|
||||
}
|
||||
|
||||
renderElement(node: ITreeNode<RawObjectReplElement, FuzzyScore>, index: number, templateData: IRawObjectReplTemplateData): void {
|
||||
@@ -260,15 +251,6 @@ export class ReplRawObjectsRenderer implements ITreeRenderer<RawObjectReplElemen
|
||||
showHover: false,
|
||||
linkDetector: this.linkDetector
|
||||
});
|
||||
|
||||
// annotation if any
|
||||
if (element.annotation) {
|
||||
templateData.annotation.className = 'annotation ' + Codicon.info.classNames;
|
||||
templateData.annotation.title = element.annotation;
|
||||
} else {
|
||||
templateData.annotation.className = '';
|
||||
templateData.annotation.title = '';
|
||||
}
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IRawObjectReplTemplateData): void {
|
||||
|
||||
@@ -194,8 +194,8 @@ export class VariablesView extends ViewPane {
|
||||
}
|
||||
if (session && session.capabilities.supportsDataBreakpoints) {
|
||||
const response = await session.dataBreakpointInfo(variable.name, variable.parent.reference);
|
||||
const dataid = response.dataId;
|
||||
if (dataid) {
|
||||
const dataid = response?.dataId;
|
||||
if (response && dataid) {
|
||||
actions.push(new Separator());
|
||||
actions.push(new Action('debug.breakWhenValueChanges', nls.localize('breakWhenValueChanges', "Break When Value Changes"), undefined, true, () => {
|
||||
return this.debugService.addDataBreakpoint(response.description, dataid, !!response.canPersist, response.accessTypes);
|
||||
@@ -359,7 +359,7 @@ class VariablesAccessibilityProvider implements IListAccessibilityProvider<IExpr
|
||||
return nls.localize('variableScopeAriaLabel', "Scope {0}", element.name);
|
||||
}
|
||||
if (element instanceof Variable) {
|
||||
return nls.localize('variableAriaLabel', "{0}, value {1}", element.name, element.value);
|
||||
return nls.localize({ key: 'variableAriaLabel', comment: ['Placeholders are variable name and variable value respectivly. They should not be translated.'] }, "{0}, value {1}", element.name, element.value);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -189,7 +189,7 @@ export class WatchExpressionsView extends ViewPane {
|
||||
this.debugService.getViewModel().setSelectedExpression(expression);
|
||||
return Promise.resolve();
|
||||
}));
|
||||
actions.push(this.instantiationService.createInstance(CopyValueAction, CopyValueAction.ID, CopyValueAction.LABEL, expression.value, 'watch'));
|
||||
actions.push(this.instantiationService.createInstance(CopyValueAction, CopyValueAction.ID, CopyValueAction.LABEL, expression, 'watch'));
|
||||
actions.push(new Separator());
|
||||
|
||||
actions.push(new Action('debug.removeWatchExpression', nls.localize('removeWatchExpression', "Remove Expression"), undefined, true, () => {
|
||||
|
||||
@@ -10,12 +10,12 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { localize } from 'vs/nls';
|
||||
import { StartAction, ConfigureAction } from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
import { StartAction, ConfigureAction, SelectAndStartAction } from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
import { IDebugService } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IViewDescriptorService, IViewsRegistry, Extensions } from 'vs/workbench/common/views';
|
||||
import { IViewDescriptorService, IViewsRegistry, Extensions, ViewContentPriority } from 'vs/workbench/common/views';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { WorkbenchStateContext } from 'vs/workbench/browser/contextkeys';
|
||||
@@ -119,6 +119,12 @@ viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, {
|
||||
preconditions: [CONTEXT_DEBUGGER_INTERESTED_IN_ACTIVE_EDITOR]
|
||||
});
|
||||
|
||||
viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, {
|
||||
content: localize({ key: 'detectThenRunAndDebug', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
|
||||
"[Show](command:{0}) all automatic debug configurations.", SelectAndStartAction.ID),
|
||||
priority: ViewContentPriority.Lowest
|
||||
});
|
||||
|
||||
viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, {
|
||||
content: localize({ key: 'customizeRunAndDebug', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] },
|
||||
"To customize Run and Debug [create a launch.json file](command:{0}).", ConfigureAction.ID),
|
||||
|
||||
@@ -24,6 +24,7 @@ import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { DebugConfigurationProviderTriggerKind } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { DebugCompoundRoot } from 'vs/workbench/contrib/debug/common/debugCompoundRoot';
|
||||
|
||||
export const VIEWLET_ID = 'workbench.view.debug';
|
||||
|
||||
@@ -56,6 +57,7 @@ export const CONTEXT_FOCUSED_SESSION_IS_ATTACH = new RawContextKey<boolean>('foc
|
||||
export const CONTEXT_STEP_BACK_SUPPORTED = new RawContextKey<boolean>('stepBackSupported', false);
|
||||
export const CONTEXT_RESTART_FRAME_SUPPORTED = new RawContextKey<boolean>('restartFrameSupported', false);
|
||||
export const CONTEXT_JUMP_TO_CURSOR_SUPPORTED = new RawContextKey<boolean>('jumpToCursorSupported', false);
|
||||
export const CONTEXT_STEP_INTO_TARGETS_SUPPORTED = new RawContextKey<boolean>('stepIntoTargetsSupported', false);
|
||||
export const CONTEXT_BREAKPOINTS_EXIST = new RawContextKey<boolean>('breakpointsExist', false);
|
||||
|
||||
export const EDITOR_CONTRIBUTION_ID = 'editor.contrib.debug';
|
||||
@@ -154,6 +156,7 @@ export interface IDebugSessionOptions {
|
||||
noDebug?: boolean;
|
||||
parentSession?: IDebugSession;
|
||||
repl?: IDebugSessionReplMode;
|
||||
compoundRoot?: DebugCompoundRoot;
|
||||
}
|
||||
|
||||
export interface IDebugSession extends ITreeElement {
|
||||
@@ -214,7 +217,7 @@ export interface IDebugSession extends ITreeElement {
|
||||
|
||||
sendBreakpoints(modelUri: uri, bpts: IBreakpoint[], sourceModified: boolean): Promise<void>;
|
||||
sendFunctionBreakpoints(fbps: IFunctionBreakpoint[]): Promise<void>;
|
||||
dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean, accessTypes?: DebugProtocol.DataBreakpointAccessType[] }>;
|
||||
dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean, accessTypes?: DebugProtocol.DataBreakpointAccessType[] } | undefined>;
|
||||
sendDataBreakpoints(dbps: IDataBreakpoint[]): Promise<void>;
|
||||
sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): Promise<void>;
|
||||
breakpointsLocations(uri: uri, lineNumber: number): Promise<IPosition[]>;
|
||||
@@ -229,7 +232,7 @@ export interface IDebugSession extends ITreeElement {
|
||||
|
||||
restartFrame(frameId: number, threadId: number): Promise<void>;
|
||||
next(threadId: number): Promise<void>;
|
||||
stepIn(threadId: number): Promise<void>;
|
||||
stepIn(threadId: number, targetId?: number): Promise<void>;
|
||||
stepOut(threadId: number): Promise<void>;
|
||||
stepBack(threadId: number): Promise<void>;
|
||||
continue(threadId: number): Promise<void>;
|
||||
@@ -237,6 +240,7 @@ export interface IDebugSession extends ITreeElement {
|
||||
pause(threadId: number): Promise<void>;
|
||||
terminateThreads(threadIds: number[]): Promise<void>;
|
||||
|
||||
stepInTargets(frameId: number): Promise<{ id: number, label: string }[]>;
|
||||
completions(frameId: number | undefined, text: string, position: Position, overwriteBefore: number, token: CancellationToken): Promise<DebugProtocol.CompletionsResponse>;
|
||||
setVariable(variablesReference: number | undefined, name: string, value: string): Promise<DebugProtocol.SetVariableResponse>;
|
||||
loadSource(resource: uri): Promise<DebugProtocol.SourceResponse>;
|
||||
@@ -516,6 +520,7 @@ export interface IConfig extends IEnvConfig {
|
||||
|
||||
export interface ICompound {
|
||||
name: string;
|
||||
stopAll?: boolean;
|
||||
preLaunchTask?: string | TaskIdentifier;
|
||||
configurations: (string | { name: string, folder: string })[];
|
||||
presentation?: IConfigPresentation;
|
||||
@@ -633,10 +638,11 @@ export interface IConfigurationManager {
|
||||
*/
|
||||
readonly selectedConfiguration: {
|
||||
launch: ILaunch | undefined;
|
||||
config: IConfig | undefined;
|
||||
name: string | undefined;
|
||||
};
|
||||
|
||||
selectConfiguration(launch: ILaunch | undefined, name?: string, debugStarted?: boolean): void;
|
||||
selectConfiguration(launch: ILaunch | undefined, name?: string, config?: IConfig): void;
|
||||
|
||||
getLaunches(): ReadonlyArray<ILaunch>;
|
||||
|
||||
@@ -717,7 +723,7 @@ export interface ILaunch {
|
||||
/**
|
||||
* Opens the launch.json file. Creates if it does not exist.
|
||||
*/
|
||||
openConfigFile(sideBySide: boolean, preserveFocus: boolean, type?: string, token?: CancellationToken): Promise<{ editor: IEditorPane | null, created: boolean }>;
|
||||
openConfigFile(preserveFocus: boolean, type?: string, token?: CancellationToken): Promise<{ editor: IEditorPane | null, created: boolean }>;
|
||||
}
|
||||
|
||||
// Debug service interfaces
|
||||
|
||||
20
src/vs/workbench/contrib/debug/common/debugCompoundRoot.ts
Normal file
20
src/vs/workbench/contrib/debug/common/debugCompoundRoot.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
export class DebugCompoundRoot {
|
||||
private stopped = false;
|
||||
private stopEmitter = new Emitter<void>();
|
||||
|
||||
onDidSessionStop = this.stopEmitter.event;
|
||||
|
||||
sessionStopped(): void {
|
||||
if (!this.stopped) { // avoid sending extranous terminate events
|
||||
this.stopped = true;
|
||||
this.stopEmitter.fire();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,6 +215,11 @@ export const launchSchema: IJSONSchema = {
|
||||
},
|
||||
description: nls.localize('app.launch.json.compounds.configurations', "Names of configurations that will be started as part of this compound.")
|
||||
},
|
||||
stopAll: {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: nls.localize('app.launch.json.compound.stopAll', "Controls whether manually terminating one session will stop all of the compound sessions.")
|
||||
},
|
||||
preLaunchTask: {
|
||||
type: 'string',
|
||||
default: '',
|
||||
|
||||
@@ -23,6 +23,22 @@ export function formatPII(value: string, excludePII: boolean, args: { [key: stri
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters exceptions (keys marked with "!") from the given object. Used to
|
||||
* ensure exception data is not sent on web remotes, see #97628.
|
||||
*/
|
||||
export function filterExceptionsFromTelemetry<T extends { [key: string]: unknown }>(data: T): Partial<T> {
|
||||
const output: Partial<T> = {};
|
||||
for (const key of Object.keys(data) as (keyof T & string)[]) {
|
||||
if (!key.startsWith('!')) {
|
||||
output[key] = data[key];
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
export function isSessionAttach(session: IDebugSession): boolean {
|
||||
return session.configuration.request === 'attach' && !getExtensionHostDebugSession(session);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { CONTEXT_EXPRESSION_SELECTED, IViewModel, IStackFrame, IDebugSession, IThread, IExpression, IFunctionBreakpoint, CONTEXT_BREAKPOINT_SELECTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { CONTEXT_EXPRESSION_SELECTED, IViewModel, IStackFrame, IDebugSession, IThread, IExpression, IFunctionBreakpoint, CONTEXT_BREAKPOINT_SELECTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_STEP_INTO_TARGETS_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { isSessionAttach } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
|
||||
@@ -27,6 +27,7 @@ export class ViewModel implements IViewModel {
|
||||
private stepBackSupportedContextKey: IContextKey<boolean>;
|
||||
private focusedSessionIsAttach: IContextKey<boolean>;
|
||||
private restartFrameSupportedContextKey: IContextKey<boolean>;
|
||||
private stepIntoTargetsSupported: IContextKey<boolean>;
|
||||
private jumpToCursorSupported: IContextKey<boolean>;
|
||||
|
||||
constructor(contextKeyService: IContextKeyService) {
|
||||
@@ -37,6 +38,7 @@ export class ViewModel implements IViewModel {
|
||||
this.stepBackSupportedContextKey = CONTEXT_STEP_BACK_SUPPORTED.bindTo(contextKeyService);
|
||||
this.focusedSessionIsAttach = CONTEXT_FOCUSED_SESSION_IS_ATTACH.bindTo(contextKeyService);
|
||||
this.restartFrameSupportedContextKey = CONTEXT_RESTART_FRAME_SUPPORTED.bindTo(contextKeyService);
|
||||
this.stepIntoTargetsSupported = CONTEXT_STEP_INTO_TARGETS_SUPPORTED.bindTo(contextKeyService);
|
||||
this.jumpToCursorSupported = CONTEXT_JUMP_TO_CURSOR_SUPPORTED.bindTo(contextKeyService);
|
||||
}
|
||||
|
||||
@@ -67,6 +69,7 @@ export class ViewModel implements IViewModel {
|
||||
this.loadedScriptsSupportedContextKey.set(session ? !!session.capabilities.supportsLoadedSourcesRequest : false);
|
||||
this.stepBackSupportedContextKey.set(session ? !!session.capabilities.supportsStepBack : false);
|
||||
this.restartFrameSupportedContextKey.set(session ? !!session.capabilities.supportsRestartFrame : false);
|
||||
this.stepIntoTargetsSupported.set(session ? !!session.capabilities.supportsStepInTargetsRequest : false);
|
||||
this.jumpToCursorSupported.set(session ? !!session.capabilities.supportsGotoTargetsRequest : false);
|
||||
const attach = !!session && isSessionAttach(session);
|
||||
this.focusedSessionIsAttach.set(attach);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
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 { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
|
||||
import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
|
||||
|
||||
export class ExtensionHostDebugService extends ExtensionHostDebugChannelClient {
|
||||
@@ -10,10 +10,17 @@ import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
|
||||
export class NodeDebugHelperService implements IDebugHelperService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||
) { }
|
||||
|
||||
|
||||
createTelemetryService(configurationService: IConfigurationService, args: string[]): TelemetryService | undefined {
|
||||
|
||||
const client = new TelemetryClient(
|
||||
@@ -33,7 +40,10 @@ export class NodeDebugHelperService implements IDebugHelperService {
|
||||
const channel = client.getChannel('telemetryAppender');
|
||||
const appender = new TelemetryAppenderClient(channel);
|
||||
|
||||
return new TelemetryService({ appender, sendErrorTelemetry: true }, configurationService);
|
||||
return new TelemetryService({
|
||||
appender,
|
||||
sendErrorTelemetry: cleanRemoteAuthority(this.environmentService.configuration.remoteAuthority) !== 'other'
|
||||
}, configurationService);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ export function prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments
|
||||
case ShellType.bash:
|
||||
|
||||
quote = (s: string) => {
|
||||
s = s.replace(/(["'\\])/g, '\\$1');
|
||||
s = s.replace(/(["'\\\$])/g, '\\$1');
|
||||
return (s.indexOf(' ') >= 0 || s.indexOf(';') >= 0 || s.length === 0) ? `"${s}"` : s;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { MockDebugAdapter, createMockDebugModel } from 'vs/workbench/contrib/debug/test/common/mockDebug';
|
||||
import { DebugModel } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { NullOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { RawDebugSession } from 'vs/workbench/contrib/debug/browser/rawDebugSession';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { stub, SinonStub } from 'sinon';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
suite('Debug - DebugSession telemetry', () => {
|
||||
let model: DebugModel;
|
||||
let session: DebugSession;
|
||||
let adapter: MockDebugAdapter;
|
||||
let telemetry: { isOptedIn: boolean; sendErrorTelemetry: boolean; publicLog: SinonStub };
|
||||
|
||||
setup(() => {
|
||||
telemetry = { isOptedIn: true, sendErrorTelemetry: true, publicLog: stub() };
|
||||
adapter = new MockDebugAdapter();
|
||||
model = createMockDebugModel();
|
||||
|
||||
const telemetryService = telemetry as Partial<ITelemetryService> as ITelemetryService;
|
||||
session = new DebugSession(generateUuid(), undefined!, undefined!, model, undefined, undefined!, telemetryService, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService, undefined!, undefined!);
|
||||
session.initializeForTest(new RawDebugSession(adapter, undefined!, undefined!, telemetryService, undefined!, undefined!, undefined!));
|
||||
});
|
||||
|
||||
test('does not send telemetry when opted out', async () => {
|
||||
telemetry.isOptedIn = false;
|
||||
adapter.sendEventBody('output', {
|
||||
category: 'telemetry',
|
||||
output: 'someEvent',
|
||||
data: { foo: 'bar', '!err': 'oh no!' }
|
||||
});
|
||||
|
||||
await timeout(0);
|
||||
assert.strictEqual(telemetry.publicLog.callCount, 0);
|
||||
});
|
||||
|
||||
test('logs telemetry and exceptions when enabled', async () => {
|
||||
adapter.sendEventBody('output', {
|
||||
category: 'telemetry',
|
||||
output: 'someEvent',
|
||||
data: { foo: 'bar', '!err': 'oh no!' }
|
||||
});
|
||||
|
||||
await timeout(0);
|
||||
assert.deepStrictEqual(telemetry.publicLog.args[0], [
|
||||
'someEvent',
|
||||
{ foo: 'bar', '!err': 'oh no!' }
|
||||
]);
|
||||
});
|
||||
|
||||
test('filters exceptions when error reporting disabled', async () => {
|
||||
telemetry.sendErrorTelemetry = false;
|
||||
|
||||
adapter.sendEventBody('output', {
|
||||
category: 'telemetry',
|
||||
output: 'someEvent',
|
||||
data: { foo: 'bar', '!err': 'oh no!' }
|
||||
});
|
||||
|
||||
await timeout(0);
|
||||
assert.deepStrictEqual(telemetry.publicLog.args[0], [
|
||||
'someEvent',
|
||||
{ foo: 'bar' }
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -136,6 +136,10 @@ export class MockDebugService implements IDebugService {
|
||||
|
||||
export class MockSession implements IDebugSession {
|
||||
|
||||
stepInTargets(frameId: number): Promise<{ id: number; label: string; }[]> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
cancel(_progressId: string): Promise<DebugProtocol.CancelResponse> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
@@ -144,7 +148,7 @@ export class MockSession implements IDebugSession {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
dataBreakpointInfo(name: string, variablesReference?: number | undefined): Promise<{ dataId: string | null; description: string; canPersist?: boolean | undefined; }> {
|
||||
dataBreakpointInfo(name: string, variablesReference?: number | undefined): Promise<{ dataId: string | null; description: string; canPersist?: boolean | undefined; } | undefined> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
@@ -304,7 +308,7 @@ export class MockSession implements IDebugSession {
|
||||
next(threadId: number): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
stepIn(threadId: number): Promise<void> {
|
||||
stepIn(threadId: number, targetId?: number): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
stepOut(threadId: number): Promise<void> {
|
||||
|
||||
@@ -15,7 +15,7 @@ import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/exte
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test';
|
||||
import { URLService } from 'vs/platform/url/node/urlService';
|
||||
import { NativeURLService } from 'vs/platform/url/common/urlService';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
@@ -89,7 +89,7 @@ suite('Experiment Service', () => {
|
||||
instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event);
|
||||
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
|
||||
instantiationService.stub(ITelemetryService, NullTelemetryService);
|
||||
instantiationService.stub(IURLService, URLService);
|
||||
instantiationService.stub(IURLService, NativeURLService);
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]);
|
||||
testConfigurationService = new TestConfigurationService();
|
||||
instantiationService.stub(IConfigurationService, testConfigurationService);
|
||||
|
||||
@@ -7,7 +7,6 @@ import { IExtensionTipsService, IExtensionManagementService, ILocalExtension, IC
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ExtensionRecommendations, ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { ExtensionRecommendationReason } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
@@ -75,7 +74,7 @@ export class ConfigBasedRecommendations extends ExtensionRecommendations {
|
||||
return;
|
||||
}
|
||||
|
||||
const local = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||
const local = await this.extensionManagementService.getInstalled();
|
||||
const { uninstalled } = this.groupByInstalled(distinct(this.importantTips.map(({ extensionId }) => extensionId)), local);
|
||||
if (uninstalled.length === 0) {
|
||||
return;
|
||||
|
||||
@@ -9,7 +9,6 @@ import { ExtensionRecommendations, ExtensionRecommendation } from 'vs/workbench/
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
@@ -61,7 +60,7 @@ export class ExeBasedRecommendations extends ExtensionRecommendations {
|
||||
importantExeBasedRecommendations[tip.extensionId.toLowerCase()] = tip;
|
||||
});
|
||||
|
||||
const local = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||
const local = await this.extensionManagementService.getInstalled();
|
||||
const { installed, uninstalled } = this.groupByInstalled(Object.keys(importantExeBasedRecommendations), local);
|
||||
|
||||
/* Log installed and uninstalled exe based recommendations */
|
||||
|
||||
@@ -610,7 +610,7 @@ export class ExtensionEditor extends BaseEditor {
|
||||
|
||||
const webview = this.contentDisposables.add(this.webviewService.createWebviewOverlay('extensionEditor', {
|
||||
enableFindWidget: true,
|
||||
}, {}));
|
||||
}, {}, undefined));
|
||||
|
||||
webview.claim(this);
|
||||
webview.layoutWebviewOverElement(template.content);
|
||||
|
||||
@@ -45,11 +45,10 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { CONTEXT_SYNC_ENABLEMENT } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess';
|
||||
import { InstallExtensionQuickAccessProvider, ManageExtensionsQuickAccessProvider } from 'vs/workbench/contrib/extensions/browser/extensionsQuickAccess';
|
||||
import { ExtensionRecommendationsService } from 'vs/workbench/contrib/extensions/browser/extensionRecommendationsService';
|
||||
import { CONTEXT_SYNC_ENABLEMENT } from 'vs/workbench/services/userDataSync/common/userDataSync';
|
||||
|
||||
// Singletons
|
||||
registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService);
|
||||
@@ -458,15 +457,11 @@ registerAction2(class extends Action2 {
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor, id: string) {
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
const ignoredExtensions = [...configurationService.getValue<string[]>('sync.ignoredExtensions')];
|
||||
const index = ignoredExtensions.findIndex(ignoredExtension => areSameExtensions({ id: ignoredExtension }, { id }));
|
||||
if (index !== -1) {
|
||||
ignoredExtensions.splice(index, 1);
|
||||
} else {
|
||||
ignoredExtensions.push(id);
|
||||
const extensionsWorkbenchService = accessor.get(IExtensionsWorkbenchService);
|
||||
const extension = extensionsWorkbenchService.local.find(e => areSameExtensions({ id }, e.identifier));
|
||||
if (extension) {
|
||||
return extensionsWorkbenchService.toggleExtensionIgnoredToSync(extension);
|
||||
}
|
||||
return configurationService.updateValue('sync.ignoredExtensions', ignoredExtensions.length ? ignoredExtensions : undefined, ConfigurationTarget.USER);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ export class InstallAction extends ExtensionAction {
|
||||
|
||||
const extension = await this.install(this.extension);
|
||||
|
||||
alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Azure Data Studio to enable it.", this.extension.displayName));
|
||||
alert(localize('installExtensionComplete', "Installing extension {0} is completed.", this.extension.displayName));
|
||||
|
||||
// {{SQL CARBON EDIT}} Add extension object check since ADS third party extensions will be directed to a download page
|
||||
// and the extension object will be undefined.
|
||||
@@ -827,7 +827,7 @@ export class MenuItemExtensionAction extends ExtensionAction {
|
||||
|
||||
constructor(
|
||||
private readonly action: IAction,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
) {
|
||||
super(action.id, action.label);
|
||||
}
|
||||
@@ -837,7 +837,7 @@ export class MenuItemExtensionAction extends ExtensionAction {
|
||||
return;
|
||||
}
|
||||
if (this.action.id === TOGGLE_IGNORE_EXTENSION_ACTION_ID) {
|
||||
this.checked = !this.configurationService.getValue<string[]>('sync.ignoredExtensions').some(id => areSameExtensions({ id }, this.extension!.identifier));
|
||||
this.checked = !this.extensionsWorkbenchService.isExtensionIgnoredToSync(this.extension);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1380,7 +1380,7 @@ export class ReloadAction extends ExtensionAction {
|
||||
this.enabled = true;
|
||||
this.label = localize('reloadRequired', "Reload Required");
|
||||
this.tooltip = localize('postEnableTooltip', "Please reload Azure Data Studio to enable this extension."); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
alert(localize('installExtensionComplete', "Installing extension {0} is completed. Please reload Azure Data Studio to enable it.", this.extension.displayName)); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
alert(localize('installExtensionCompletedAndReloadRequired', "Installing extension {0} is completed. Please reload Azure Data Studio to enable it.", this.extension.displayName)); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2681,7 +2681,8 @@ export class SyncIgnoredIconAction extends ExtensionAction {
|
||||
private static readonly DISABLE_CLASS = `${SyncIgnoredIconAction.ENABLE_CLASS} hide`;
|
||||
|
||||
constructor(
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
) {
|
||||
super('extensions.syncignore', '', SyncIgnoredIconAction.DISABLE_CLASS, false);
|
||||
this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectedKeys.includes('sync.ignoredExtensions'))(() => this.update()));
|
||||
@@ -2691,11 +2692,8 @@ export class SyncIgnoredIconAction extends ExtensionAction {
|
||||
|
||||
update(): void {
|
||||
this.class = SyncIgnoredIconAction.DISABLE_CLASS;
|
||||
if (this.extension) {
|
||||
const ignoredExtensions = this.configurationService.getValue<string[]>('sync.ignoredExtensions') || [];
|
||||
if (ignoredExtensions.some(id => areSameExtensions({ id }, this.extension!.identifier))) {
|
||||
this.class = SyncIgnoredIconAction.ENABLE_CLASS;
|
||||
}
|
||||
if (this.extension && this.extensionsWorkbenchService.isExtensionIgnoredToSync(this.extension)) {
|
||||
this.class = SyncIgnoredIconAction.ENABLE_CLASS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -456,8 +456,8 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
}
|
||||
},
|
||||
onDragOver: (e: DragEvent) => {
|
||||
if (e.dataTransfer) {
|
||||
e.dataTransfer.dropEffect = this.isSupportedDragElement(e) ? 'copy' : 'none';
|
||||
if (this.isSupportedDragElement(e)) {
|
||||
e.dataTransfer!.dropEffect = 'copy';
|
||||
}
|
||||
},
|
||||
onDrop: async (e: DragEvent) => {
|
||||
@@ -482,7 +482,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}));
|
||||
|
||||
super.create(append(this.root, $('.extensions')));
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet, groupByExtension, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IExtension, ExtensionState, IExtensionsWorkbenchService, AutoUpdateConfigurationKey, AutoCheckUpdatesConfigurationKey } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
@@ -38,6 +38,7 @@ import { IExtensionManifest, ExtensionType, IExtension as IPlatformExtension, is
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { asDomUri } from 'vs/base/browser/dom';
|
||||
import { getIgnoredExtensions } from 'vs/platform/userDataSync/common/extensionsMerge';
|
||||
|
||||
import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator'; // {{SQL CARBON EDIT}}
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener'; // {{SQL CARBON EDIT}}
|
||||
@@ -98,8 +99,8 @@ class Extension implements IExtension {
|
||||
return this.gallery.publisherDisplayName || this.gallery.publisher;
|
||||
}
|
||||
|
||||
if (this.local!.metadata && this.local!.metadata.publisherDisplayName) {
|
||||
return this.local!.metadata.publisherDisplayName;
|
||||
if (this.local?.publisherDisplayName) {
|
||||
return this.local.publisherDisplayName;
|
||||
}
|
||||
|
||||
return this.local!.manifest.publisher;
|
||||
@@ -386,7 +387,7 @@ class Extensions extends Disposable {
|
||||
}
|
||||
// Sync the local extension with gallery extension if local extension doesnot has metadata
|
||||
if (extension.local) {
|
||||
const local = extension.local.metadata ? extension.local : await this.server.extensionManagementService.updateMetadata(extension.local, { id: compatible.identifier.uuid, publisherDisplayName: compatible.publisherDisplayName, publisherId: compatible.publisherId });
|
||||
const local = extension.local.identifier.uuid ? extension.local : await this.server.extensionManagementService.updateMetadata(extension.local, { id: compatible.identifier.uuid, publisherDisplayName: compatible.publisherDisplayName, publisherId: compatible.publisherId });
|
||||
extension.local = local;
|
||||
extension.gallery = compatible;
|
||||
this._onChange.fire({ extension });
|
||||
@@ -923,6 +924,39 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
||||
}, () => this.extensionService.reinstallFromGallery(toReinstall).then(() => this.local.filter(local => areSameExtensions(local.identifier, extension.identifier))[0]));
|
||||
}
|
||||
|
||||
isExtensionIgnoredToSync(extension: IExtension): boolean {
|
||||
const localExtensions = (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer
|
||||
? this.local.filter(i => i.server === this.extensionManagementServerService.localExtensionManagementServer)
|
||||
: this.local)
|
||||
.filter(l => !!l.local)
|
||||
.map(l => l.local!);
|
||||
|
||||
const ignoredExtensions = getIgnoredExtensions(localExtensions, this.configurationService);
|
||||
return ignoredExtensions.includes(extension.identifier.id.toLowerCase());
|
||||
}
|
||||
|
||||
toggleExtensionIgnoredToSync(extension: IExtension): Promise<void> {
|
||||
const isIgnored = this.isExtensionIgnoredToSync(extension);
|
||||
const isDefaultIgnored = extension.local?.isMachineScoped;
|
||||
const id = extension.identifier.id.toLowerCase();
|
||||
|
||||
// first remove the extension completely from ignored extensions
|
||||
let currentValue = [...this.configurationService.getValue<string[]>('sync.ignoredExtensions')].map(id => id.toLowerCase());
|
||||
currentValue = currentValue.filter(v => v !== id && v !== `-${id}`);
|
||||
|
||||
// If ignored, then add only if it is ignored by default
|
||||
if (isIgnored && isDefaultIgnored) {
|
||||
currentValue.push(`-${id}`);
|
||||
}
|
||||
|
||||
// If asked not to sync, then add only if it is not ignored by default
|
||||
if (!isIgnored && !isDefaultIgnored) {
|
||||
currentValue.push(id);
|
||||
}
|
||||
|
||||
return this.configurationService.updateValue('sync.ignoredExtensions', currentValue.length ? currentValue : undefined, ConfigurationTarget.USER);
|
||||
}
|
||||
|
||||
private installWithProgress<T>(installTask: () => Promise<T>, extensionName?: string): Promise<T> {
|
||||
const title = extensionName ? nls.localize('installing named extension', "Installing '{0}' extension....", extensionName) : nls.localize('installing extension', 'Installing extension....');
|
||||
return this.progressService.withProgress({
|
||||
|
||||
@@ -12,7 +12,6 @@ import { ExtensionRecommendationSource, ExtensionRecommendationReason } from 'vs
|
||||
import { IExtensionsViewPaneContainer, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { StorageScope, IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
@@ -181,7 +180,7 @@ export class FileBasedRecommendations extends ExtensionRecommendations {
|
||||
return;
|
||||
}
|
||||
|
||||
const installed = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||
const installed = await this.extensionManagementService.getInstalled();
|
||||
if (await this.promptRecommendedExtensionForFileType(recommendationsToPrompt, installed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.vs .extension-editor > .header > .details > .title > .preview {
|
||||
.monaco-workbench.vs .extension-editor > .header > .details > .title > .preview {
|
||||
color: white;
|
||||
}
|
||||
|
||||
@@ -408,8 +408,8 @@
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.vs-dark .extension-editor > .body > .content table .colorBox,
|
||||
.hc-black .extension-editor > .body > .content table .colorBox {
|
||||
.monaco-workbench.vs-dark .extension-editor > .body > .content table .colorBox,
|
||||
.monaco-workbench.hc-black .extension-editor > .body > .content table .colorBox {
|
||||
border-color: rgb(238, 238, 238);
|
||||
}
|
||||
|
||||
|
||||
@@ -112,16 +112,16 @@
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .bookmark,
|
||||
.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .bookmark,
|
||||
.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .icon-container > .icon,
|
||||
.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .icon-container > .icon,
|
||||
.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .details > .header-container,
|
||||
.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .details > .header-container,
|
||||
.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .details > .description,
|
||||
.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .details > .description,
|
||||
.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .details > .footer > .author,
|
||||
.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .details > .footer > .author {
|
||||
.monaco-workbench.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .bookmark,
|
||||
.monaco-workbench.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .bookmark,
|
||||
.monaco-workbench.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .icon-container > .icon,
|
||||
.monaco-workbench.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .icon-container > .icon,
|
||||
.monaco-workbench.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .details > .header-container,
|
||||
.monaco-workbench.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .details > .header-container,
|
||||
.monaco-workbench.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .details > .description,
|
||||
.monaco-workbench.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .details > .description,
|
||||
.monaco-workbench.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .details > .footer > .author,
|
||||
.monaco-workbench.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension-list-item > .details > .footer > .author {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export class RemoteExtensionsInstaller extends Disposable implements IWorkbenchC
|
||||
disposable = MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
command: {
|
||||
id: 'workbench.extensions.installLocalExtensions',
|
||||
category: localize('remote', "Remote"),
|
||||
category: localize({ key: 'remote', comment: ['Remote as in remote machine'] }, "Remote"),
|
||||
title: installLocalExtensionsInRemoteAction.label
|
||||
}
|
||||
});
|
||||
|
||||
@@ -17,7 +17,6 @@ import { EXTENSIONS_CONFIG } from 'vs/workbench/contrib/extensions/common/extens
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { InstallWorkspaceRecommendedExtensionsAction, ShowRecommendedExtensionsAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { StorageScope, IStorageService } from 'vs/platform/storage/common/storage';
|
||||
@@ -105,7 +104,7 @@ export class WorkspaceRecommendations extends ExtensionRecommendations {
|
||||
return;
|
||||
}
|
||||
|
||||
let installed = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||
let installed = await this.extensionManagementService.getInstalled();
|
||||
installed = installed.filter(l => this.extensionEnablementService.getEnablementState(l) !== EnablementState.DisabledByExtensionKind); // Filter extensions disabled by kind
|
||||
const recommendations = allowedRecommendations.filter(({ extensionId }) => installed.every(local => !areSameExtensions({ id: extensionId }, local.identifier)));
|
||||
|
||||
|
||||
@@ -89,6 +89,10 @@ export interface IExtensionsWorkbenchService {
|
||||
setEnablement(extensions: IExtension | IExtension[], enablementState: EnablementState): Promise<void>;
|
||||
open(extension: IExtension, options?: { sideByside?: boolean, preserveFocus?: boolean, pinned?: boolean }): Promise<any>;
|
||||
checkForUpdates(): Promise<void>;
|
||||
|
||||
// Sync APIs
|
||||
isExtensionIgnoredToSync(extension: IExtension): boolean;
|
||||
toggleExtensionIgnoredToSync(extension: IExtension): Promise<void>;
|
||||
}
|
||||
|
||||
export const ConfigurationKey = 'extensions';
|
||||
|
||||
@@ -12,7 +12,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar';
|
||||
import { IExtensionHostProfileService, ProfileSessionState } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
import { IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { randomPort } from 'vs/base/node/ports';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
|
||||
@@ -9,7 +9,7 @@ import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
import { IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
export class OpenExtensionsFolderAction extends Action {
|
||||
|
||||
@@ -57,8 +57,8 @@
|
||||
color: currentColor;
|
||||
}
|
||||
|
||||
.vs .runtime-extensions-editor .extension > .icon-container > .icon,
|
||||
.vs-dark .runtime-extensions-editor .extension > .icon-container > .icon {
|
||||
.monaco-workbench.vs .runtime-extensions-editor .extension > .icon-container > .icon,
|
||||
.monaco-workbench.vs-dark .runtime-extensions-editor .extension > .icon-container > .icon {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { EnablementState } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
import { IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
|
||||
import { writeFile } from 'vs/base/node/pfs';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
|
||||
@@ -41,7 +41,7 @@ import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { INotificationService, Severity, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification';
|
||||
import { URLService } from 'vs/platform/url/node/urlService';
|
||||
import { NativeURLService } from 'vs/platform/url/common/urlService';
|
||||
import { IExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||
import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
@@ -206,7 +206,7 @@ suite.skip('ExtensionRecommendationsService Test', () => { // {{SQL CARBON EDIT}
|
||||
instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event);
|
||||
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
|
||||
instantiationService.stub(ITelemetryService, NullTelemetryService);
|
||||
instantiationService.stub(IURLService, URLService);
|
||||
instantiationService.stub(IURLService, NativeURLService);
|
||||
instantiationService.stub(IWorkspaceTagsService, new NoOpWorkspaceTagsService());
|
||||
instantiationService.stub(IStorageService, new TestStorageService());
|
||||
instantiationService.stub(ILogService, new NullLogService());
|
||||
|
||||
@@ -11,11 +11,10 @@ import * as ExtensionsActions from 'vs/workbench/contrib/extensions/browser/exte
|
||||
import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/browser/extensionsWorkbenchService';
|
||||
import {
|
||||
IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension,
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, InstallOperation, IExtensionTipsService
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier, InstallOperation, IExtensionTipsService, IGalleryMetadata
|
||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, IExtensionRecommendationsService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test';
|
||||
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
@@ -30,7 +29,7 @@ import { TestContextService } from 'vs/workbench/test/common/workbenchTestServic
|
||||
import { TestSharedProcessService } from 'vs/workbench/test/electron-browser/workbenchTestServices';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||
import { URLService } from 'vs/platform/url/node/urlService';
|
||||
import { NativeURLService } from 'vs/platform/url/common/urlService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
@@ -82,11 +81,21 @@ async function setupTest() {
|
||||
instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService);
|
||||
instantiationService.stub(ISharedProcessService, TestSharedProcessService);
|
||||
|
||||
instantiationService.stub(IExtensionManagementService, ExtensionManagementService);
|
||||
instantiationService.stub(IExtensionManagementService, 'onInstallExtension', installEvent.event);
|
||||
instantiationService.stub(IExtensionManagementService, 'onDidInstallExtension', didInstallEvent.event);
|
||||
instantiationService.stub(IExtensionManagementService, 'onUninstallExtension', uninstallEvent.event);
|
||||
instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event);
|
||||
instantiationService.stub(IExtensionManagementService, <Partial<IExtensionManagementService>>{
|
||||
onInstallExtension: installEvent.event,
|
||||
onDidInstallExtension: didInstallEvent.event,
|
||||
onUninstallExtension: uninstallEvent.event,
|
||||
onDidUninstallExtension: didUninstallEvent.event,
|
||||
async getInstalled() { return []; },
|
||||
async getExtensionsReport() { return []; },
|
||||
async updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata) {
|
||||
local.identifier.uuid = metadata.id;
|
||||
local.publisherDisplayName = metadata.publisherDisplayName;
|
||||
local.publisherId = metadata.publisherId;
|
||||
return local;
|
||||
}
|
||||
});
|
||||
|
||||
instantiationService.stub(IRemoteAgentService, RemoteAgentService);
|
||||
|
||||
instantiationService.stub(IExtensionManagementServerService, new class extends ExtensionManagementServerService {
|
||||
@@ -105,10 +114,8 @@ async function setupTest() {
|
||||
instantiationService.stub(IExperimentService, instantiationService.createInstance(TestExperimentService));
|
||||
instantiationService.stub(IExtensionTipsService, instantiationService.createInstance(ExtensionTipsService));
|
||||
instantiationService.stub(IExtensionRecommendationsService, {});
|
||||
instantiationService.stub(IURLService, URLService);
|
||||
instantiationService.stub(IURLService, NativeURLService);
|
||||
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', []);
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getExtensionsReport', []);
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage());
|
||||
instantiationService.stub(IExtensionService, <Partial<IExtensionService>>{ getExtensions: () => Promise.resolve([]), onDidChangeExtensions: new Emitter<void>().event, canAddExtension: (extension: IExtensionDescription) => false, canRemoveExtension: (extension: IExtensionDescription) => false });
|
||||
(<TestExtensionEnablementService>instantiationService.get(IWorkbenchExtensionEnablementService)).reset();
|
||||
@@ -117,7 +124,7 @@ async function setupTest() {
|
||||
}
|
||||
|
||||
|
||||
suite('ExtensionsActions Test', () => {
|
||||
suite('ExtensionsActions', () => {
|
||||
|
||||
setup(setupTest);
|
||||
teardown(() => disposables.dispose());
|
||||
@@ -2491,8 +2498,7 @@ function aLocalExtension(name: string = 'someext', manifest: any = {}, propertie
|
||||
properties = assign({
|
||||
type: ExtensionType.User,
|
||||
location: URI.file(`pub.${name}`),
|
||||
identifier: { id: getGalleryExtensionId(manifest.publisher, manifest.name), uuid: undefined },
|
||||
metadata: { id: getGalleryExtensionId(manifest.publisher, manifest.name), publisherId: manifest.publisher, publisherDisplayName: 'somename' }
|
||||
identifier: { id: getGalleryExtensionId(manifest.publisher, manifest.name) }
|
||||
}, properties);
|
||||
return <ILocalExtension>Object.create({ manifest, ...properties });
|
||||
}
|
||||
@@ -2563,7 +2569,13 @@ function createExtensionManagementService(installed: ILocalExtension[] = []): IE
|
||||
onUninstallExtension: Event.None,
|
||||
onDidUninstallExtension: Event.None,
|
||||
getInstalled: () => Promise.resolve<ILocalExtension[]>(installed),
|
||||
installFromGallery: (extension: IGalleryExtension) => Promise.reject(new Error('not supported'))
|
||||
installFromGallery: (extension: IGalleryExtension) => Promise.reject(new Error('not supported')),
|
||||
updateMetadata: async (local: ILocalExtension, metadata: IGalleryMetadata) => {
|
||||
local.identifier.uuid = metadata.id;
|
||||
local.publisherDisplayName = metadata.publisherDisplayName;
|
||||
local.publisherId = metadata.publisherId;
|
||||
return local;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import { TestMenuService } from 'vs/workbench/test/browser/workbenchTestServices
|
||||
import { TestSharedProcessService } from 'vs/workbench/test/electron-browser/workbenchTestServices';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||
import { URLService } from 'vs/platform/url/node/urlService';
|
||||
import { NativeURLService } from 'vs/platform/url/common/urlService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { SinonStub } from 'sinon';
|
||||
@@ -142,7 +142,7 @@ suite('ExtensionsListView Tests', () => {
|
||||
return reasons;
|
||||
}
|
||||
});
|
||||
instantiationService.stub(IURLService, URLService);
|
||||
instantiationService.stub(IURLService, NativeURLService);
|
||||
});
|
||||
|
||||
setup(async () => {
|
||||
|
||||
@@ -12,11 +12,10 @@ import { IExtensionsWorkbenchService, ExtensionState, AutoCheckUpdatesConfigurat
|
||||
import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/browser/extensionsWorkbenchService';
|
||||
import {
|
||||
IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension,
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets, IExtensionIdentifier, InstallOperation, IExtensionTipsService
|
||||
DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets, IExtensionIdentifier, InstallOperation, IExtensionTipsService, IGalleryMetadata
|
||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test';
|
||||
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
@@ -32,7 +31,7 @@ import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||
import { IProgressService } from 'vs/platform/progress/common/progress';
|
||||
import { ProgressService } from 'vs/workbench/services/progress/browser/progressService';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { URLService } from 'vs/platform/url/node/urlService';
|
||||
import { NativeURLService } from 'vs/platform/url/common/urlService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
@@ -72,7 +71,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
instantiationService.stub(IProductService, {});
|
||||
|
||||
instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService);
|
||||
instantiationService.stub(IURLService, URLService);
|
||||
instantiationService.stub(IURLService, NativeURLService);
|
||||
instantiationService.stub(ISharedProcessService, TestSharedProcessService);
|
||||
|
||||
instantiationService.stub(IWorkspaceContextService, new TestContextService());
|
||||
@@ -85,11 +84,20 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
|
||||
instantiationService.stub(IRemoteAgentService, RemoteAgentService);
|
||||
|
||||
instantiationService.stub(IExtensionManagementService, ExtensionManagementService);
|
||||
instantiationService.stub(IExtensionManagementService, 'onInstallExtension', installEvent.event);
|
||||
instantiationService.stub(IExtensionManagementService, 'onDidInstallExtension', didInstallEvent.event);
|
||||
instantiationService.stub(IExtensionManagementService, 'onUninstallExtension', uninstallEvent.event);
|
||||
instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event);
|
||||
instantiationService.stub(IExtensionManagementService, <Partial<IExtensionManagementService>>{
|
||||
onInstallExtension: installEvent.event,
|
||||
onDidInstallExtension: didInstallEvent.event,
|
||||
onUninstallExtension: uninstallEvent.event,
|
||||
onDidUninstallExtension: didUninstallEvent.event,
|
||||
async getInstalled() { return []; },
|
||||
async getExtensionsReport() { return []; },
|
||||
async updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata) {
|
||||
local.identifier.uuid = metadata.id;
|
||||
local.publisherDisplayName = metadata.publisherDisplayName;
|
||||
local.publisherId = metadata.publisherId;
|
||||
return local;
|
||||
}
|
||||
});
|
||||
|
||||
instantiationService.stub(IExtensionManagementServerService, <IExtensionManagementServerService>{
|
||||
localExtensionManagementServer: {
|
||||
@@ -109,7 +117,6 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
|
||||
setup(async () => {
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', []);
|
||||
instantiationService.stubPromise(IExtensionManagementService, 'getExtensionsReport', []);
|
||||
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage());
|
||||
instantiationService.stubPromise(INotificationService, 'prompt', 0);
|
||||
await (<TestExtensionEnablementService>instantiationService.get(IWorkbenchExtensionEnablementService)).reset();
|
||||
@@ -985,8 +992,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
|
||||
properties = assign({
|
||||
type: ExtensionType.User,
|
||||
location: URI.file(`pub.${name}`),
|
||||
identifier: { id: getGalleryExtensionId(manifest.publisher, manifest.name), uuid: undefined },
|
||||
metadata: { id: getGalleryExtensionId(manifest.publisher, manifest.name), publisherId: manifest.publisher, publisherDisplayName: 'somename' }
|
||||
identifier: { id: getGalleryExtensionId(manifest.publisher, manifest.name) }
|
||||
}, properties);
|
||||
return <ILocalExtension>Object.create({ manifest, ...properties });
|
||||
}
|
||||
|
||||
@@ -115,7 +115,8 @@
|
||||
}
|
||||
|
||||
/* Theming */
|
||||
.vs .monaco-workbench .feedback-form .feedback-alias, .vs .monaco-workbench .feedback-form .feedback-description {
|
||||
.monaco-workbench.vs .feedback-form .feedback-alias,
|
||||
.monaco-workbench.vs .feedback-form .feedback-description {
|
||||
font-family: inherit;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
@@ -167,16 +168,17 @@
|
||||
background-color: #E51400;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .feedback-form h3 {
|
||||
.monaco-workbench.vs-dark .feedback-form h3 {
|
||||
font-weight: normal;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .feedback-form .sentiment:hover {
|
||||
.monaco-workbench.vs-dark .feedback-form .sentiment:hover {
|
||||
background-color: rgba(30,30,30,0.8);
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .feedback-form .feedback-alias, .vs-dark .monaco-workbench .feedback-form .feedback-description {
|
||||
.monaco-workbench.vs-dark .feedback-form .feedback-alias,
|
||||
.monaco-workbench.vs-dark .feedback-form .feedback-description {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
@@ -193,28 +195,29 @@
|
||||
}
|
||||
|
||||
/* High Contrast Theming */
|
||||
.hc-black .monaco-workbench .feedback-form {
|
||||
.monaco-workbench.hc-black .feedback-form {
|
||||
outline: 2px solid #6fc3df;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .feedback-form .feedback-alias, .hc-black .monaco-workbench .feedback-form .feedback-description {
|
||||
.monaco-workbench.hc-black .feedback-form .feedback-alias,
|
||||
.monaco-workbench.hc-black .feedback-form .feedback-description {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .feedback-form .content .contactus {
|
||||
.monaco-workbench.hc-black .feedback-form .content .contactus {
|
||||
padding: 10px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .feedback-form .form-buttons .send,
|
||||
.hc-black .monaco-workbench .feedback-form .form-buttons .send.in-progress,
|
||||
.hc-black .monaco-workbench .feedback-form .form-buttons .send.success {
|
||||
.monaco-workbench.hc-black .feedback-form .form-buttons .send,
|
||||
.monaco-workbench.hc-black .feedback-form .form-buttons .send.in-progress,
|
||||
.monaco-workbench.hc-black .feedback-form .form-buttons .send.success {
|
||||
background-color: #0C141F;
|
||||
color: #D4D4D4;
|
||||
border: 1px solid #6FC3DF;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .feedback-form .form-buttons .send:hover {
|
||||
.monaco-workbench.hc-black .feedback-form .form-buttons .send:hover {
|
||||
background-color: #0C141F;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { Action } from 'vs/base/common/actions';
|
||||
import { VIEWLET_ID, TEXT_FILE_EDITOR_ID, IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
||||
import { ITextFileService, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { BaseTextEditor, IEditorConfiguration } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||
import { EditorOptions, TextEditorOptions, IEditorCloseEvent, Verbosity } from 'vs/workbench/common/editor';
|
||||
import { EditorOptions, TextEditorOptions, IEditorCloseEvent } from 'vs/workbench/common/editor';
|
||||
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
@@ -245,11 +245,6 @@ export class TextFileEditor extends BaseTextEditor {
|
||||
}
|
||||
}
|
||||
|
||||
protected getAriaLabel(): string {
|
||||
const title = this.input?.getTitle(Verbosity.SHORT) || nls.localize('fileEditorAriaLabel', "editor");
|
||||
return this.input?.isReadonly() ? nls.localize('readonlyEditor', "{0} readonly", title) : title;
|
||||
}
|
||||
|
||||
clearInput(): void {
|
||||
|
||||
// Update/clear editor view state in settings
|
||||
|
||||
@@ -350,18 +350,23 @@ export const acceptLocalChangesCommand = async (accessor: ServicesAccessor, reso
|
||||
const reference = await resolverService.createModelReference(resource);
|
||||
const model = reference.object as IResolvedTextFileEditorModel;
|
||||
|
||||
clearPendingResolveSaveConflictMessages(); // hide any previously shown message about how to use these actions
|
||||
try {
|
||||
|
||||
// Trigger save
|
||||
await model.save({ ignoreModifiedSince: true, reason: SaveReason.EXPLICIT });
|
||||
// hide any previously shown message about how to use these actions
|
||||
clearPendingResolveSaveConflictMessages();
|
||||
|
||||
// Reopen file input
|
||||
await editorService.openEditor({ resource: model.resource }, group);
|
||||
// Trigger save
|
||||
await model.save({ ignoreModifiedSince: true, reason: SaveReason.EXPLICIT });
|
||||
|
||||
// Clean up
|
||||
group.closeEditor(editor);
|
||||
editor.dispose();
|
||||
reference.dispose();
|
||||
// Reopen file input
|
||||
await editorService.openEditor({ resource: model.resource }, group);
|
||||
|
||||
// Clean up
|
||||
group.closeEditor(editor);
|
||||
editor.dispose();
|
||||
} finally {
|
||||
reference.dispose();
|
||||
}
|
||||
};
|
||||
|
||||
export const revertLocalChangesCommand = async (accessor: ServicesAccessor, resource: URI) => {
|
||||
@@ -379,16 +384,21 @@ export const revertLocalChangesCommand = async (accessor: ServicesAccessor, reso
|
||||
const reference = await resolverService.createModelReference(resource);
|
||||
const model = reference.object as ITextFileEditorModel;
|
||||
|
||||
clearPendingResolveSaveConflictMessages(); // hide any previously shown message about how to use these actions
|
||||
try {
|
||||
|
||||
// Revert on model
|
||||
await model.revert();
|
||||
// hide any previously shown message about how to use these actions
|
||||
clearPendingResolveSaveConflictMessages();
|
||||
|
||||
// Reopen file input
|
||||
await editorService.openEditor({ resource: model.resource }, group);
|
||||
// Revert on model
|
||||
await model.revert();
|
||||
|
||||
// Clean up
|
||||
group.closeEditor(editor);
|
||||
editor.dispose();
|
||||
reference.dispose();
|
||||
// Reopen file input
|
||||
await editorService.openEditor({ resource: model.resource }, group);
|
||||
|
||||
// Clean up
|
||||
group.closeEditor(editor);
|
||||
editor.dispose();
|
||||
} finally {
|
||||
reference.dispose();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -109,6 +109,7 @@ export class ExplorerViewletViewsContribution extends Disposable implements IWor
|
||||
id: OpenEditorsView.ID,
|
||||
name: OpenEditorsView.NAME,
|
||||
ctorDescriptor: new SyncDescriptor(OpenEditorsView),
|
||||
containerIcon: 'codicon-files',
|
||||
order: 0,
|
||||
when: OpenEditorsVisibleContext,
|
||||
canToggleVisibility: true,
|
||||
|
||||
@@ -145,9 +145,9 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
weight: KeybindingWeight.WorkbenchContrib + explorerCommandsWeightBonus,
|
||||
when: ContextKeyExpr.and(FilesExplorerFocusCondition, ExplorerResourceCut),
|
||||
primary: KeyCode.Escape,
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
handler: async (accessor: ServicesAccessor) => {
|
||||
const explorerService = accessor.get(IExplorerService);
|
||||
explorerService.setToCopy([], true);
|
||||
await explorerService.setToCopy([], true);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ import { sequence, timeout } from 'vs/base/common/async';
|
||||
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
import { once } from 'vs/base/common/functional';
|
||||
import { IEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorGroup, OpenEditorContext } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { IViewsService } from 'vs/workbench/common/views';
|
||||
import { openEditorWith, getAllAvailableEditors } from 'vs/workbench/contrib/files/common/openWith';
|
||||
@@ -597,7 +597,7 @@ export class ToggleEditorTypeCommand extends Action {
|
||||
return;
|
||||
}
|
||||
|
||||
await firstNonActiveOverride[0].open(input, options, group, firstNonActiveOverride[1].id)?.override;
|
||||
await firstNonActiveOverride[0].open(input, options, group, OpenEditorContext.NEW_EDITOR, firstNonActiveOverride[1].id)?.override;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1081,20 +1081,20 @@ export const deleteFileHandler = async (accessor: ServicesAccessor) => {
|
||||
};
|
||||
|
||||
let pasteShouldMove = false;
|
||||
export const copyFileHandler = (accessor: ServicesAccessor) => {
|
||||
export const copyFileHandler = async (accessor: ServicesAccessor) => {
|
||||
const explorerService = accessor.get(IExplorerService);
|
||||
const stats = explorerService.getContext(true);
|
||||
if (stats.length > 0) {
|
||||
explorerService.setToCopy(stats, false);
|
||||
await explorerService.setToCopy(stats, false);
|
||||
pasteShouldMove = false;
|
||||
}
|
||||
};
|
||||
|
||||
export const cutFileHandler = (accessor: ServicesAccessor) => {
|
||||
export const cutFileHandler = async (accessor: ServicesAccessor) => {
|
||||
const explorerService = accessor.get(IExplorerService);
|
||||
const stats = explorerService.getContext(true);
|
||||
if (stats.length > 0) {
|
||||
explorerService.setToCopy(stats, true);
|
||||
await explorerService.setToCopy(stats, true);
|
||||
pasteShouldMove = true;
|
||||
}
|
||||
};
|
||||
@@ -1161,7 +1161,7 @@ export const pasteFileHandler = async (accessor: ServicesAccessor) => {
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
|
||||
const context = explorerService.getContext(true);
|
||||
const toPaste = resources.distinctParents(clipboardService.readResources(), r => r);
|
||||
const toPaste = resources.distinctParents(await clipboardService.readResources(), r => r);
|
||||
const element = context.length ? context[0] : explorerService.roots[0];
|
||||
|
||||
// Check if target is ancestor of pasted folder
|
||||
@@ -1199,7 +1199,7 @@ export const pasteFileHandler = async (accessor: ServicesAccessor) => {
|
||||
|
||||
if (pasteShouldMove) {
|
||||
// Cut is done. Make sure to clear cut state.
|
||||
explorerService.setToCopy([], false);
|
||||
await explorerService.setToCopy([], false);
|
||||
pasteShouldMove = false;
|
||||
}
|
||||
if (stats.length >= 1) {
|
||||
|
||||
@@ -369,9 +369,15 @@ configurationRegistry.registerConfiguration({
|
||||
'default': 9
|
||||
},
|
||||
'explorer.autoReveal': {
|
||||
'type': 'boolean',
|
||||
'description': nls.localize('autoReveal', "Controls whether the explorer should automatically reveal and select files when opening them."),
|
||||
'default': true
|
||||
'type': ['boolean', 'string'],
|
||||
'enum': [true, false, 'focusNoScroll'],
|
||||
'default': true,
|
||||
'enumDescriptions': [
|
||||
nls.localize('autoReveal.on', 'Files will be revealed and selected.'),
|
||||
nls.localize('autoReveal.off', 'Files will not be revealed and selected.'),
|
||||
nls.localize('autoReveal.focusNoScroll', 'Files will not be scrolled into view, but will still be focused.'),
|
||||
],
|
||||
'description': nls.localize('autoReveal', "Controls whether the explorer should automatically reveal and select files when opening them.")
|
||||
},
|
||||
'explorer.enableDragAndDrop': {
|
||||
'type': 'boolean',
|
||||
|
||||
@@ -95,6 +95,6 @@
|
||||
}
|
||||
|
||||
/* High Contrast Theming */
|
||||
.hc-black .monaco-workbench .explorer-viewlet .explorer-item {
|
||||
.monaco-workbench.hc-black .explorer-viewlet .explorer-item {
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
|
||||
import { IAsyncDataTreeViewState } from 'vs/base/browser/ui/tree/asyncDataTree';
|
||||
import { FuzzyScore } from 'vs/base/common/filters';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { isEqualOrParent } from 'vs/base/common/resources';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { first } from 'vs/base/common/arrays';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
@@ -56,6 +55,7 @@ import { Color } from 'vs/base/common/color';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
|
||||
|
||||
interface IExplorerViewColors extends IColorMapping {
|
||||
listDropBackground?: ColorValue | undefined;
|
||||
@@ -146,7 +146,7 @@ export class ExplorerView extends ViewPane {
|
||||
// Refresh is needed on the initial explorer open
|
||||
private shouldRefresh = true;
|
||||
private dragHandler!: DelayedDragHandler;
|
||||
private autoReveal = false;
|
||||
private autoReveal: boolean | 'focusNoScroll' = false;
|
||||
private actions: IAction[] | undefined;
|
||||
private decorationsProvider: ExplorerDecorationsProvider | undefined;
|
||||
|
||||
@@ -171,6 +171,7 @@ export class ExplorerView extends ViewPane {
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IClipboardService private clipboardService: IClipboardService,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
|
||||
@IOpenerService openerService: IOpenerService,
|
||||
) {
|
||||
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
|
||||
@@ -471,7 +472,7 @@ export class ExplorerView extends ViewPane {
|
||||
}
|
||||
}
|
||||
|
||||
private onContextMenu(e: ITreeContextMenuEvent<ExplorerItem>): void {
|
||||
private async onContextMenu(e: ITreeContextMenuEvent<ExplorerItem>): Promise<void> {
|
||||
const disposables = new DisposableStore();
|
||||
let stat = e.element;
|
||||
let anchor = e.anchor;
|
||||
@@ -490,7 +491,7 @@ export class ExplorerView extends ViewPane {
|
||||
}
|
||||
|
||||
// update dynamic contexts
|
||||
this.fileCopiedContextKey.set(this.clipboardService.hasResources());
|
||||
this.fileCopiedContextKey.set(await this.clipboardService.hasResources());
|
||||
this.setContextKeys(stat);
|
||||
|
||||
const selection = this.tree.getSelection();
|
||||
@@ -652,8 +653,7 @@ export class ExplorerView extends ViewPane {
|
||||
}
|
||||
|
||||
// Expand all stats in the parent chain.
|
||||
const ignoreCase = !this.fileService.hasCapability(resource, FileSystemProviderCapabilities.PathCaseSensitive);
|
||||
let item: ExplorerItem | undefined = this.explorerService.roots.filter(i => isEqualOrParent(resource, i.resource, ignoreCase))
|
||||
let item: ExplorerItem | undefined = this.explorerService.roots.filter(i => this.uriIdentityService.extUri.isEqualOrParent(resource, i.resource))
|
||||
// Take the root that is the closest to the stat #72299
|
||||
.sort((first, second) => second.resource.path.length - first.resource.path.length)[0];
|
||||
|
||||
@@ -663,7 +663,7 @@ export class ExplorerView extends ViewPane {
|
||||
} catch (e) {
|
||||
return this.selectResource(resource, reveal, retry + 1);
|
||||
}
|
||||
item = first(values(item.children), i => isEqualOrParent(resource, i.resource, ignoreCase));
|
||||
item = first(values(item.children), i => this.uriIdentityService.extUri.isEqualOrParent(resource, i.resource));
|
||||
}
|
||||
|
||||
if (item) {
|
||||
@@ -674,11 +674,9 @@ export class ExplorerView extends ViewPane {
|
||||
}
|
||||
|
||||
try {
|
||||
if (reveal) {
|
||||
// Don't scroll to the item if it's already visible
|
||||
if (this.tree.getRelativeTop(item) === null) {
|
||||
this.tree.reveal(item, 0.5);
|
||||
}
|
||||
if (reveal === true && this.tree.getRelativeTop(item) === null) {
|
||||
// Don't scroll to the item if it's already visible, or if set not to.
|
||||
this.tree.reveal(item, 0.5);
|
||||
}
|
||||
|
||||
this.tree.setFocus([item]);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import * as glob from 'vs/base/common/glob';
|
||||
import { IListVirtualDelegate, ListDragOverEffect } from 'vs/base/browser/ui/list/list';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { IProgressService, ProgressLocation, IProgressStep, IProgress } from 'vs/platform/progress/common/progress';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IFileService, FileKind, FileOperationError, FileOperationResult, FileSystemProviderCapabilities } from 'vs/platform/files/common/files';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
@@ -19,7 +19,7 @@ import { ITreeNode, ITreeFilter, TreeVisibility, TreeFilterResult, IAsyncDataSou
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { IFilesConfiguration, IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
||||
import { IFilesConfiguration, IExplorerService, VIEW_ID } from 'vs/workbench/contrib/files/common/files';
|
||||
import { dirname, joinPath, isEqualOrParent, basename, distinctParents } from 'vs/base/common/resources';
|
||||
import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -29,7 +29,7 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { equals, deepClone } from 'vs/base/common/objects';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel';
|
||||
import { compareFileExtensions, compareFileNames } from 'vs/base/common/comparers';
|
||||
import { compareFileExtensionsNumeric, compareFileNamesNumeric } from 'vs/base/common/comparers';
|
||||
import { fillResourceDataTransfers, CodeDataTransfers, extractResources, containsDragType } from 'vs/workbench/browser/dnd';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IDragAndDropData, DataTransfers } from 'vs/base/browser/dnd';
|
||||
@@ -50,12 +50,13 @@ import { Emitter, Event, EventMultiplexer } from 'vs/base/common/event';
|
||||
import { ITreeCompressionDelegate } from 'vs/base/browser/ui/tree/asyncDataTree';
|
||||
import { ICompressibleTreeRenderer } from 'vs/base/browser/ui/tree/objectTree';
|
||||
import { ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { VSBuffer, newWriteableBufferStream } from 'vs/base/common/buffer';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { isNumber } from 'vs/base/common/types';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { IEditableData } from 'vs/workbench/common/views';
|
||||
import { IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
export class ExplorerDelegate implements IListVirtualDelegate<ExplorerItem> {
|
||||
|
||||
@@ -616,7 +617,7 @@ export class FilesFilter implements ITreeFilter<ExplorerItem, FuzzyScore> {
|
||||
}
|
||||
}
|
||||
|
||||
// // Explorer Sorter
|
||||
// Explorer Sorter
|
||||
export class FileSorter implements ITreeSorter<ExplorerItem> {
|
||||
|
||||
constructor(
|
||||
@@ -624,7 +625,7 @@ export class FileSorter implements ITreeSorter<ExplorerItem> {
|
||||
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService
|
||||
) { }
|
||||
|
||||
public compare(statA: ExplorerItem, statB: ExplorerItem): number {
|
||||
compare(statA: ExplorerItem, statB: ExplorerItem): number {
|
||||
// Do not sort roots
|
||||
if (statA.isRoot) {
|
||||
if (statB.isRoot) {
|
||||
@@ -654,7 +655,7 @@ export class FileSorter implements ITreeSorter<ExplorerItem> {
|
||||
}
|
||||
|
||||
if (statA.isDirectory && statB.isDirectory) {
|
||||
return compareFileNames(statA.name, statB.name);
|
||||
return compareFileNamesNumeric(statA.name, statB.name);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -688,17 +689,17 @@ export class FileSorter implements ITreeSorter<ExplorerItem> {
|
||||
// Sort Files
|
||||
switch (sortOrder) {
|
||||
case 'type':
|
||||
return compareFileExtensions(statA.name, statB.name);
|
||||
return compareFileExtensionsNumeric(statA.name, statB.name);
|
||||
|
||||
case 'modified':
|
||||
if (statA.mtime !== statB.mtime) {
|
||||
return (statA.mtime && statB.mtime && statA.mtime < statB.mtime) ? 1 : -1;
|
||||
}
|
||||
|
||||
return compareFileNames(statA.name, statB.name);
|
||||
return compareFileNamesNumeric(statA.name, statB.name);
|
||||
|
||||
default: /* 'default', 'mixed', 'filesFirst' */
|
||||
return compareFileNames(statA.name, statB.name);
|
||||
return compareFileNamesNumeric(statA.name, statB.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -712,6 +713,27 @@ const getFileOverwriteConfirm = (name: string) => {
|
||||
};
|
||||
};
|
||||
|
||||
interface IWebkitDataTransfer {
|
||||
items: IWebkitDataTransferItem[];
|
||||
}
|
||||
|
||||
interface IWebkitDataTransferItem {
|
||||
webkitGetAsEntry(): IWebkitDataTransferItemEntry;
|
||||
}
|
||||
|
||||
interface IWebkitDataTransferItemEntry {
|
||||
name: string | undefined;
|
||||
isFile: boolean;
|
||||
isDirectory: boolean;
|
||||
|
||||
file(resolve: (file: File) => void, reject: () => void): void;
|
||||
createReader(): IWebkitDataTransferItemEntryReader;
|
||||
}
|
||||
|
||||
interface IWebkitDataTransferItemEntryReader {
|
||||
readEntries(resolve: (file: IWebkitDataTransferItemEntry[]) => void, reject: () => void): void
|
||||
}
|
||||
|
||||
export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
|
||||
private static readonly CONFIRM_DND_SETTING_KEY = 'explorer.confirmDragAndDrop';
|
||||
|
||||
@@ -732,7 +754,8 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IWorkingCopyFileService private workingCopyFileService: IWorkingCopyFileService,
|
||||
@IHostService private hostService: IHostService,
|
||||
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService
|
||||
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService,
|
||||
@IProgressService private readonly progressService: IProgressService
|
||||
) {
|
||||
this.toDispose = [];
|
||||
|
||||
@@ -756,7 +779,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
|
||||
const iconLabelName = getIconLabelNameFromHTMLElement(originalEvent.target);
|
||||
|
||||
if (iconLabelName && iconLabelName.index < iconLabelName.count - 1) {
|
||||
const result = this._onDragOver(data, compressedTarget, targetIndex, originalEvent);
|
||||
const result = this.handleDragOver(data, compressedTarget, targetIndex, originalEvent);
|
||||
|
||||
if (result) {
|
||||
if (iconLabelName.element !== this.compressedDragOverElement) {
|
||||
@@ -780,10 +803,10 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
|
||||
}
|
||||
|
||||
this.compressedDropTargetDisposable.dispose();
|
||||
return this._onDragOver(data, target, targetIndex, originalEvent);
|
||||
return this.handleDragOver(data, target, targetIndex, originalEvent);
|
||||
}
|
||||
|
||||
private _onDragOver(data: IDragAndDropData, target: ExplorerItem | undefined, targetIndex: number | undefined, originalEvent: DragEvent): boolean | ITreeDragOverReaction {
|
||||
private handleDragOver(data: IDragAndDropData, target: ExplorerItem | undefined, targetIndex: number | undefined, originalEvent: DragEvent): boolean | ITreeDragOverReaction {
|
||||
const isCopy = originalEvent && ((originalEvent.ctrlKey && !isMacintosh) || (originalEvent.altKey && isMacintosh));
|
||||
const fromDesktop = data instanceof DesktopDragAndDropData;
|
||||
const effect = (fromDesktop || isCopy) ? ListDragOverEffect.Copy : ListDragOverEffect.Move;
|
||||
@@ -939,32 +962,163 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
|
||||
}
|
||||
|
||||
private async handleWebExternalDrop(data: DesktopDragAndDropData, target: ExplorerItem, originalEvent: DragEvent): Promise<void> {
|
||||
data.files.forEach(file => {
|
||||
const items = (originalEvent.dataTransfer as unknown as IWebkitDataTransfer).items;
|
||||
|
||||
// Somehow the items thing is being modified at random, maybe as a security
|
||||
// measure since this is a DND operation. As such, we copy the items into
|
||||
// an array we own as early as possible before using it.
|
||||
const entries: IWebkitDataTransferItemEntry[] = [];
|
||||
for (const item of items) {
|
||||
entries.push(item.webkitGetAsEntry());
|
||||
}
|
||||
|
||||
const results: { isFile: boolean, resource: URI }[] = [];
|
||||
const cts = new CancellationTokenSource();
|
||||
|
||||
// Start upload and report progress globally
|
||||
const uploadPromise = this.progressService.withProgress({
|
||||
location: ProgressLocation.Window,
|
||||
delay: 800,
|
||||
cancellable: true,
|
||||
title: localize('uploadingFiles', "Uploading")
|
||||
}, async progress => {
|
||||
for (let entry of entries) {
|
||||
const result = await this.doUploadWebFileEntry(entry, target.resource, target, progress, cts.token);
|
||||
if (result) {
|
||||
results.push(result);
|
||||
}
|
||||
}
|
||||
}, () => cts.dispose(true));
|
||||
|
||||
// Also indicate progress in the files view
|
||||
this.progressService.withProgress({ location: VIEW_ID, delay: 800 }, () => uploadPromise);
|
||||
|
||||
// Wait until upload is done
|
||||
await uploadPromise;
|
||||
|
||||
// Open uploaded file in editor only if we upload just one
|
||||
if (!cts.token.isCancellationRequested && results.length === 1 && results[0].isFile) {
|
||||
await this.editorService.openEditor({ resource: results[0].resource, options: { pinned: true } });
|
||||
}
|
||||
}
|
||||
|
||||
private async doUploadWebFileEntry(entry: IWebkitDataTransferItemEntry, parentResource: URI, target: ExplorerItem | undefined, progress: IProgress<IProgressStep>, token: CancellationToken): Promise<{ isFile: boolean, resource: URI } | undefined> {
|
||||
if (token.isCancellationRequested || !entry.name || (!entry.isFile && !entry.isDirectory)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const resource = joinPath(parentResource, entry.name);
|
||||
|
||||
// Confirm overwrite as needed
|
||||
if (target && target.getChild(entry.name)) {
|
||||
const { confirmed } = await this.dialogService.confirm(getFileOverwriteConfirm(resource.path));
|
||||
if (!confirmed) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Report progress
|
||||
progress.report({ message: entry.name });
|
||||
|
||||
// Handle file upload
|
||||
if (entry.isFile) {
|
||||
const file = await new Promise<File>((resolve, reject) => entry.file(resolve, reject));
|
||||
|
||||
if (token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Chrome/Edge/Firefox support stream method
|
||||
if (typeof file.stream === 'function') {
|
||||
await this.doUploadWebFileEntryBuffered(resource, file);
|
||||
}
|
||||
|
||||
// Fallback to unbuffered upload for other browsers
|
||||
else {
|
||||
await this.doUploadWebFileEntryUnbuffered(resource, file);
|
||||
}
|
||||
|
||||
return { isFile: true, resource };
|
||||
}
|
||||
|
||||
// Handle folder upload
|
||||
else {
|
||||
|
||||
// Create target folder
|
||||
await this.fileService.createFolder(resource);
|
||||
|
||||
if (token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Recursive upload files in this directory
|
||||
const folderTarget = target && target.getChild(entry.name) || undefined;
|
||||
const dirReader = entry.createReader();
|
||||
const childEntries = await new Promise<IWebkitDataTransferItemEntry[]>((resolve, reject) => {
|
||||
dirReader.readEntries(resolve, reject);
|
||||
});
|
||||
|
||||
for (let childEntry of childEntries) {
|
||||
await this.doUploadWebFileEntry(childEntry, resource, folderTarget, progress, token);
|
||||
}
|
||||
|
||||
return { isFile: false, resource };
|
||||
}
|
||||
}
|
||||
|
||||
private async doUploadWebFileEntryBuffered(resource: URI, file: File): Promise<void> {
|
||||
const writeableStream = newWriteableBufferStream();
|
||||
|
||||
// Read the file in chunks using File.stream() web APIs
|
||||
(async () => {
|
||||
try {
|
||||
const reader: ReadableStreamDefaultReader<Uint8Array> = file.stream().getReader();
|
||||
|
||||
let res = await reader.read();
|
||||
while (!res.done) {
|
||||
writeableStream.write(VSBuffer.wrap(res.value));
|
||||
|
||||
res = await reader.read();
|
||||
}
|
||||
writeableStream.end(res.value instanceof Uint8Array ? VSBuffer.wrap(res.value) : undefined);
|
||||
} catch (error) {
|
||||
writeableStream.end(error);
|
||||
}
|
||||
})();
|
||||
|
||||
await this.fileService.writeFile(resource, writeableStream);
|
||||
}
|
||||
|
||||
private doUploadWebFileEntryUnbuffered(resource: URI, file: File): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsArrayBuffer(file);
|
||||
reader.onload = async (event) => {
|
||||
const name = file.name;
|
||||
if (typeof name === 'string' && event.target?.result instanceof ArrayBuffer) {
|
||||
if (target.getChild(name)) {
|
||||
const { confirmed } = await this.dialogService.confirm(getFileOverwriteConfirm(name));
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
reader.onload = async event => {
|
||||
try {
|
||||
if (event.target?.result instanceof ArrayBuffer) {
|
||||
await this.fileService.writeFile(resource, VSBuffer.wrap(new Uint8Array(event.target.result)));
|
||||
} else {
|
||||
throw new Error('Could not read from dropped file.');
|
||||
}
|
||||
|
||||
const resource = joinPath(target.resource, name);
|
||||
await this.fileService.writeFile(resource, VSBuffer.wrap(new Uint8Array(event.target.result)));
|
||||
if (data.files.length === 1) {
|
||||
await this.editorService.openEditor({ resource, options: { pinned: true } });
|
||||
}
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Start reading the file to trigger `onload`
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
}
|
||||
|
||||
private async handleExternalDrop(data: DesktopDragAndDropData, target: ExplorerItem, originalEvent: DragEvent): Promise<void> {
|
||||
const droppedResources = extractResources(originalEvent, true);
|
||||
|
||||
// Check for dropped external files to be folders
|
||||
const droppedResources = extractResources(originalEvent, true);
|
||||
const result = await this.fileService.resolveAll(droppedResources.map(droppedResource => ({ resource: droppedResource.resource })));
|
||||
|
||||
// Pass focus to window
|
||||
@@ -973,7 +1127,6 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
|
||||
// Handle folders by adding to workspace if we are in workspace context
|
||||
const folders = result.filter(r => r.success && r.stat && r.stat.isDirectory).map(result => ({ uri: result.stat!.resource }));
|
||||
if (folders.length > 0) {
|
||||
|
||||
const buttons = [
|
||||
folders.length > 1 ? localize('copyFolders', "&&Copy Folders") : localize('copyFolder', "&&Copy Folder"),
|
||||
localize('cancel', "Cancel")
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .open-editors .open-editor,
|
||||
.hc-black .monaco-workbench .open-editors .editor-group {
|
||||
.monaco-workbench.hc-black .open-editors .open-editor,
|
||||
.monaco-workbench.hc-black .open-editors .editor-group {
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { EncodingMode, IFileEditorInput, Verbosity, TextResourceEditorInput, GroupIdentifier, IMoveResult, isTextEditorPane } from 'vs/workbench/common/editor';
|
||||
import { EncodingMode, IFileEditorInput, Verbosity, GroupIdentifier, IMoveResult, isTextEditorPane } from 'vs/workbench/common/editor';
|
||||
import { AbstractTextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput';
|
||||
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
|
||||
import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files';
|
||||
import { ITextFileService, TextFileEditorModelState, TextFileLoadReason, TextFileOperationError, TextFileOperationResult, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
@@ -30,7 +31,7 @@ const enum ForceOpenAs {
|
||||
/**
|
||||
* A file editor input is the input type for the file editor of file system resources.
|
||||
*/
|
||||
export class FileEditorInput extends TextResourceEditorInput implements IFileEditorInput {
|
||||
export class FileEditorInput extends AbstractTextResourceEditorInput implements IFileEditorInput {
|
||||
|
||||
private preferredEncoding: string | undefined;
|
||||
private preferredMode: string | undefined;
|
||||
|
||||
@@ -126,10 +126,10 @@ export class ExplorerService implements IExplorerService {
|
||||
await this.view.setEditable(stat, isEditing);
|
||||
}
|
||||
|
||||
setToCopy(items: ExplorerItem[], cut: boolean): void {
|
||||
async setToCopy(items: ExplorerItem[], cut: boolean): Promise<void> {
|
||||
const previouslyCutItems = this.cutItems;
|
||||
this.cutItems = cut ? items : undefined;
|
||||
this.clipboardService.writeResources(items.map(s => s.resource));
|
||||
await this.clipboardService.writeResources(items.map(s => s.resource));
|
||||
|
||||
this.view?.itemsCopied(items, cut, previouslyCutItems);
|
||||
}
|
||||
@@ -150,10 +150,11 @@ export class ExplorerService implements IExplorerService {
|
||||
return !!this.editable && (this.editable.stat === stat || !stat);
|
||||
}
|
||||
|
||||
async select(resource: URI, reveal?: boolean): Promise<void> {
|
||||
async select(resource: URI, reveal?: boolean | string): Promise<void> {
|
||||
if (!this.view) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fileStat = this.findClosest(resource);
|
||||
if (fileStat) {
|
||||
await this.view.selectResource(fileStat.resource, reveal);
|
||||
@@ -197,7 +198,7 @@ export class ExplorerService implements IExplorerService {
|
||||
|
||||
if (reveal && resource && autoReveal) {
|
||||
// We did a top level refresh, reveal the active file #67118
|
||||
this.select(resource, true);
|
||||
this.select(resource, autoReveal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,14 +51,14 @@ export interface IExplorerService {
|
||||
isEditable(stat: ExplorerItem | undefined): boolean;
|
||||
findClosest(resource: URI): ExplorerItem | null;
|
||||
refresh(): Promise<void>;
|
||||
setToCopy(stats: ExplorerItem[], cut: boolean): void;
|
||||
setToCopy(stats: ExplorerItem[], cut: boolean): Promise<void>;
|
||||
isCut(stat: ExplorerItem): boolean;
|
||||
|
||||
/**
|
||||
* Selects and reveal the file element provided by the given resource if its found in the explorer.
|
||||
* Will try to resolve the path in case the explorer is not yet expanded to the file yet.
|
||||
*/
|
||||
select(resource: URI, reveal?: boolean): Promise<void>;
|
||||
select(resource: URI, reveal?: boolean | string): Promise<void>;
|
||||
|
||||
registerView(contextAndRefreshProvider: IExplorerView): void;
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export interface IExplorerService {
|
||||
export interface IExplorerView {
|
||||
getContext(respectMultiSelection: boolean): ExplorerItem[];
|
||||
refresh(recursive: boolean, item?: ExplorerItem): Promise<void>;
|
||||
selectResource(resource: URI | undefined, reveal?: boolean): Promise<void>;
|
||||
selectResource(resource: URI | undefined, reveal?: boolean | string): Promise<void>;
|
||||
setTreeInput(): Promise<void>;
|
||||
itemsCopied(tats: ExplorerItem[], cut: boolean, previousCut: ExplorerItem[] | undefined): void;
|
||||
setEditable(stat: ExplorerItem, isEditing: boolean): Promise<void>;
|
||||
@@ -121,7 +121,7 @@ export interface IFilesConfiguration extends PlatformIFilesConfiguration, IWorkb
|
||||
openEditors: {
|
||||
visible: number;
|
||||
};
|
||||
autoReveal: boolean;
|
||||
autoReveal: boolean | 'focusNoScroll';
|
||||
enableDragAndDrop: boolean;
|
||||
confirmDelete: boolean;
|
||||
sortOrder: SortOrder;
|
||||
|
||||
@@ -13,7 +13,7 @@ import { IEditorInput, IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { DEFAULT_EDITOR_ID } from 'vs/workbench/contrib/files/common/files';
|
||||
import { CustomEditorAssociation, CustomEditorsAssociations, customEditorsAssociationsSettingId } from 'vs/workbench/services/editor/common/editorAssociationsSetting';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorGroup, OpenEditorContext } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService, IOpenEditorOverrideEntry, IOpenEditorOverrideHandler } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
const builtinProviderDisplayName = nls.localize('builtinProviderDisplayName', "Built-in");
|
||||
@@ -45,7 +45,7 @@ export async function openEditorWith(
|
||||
|
||||
const overrideToUse = typeof id === 'string' && allEditorOverrides.find(([_, entry]) => entry.id === id);
|
||||
if (overrideToUse) {
|
||||
return overrideToUse[0].open(input, options, group, id)?.override;
|
||||
return overrideToUse[0].open(input, options, group, OpenEditorContext.NEW_EDITOR, id)?.override;
|
||||
}
|
||||
|
||||
// Prompt
|
||||
@@ -108,7 +108,7 @@ export async function openEditorWith(
|
||||
picker.show();
|
||||
});
|
||||
|
||||
return pickedItem?.handler.open(input!, options, group, pickedItem.id)?.override;
|
||||
return pickedItem?.handler.open(input!, options, group, OpenEditorContext.NEW_EDITOR, pickedItem.id)?.override;
|
||||
}
|
||||
|
||||
export const defaultEditorOverrideEntry = Object.freeze({
|
||||
|
||||
@@ -9,7 +9,7 @@ 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 { IElectronService } from 'vs/platform/electron/electron-sandbox/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';
|
||||
@@ -17,7 +17,7 @@ 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 { revealResourcesInOS } from 'vs/workbench/contrib/files/electron-sandbox/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';
|
||||
@@ -9,7 +9,7 @@ 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';
|
||||
import { IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
|
||||
|
||||
// Commands
|
||||
|
||||
@@ -3,17 +3,13 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
import * as nls from 'vs/nls';
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { EditorInput } from 'vs/workbench/common/editor';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||
import { NativeTextFileEditor } from 'vs/workbench/contrib/files/electron-browser/textFileEditor';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { NativeTextFileEditor } from 'vs/workbench/contrib/files/electron-sandbox/textFileEditor';
|
||||
|
||||
// Register file editor
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
@@ -26,8 +22,3 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
new SyncDescriptor<EditorInput>(FileEditorInput)
|
||||
]
|
||||
);
|
||||
|
||||
// Register mkdtemp command
|
||||
CommandsRegistry.registerCommand('mkdtemp', function () {
|
||||
return fs.promises.mkdtemp(join(os.tmpdir(), 'vscodetmp-'));
|
||||
});
|
||||
@@ -7,8 +7,7 @@ import * as nls from 'vs/nls';
|
||||
import { TextFileEditor } from 'vs/workbench/contrib/files/browser/editors/textFileEditor';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files';
|
||||
import { MIN_MAX_MEMORY_SIZE_MB, FALLBACK_MAX_MEMORY_SIZE_MB } from 'vs/platform/files/node/files';
|
||||
import { FileOperationError, FileOperationResult, IFileService, MIN_MAX_MEMORY_SIZE_MB, FALLBACK_MAX_MEMORY_SIZE_MB } from 'vs/platform/files/common/files';
|
||||
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
@@ -23,7 +22,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
||||
import { IElectronService } from 'vs/platform/electron/node/electron';
|
||||
import { IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
/**
|
||||
@@ -47,4 +47,8 @@ class RegisterIssueContribution implements IWorkbenchContribution {
|
||||
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(RegisterIssueContribution, LifecyclePhase.Starting);
|
||||
|
||||
CommandsRegistry.registerCommand('_issues.getSystemStatus', (accessor) => {
|
||||
return nls.localize('statusUnsupported', "The --status argument is not yet supported in browsers.");
|
||||
});
|
||||
|
||||
registerSingleton(IWebIssueService, WebIssueService, true);
|
||||
@@ -13,7 +13,8 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issue';
|
||||
import { WorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issueService';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { IIssueService, IssueReporterData } from 'vs/platform/issue/node/issue';
|
||||
import { IssueReporterData } from 'vs/platform/issue/common/issue';
|
||||
import { IIssueService } from 'vs/platform/issue/electron-sandbox/issue';
|
||||
import { OpenIssueReporterArgs, OpenIssueReporterActionId } from 'vs/workbench/contrib/issue/common/commands';
|
||||
|
||||
const helpCategory = { value: nls.localize('help', "Help"), original: 'Help' };
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IssueReporterData } from 'vs/platform/issue/node/issue';
|
||||
import { IssueReporterData } from 'vs/platform/issue/common/issue';
|
||||
|
||||
export const IWorkbenchIssueService = createDecorator<IWorkbenchIssueService>('workbenchIssueService');
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IssueType } from 'vs/platform/issue/node/issue';
|
||||
import { IssueType } from 'vs/platform/issue/common/issue';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issue';
|
||||
|
||||
export class OpenProcessExplorer extends Action {
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IssueReporterStyles, IIssueService, IssueReporterData, ProcessExplorerData, IssueReporterExtensionData } from 'vs/platform/issue/node/issue';
|
||||
import { IssueReporterStyles, IssueReporterData, ProcessExplorerData, IssueReporterExtensionData } from 'vs/platform/issue/common/issue';
|
||||
import { IIssueService } from 'vs/platform/issue/electron-sandbox/issue';
|
||||
import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { textLinkForeground, inputBackground, inputBorder, inputForeground, buttonBackground, buttonHoverBackground, buttonForeground, inputValidationErrorBorder, foreground, inputActiveOptionBorder, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, editorBackground, editorForeground, listHoverBackground, listHoverForeground, listHighlightForeground, textLinkActiveForeground, inputValidationErrorBackground, inputValidationErrorForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { webFrame } from 'electron';
|
||||
import { webFrame } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/electron-browser/issue';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user