SQL Operations Studio Public Preview 1 (0.23) release source code
21
src/vs/workbench/parts/backup/common/backup.contribution.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { BackupModelTracker } from 'vs/workbench/parts/backup/common/backupModelTracker';
|
||||
import { BackupRestorer } from 'vs/workbench/parts/backup/common/backupRestorer';
|
||||
|
||||
// Register Backup Model Tracker
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
|
||||
BackupModelTracker
|
||||
);
|
||||
|
||||
// Register Backup Restorer
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
|
||||
BackupRestorer
|
||||
);
|
||||
99
src/vs/workbench/parts/backup/common/backupModelTracker.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import Uri from 'vs/base/common/uri';
|
||||
import errors = require('vs/base/common/errors');
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ITextFileService, TextFileModelChangeEvent, StateChange } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IFilesConfiguration, AutoSaveConfiguration, CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files';
|
||||
|
||||
const AUTO_SAVE_AFTER_DELAY_DISABLED_TIME = CONTENT_CHANGE_EVENT_BUFFER_DELAY + 500;
|
||||
|
||||
export class BackupModelTracker implements IWorkbenchContribution {
|
||||
|
||||
public _serviceBrand: any;
|
||||
|
||||
private configuredAutoSaveAfterDelay: boolean;
|
||||
private toDispose: IDisposable[];
|
||||
|
||||
constructor(
|
||||
@IBackupFileService private backupFileService: IBackupFileService,
|
||||
@ITextFileService private textFileService: ITextFileService,
|
||||
@IUntitledEditorService private untitledEditorService: IUntitledEditorService,
|
||||
@IConfigurationService private configurationService: IConfigurationService
|
||||
) {
|
||||
this.toDispose = [];
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners() {
|
||||
if (!this.backupFileService.backupEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Listen for text file model changes
|
||||
this.toDispose.push(this.textFileService.models.onModelContentChanged((e) => this.onTextFileModelChanged(e)));
|
||||
this.toDispose.push(this.textFileService.models.onModelSaved((e) => this.discardBackup(e.resource)));
|
||||
this.toDispose.push(this.textFileService.models.onModelDisposed((e) => this.discardBackup(e)));
|
||||
|
||||
// Listen for untitled model changes
|
||||
this.toDispose.push(this.untitledEditorService.onDidChangeContent((e) => this.onUntitledModelChanged(e)));
|
||||
this.toDispose.push(this.untitledEditorService.onDidDisposeModel((e) => this.discardBackup(e)));
|
||||
|
||||
// Listen to config changes
|
||||
this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration<IFilesConfiguration>())));
|
||||
}
|
||||
|
||||
private onConfigurationChange(configuration: IFilesConfiguration): void {
|
||||
if (!configuration || !configuration.files) {
|
||||
this.configuredAutoSaveAfterDelay = false;
|
||||
return;
|
||||
}
|
||||
this.configuredAutoSaveAfterDelay =
|
||||
(configuration.files.autoSave === AutoSaveConfiguration.AFTER_DELAY &&
|
||||
configuration.files.autoSaveDelay <= AUTO_SAVE_AFTER_DELAY_DISABLED_TIME);
|
||||
}
|
||||
|
||||
private onTextFileModelChanged(event: TextFileModelChangeEvent): void {
|
||||
if (event.kind === StateChange.REVERTED) {
|
||||
// This must proceed even if auto save after delay is configured in order to clean up
|
||||
// any backups made before the config change
|
||||
this.discardBackup(event.resource);
|
||||
} else if (event.kind === StateChange.CONTENT_CHANGE) {
|
||||
// Do not backup when auto save after delay is configured
|
||||
if (!this.configuredAutoSaveAfterDelay) {
|
||||
const model = this.textFileService.models.get(event.resource);
|
||||
this.backupFileService.backupResource(model.getResource(), model.getValue(), model.getVersionId()).done(null, errors.onUnexpectedError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private onUntitledModelChanged(resource: Uri): void {
|
||||
if (this.untitledEditorService.isDirty(resource)) {
|
||||
this.untitledEditorService.loadOrCreate({ resource }).then(model => this.backupFileService.backupResource(resource, model.getValue(), model.getVersionId())).done(null, errors.onUnexpectedError);
|
||||
} else {
|
||||
this.discardBackup(resource);
|
||||
}
|
||||
}
|
||||
|
||||
private discardBackup(resource: Uri): void {
|
||||
this.backupFileService.discardResourceBackup(resource).done(null, errors.onUnexpectedError);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.toDispose = dispose(this.toDispose);
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return 'vs.backup.backupModelTracker';
|
||||
}
|
||||
}
|
||||
112
src/vs/workbench/parts/backup/common/backupRestorer.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IUntitledEditorService, UNTITLED_SCHEMA } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import errors = require('vs/base/common/errors');
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { Position, IResourceInput, IUntitledResourceInput } from 'vs/platform/editor/common/editor';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
export class BackupRestorer implements IWorkbenchContribution {
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
private static readonly SQLQUERY_REGEX = /SQLQuery\d+/;
|
||||
private static readonly UNTITLED_REGEX = /Untitled-\d+/;
|
||||
|
||||
constructor(
|
||||
@IUntitledEditorService private untitledEditorService: IUntitledEditorService,
|
||||
@IPartService private partService: IPartService,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@IBackupFileService private backupFileService: IBackupFileService,
|
||||
@ITextFileService private textFileService: ITextFileService,
|
||||
@IEditorGroupService private groupService: IEditorGroupService
|
||||
) {
|
||||
this.restoreBackups();
|
||||
}
|
||||
|
||||
private restoreBackups(): void {
|
||||
if (this.backupFileService.backupEnabled) {
|
||||
this.partService.joinCreation().then(() => {
|
||||
this.doRestoreBackups().done(null, errors.onUnexpectedError);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private doRestoreBackups(): TPromise<URI[]> {
|
||||
|
||||
// Find all files and untitled with backups
|
||||
return this.backupFileService.getWorkspaceFileBackups().then(backups => {
|
||||
|
||||
// Resolve backups that are opened in stacks model
|
||||
return this.doResolveOpenedBackups(backups).then(unresolved => {
|
||||
|
||||
// Some failed to restore or were not opened at all so we open and resolve them manually
|
||||
if (unresolved.length > 0) {
|
||||
return this.doOpenEditors(unresolved).then(() => this.doResolveOpenedBackups(unresolved));
|
||||
}
|
||||
|
||||
return void 0;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private doResolveOpenedBackups(backups: URI[]): TPromise<URI[]> {
|
||||
const stacks = this.groupService.getStacksModel();
|
||||
|
||||
const restorePromises: TPromise<any>[] = [];
|
||||
const unresolved: URI[] = [];
|
||||
|
||||
backups.forEach(backup => {
|
||||
if (stacks.isOpen(backup)) {
|
||||
if (backup.scheme === Schemas.file) {
|
||||
restorePromises.push(this.textFileService.models.loadOrCreate(backup).then(null, () => unresolved.push(backup)));
|
||||
} else if (backup.scheme === UNTITLED_SCHEMA) {
|
||||
restorePromises.push(this.untitledEditorService.loadOrCreate({ resource: backup }).then(null, () => unresolved.push(backup)));
|
||||
}
|
||||
} else {
|
||||
unresolved.push(backup);
|
||||
}
|
||||
});
|
||||
|
||||
return TPromise.join(restorePromises).then(() => unresolved, () => unresolved);
|
||||
}
|
||||
|
||||
private doOpenEditors(resources: URI[]): TPromise<void> {
|
||||
const stacks = this.groupService.getStacksModel();
|
||||
const hasOpenedEditors = stacks.groups.length > 0;
|
||||
const inputs = resources.map((resource, index) => this.resolveInput(resource, index, hasOpenedEditors));
|
||||
|
||||
// Open all remaining backups as editors and resolve them to load their backups
|
||||
return this.editorService.openEditors(inputs.map(input => { return { input, position: Position.ONE }; })).then(() => void 0);
|
||||
}
|
||||
|
||||
private resolveInput(resource: URI, index: number, hasOpenedEditors: boolean): IResourceInput | IUntitledResourceInput {
|
||||
const options = { pinned: true, preserveFocus: true, inactive: index > 0 || hasOpenedEditors };
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
if (resource.scheme === UNTITLED_SCHEMA
|
||||
&& !BackupRestorer.UNTITLED_REGEX.test(resource.fsPath)
|
||||
&& !BackupRestorer.SQLQUERY_REGEX.test(resource.fsPath)) {
|
||||
// TODO@Ben debt: instead of guessing if an untitled file has an associated file path or not
|
||||
// this information should be provided by the backup service and stored as meta data within
|
||||
return { filePath: resource.fsPath, options };
|
||||
}
|
||||
|
||||
return { resource, options };
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return 'vs.backup.backupRestorer';
|
||||
}
|
||||
}
|
||||
159
src/vs/workbench/parts/cli/electron-browser/cli.contribution.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as path from 'path';
|
||||
import * as cp from 'child_process';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import { nfcall } from 'vs/base/common/async';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { IMessageService, Severity } from 'vs/platform/message/common/message';
|
||||
import { IEditorService } from 'vs/platform/editor/common/editor';
|
||||
import product from 'vs/platform/node/product';
|
||||
|
||||
interface ILegacyUse {
|
||||
file: string;
|
||||
lineNumber: number;
|
||||
}
|
||||
|
||||
function ignore<T>(code: string, value: T = null): (err: any) => TPromise<T> {
|
||||
return err => err.code === code ? TPromise.as<T>(value) : TPromise.wrapError<T>(err);
|
||||
}
|
||||
|
||||
const root = URI.parse(require.toUrl('')).fsPath;
|
||||
const source = path.resolve(root, '..', 'bin', 'code');
|
||||
|
||||
function isAvailable(): TPromise<boolean> {
|
||||
return pfs.exists(source);
|
||||
}
|
||||
|
||||
class InstallAction extends Action {
|
||||
|
||||
static ID = 'workbench.action.installCommandLine';
|
||||
static LABEL = nls.localize('install', "Install '{0}' command in PATH", product.applicationName);
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IMessageService private messageService: IMessageService,
|
||||
@IEditorService private editorService: IEditorService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
private get target(): string {
|
||||
return `/usr/local/bin/${product.applicationName}`;
|
||||
}
|
||||
|
||||
run(): TPromise<void> {
|
||||
return isAvailable().then(isAvailable => {
|
||||
if (!isAvailable) {
|
||||
const message = nls.localize('not available', "This command is not available");
|
||||
this.messageService.show(Severity.Info, message);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.isInstalled()
|
||||
.then(isInstalled => {
|
||||
if (!isAvailable || isInstalled) {
|
||||
return TPromise.as(null);
|
||||
} else {
|
||||
const createSymlink = () => {
|
||||
return pfs.unlink(this.target)
|
||||
.then(null, ignore('ENOENT'))
|
||||
.then(() => pfs.symlink(source, this.target));
|
||||
};
|
||||
|
||||
return createSymlink().then(null, err => {
|
||||
if (err.code === 'EACCES' || err.code === 'ENOENT') {
|
||||
return this.createBinFolder()
|
||||
.then(() => createSymlink());
|
||||
}
|
||||
|
||||
return TPromise.wrapError(err);
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
this.messageService.show(Severity.Info, nls.localize('successIn', "Shell command '{0}' successfully installed in PATH.", product.applicationName));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private isInstalled(): TPromise<boolean> {
|
||||
return pfs.lstat(this.target)
|
||||
.then(stat => stat.isSymbolicLink())
|
||||
.then(() => pfs.readlink(this.target))
|
||||
.then(link => link === source)
|
||||
.then(null, ignore('ENOENT', false));
|
||||
}
|
||||
|
||||
private createBinFolder(): TPromise<void> {
|
||||
return new TPromise<void>((c, e) => {
|
||||
const message = nls.localize('warnEscalation', "Code will now prompt with 'osascript' for Administrator privileges to install the shell command.");
|
||||
const actions = [
|
||||
new Action('ok', nls.localize('ok', "OK"), '', true, () => {
|
||||
const command = 'osascript -e "do shell script \\"mkdir -p /usr/local/bin && chown \\" & (do shell script (\\"whoami\\")) & \\" /usr/local/bin\\" with administrator privileges"';
|
||||
|
||||
nfcall(cp.exec, command, {})
|
||||
.then(null, _ => TPromise.wrapError(new Error(nls.localize('cantCreateBinFolder', "Unable to create '/usr/local/bin'."))))
|
||||
.done(c, e);
|
||||
|
||||
return null;
|
||||
}),
|
||||
new Action('cancel2', nls.localize('cancel2', "Cancel"), '', true, () => { e(new Error(nls.localize('aborted', "Aborted"))); return null; })
|
||||
];
|
||||
|
||||
this.messageService.show(Severity.Info, { message, actions });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class UninstallAction extends Action {
|
||||
|
||||
static ID = 'workbench.action.uninstallCommandLine';
|
||||
static LABEL = nls.localize('uninstall', "Uninstall '{0}' command from PATH", product.applicationName);
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IMessageService private messageService: IMessageService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
private get target(): string {
|
||||
return `/usr/local/bin/${product.applicationName}`;
|
||||
}
|
||||
|
||||
run(): TPromise<void> {
|
||||
return isAvailable().then(isAvailable => {
|
||||
if (!isAvailable) {
|
||||
const message = nls.localize('not available', "This command is not available");
|
||||
this.messageService.show(Severity.Info, message);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return pfs.unlink(this.target)
|
||||
.then(null, ignore('ENOENT'))
|
||||
.then(() => {
|
||||
this.messageService.show(Severity.Info, nls.localize('successFrom', "Shell command '{0}' successfully uninstalled from PATH.", product.applicationName));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
const category = nls.localize('shellCommand', "Shell Command");
|
||||
|
||||
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(InstallAction, InstallAction.ID, InstallAction.LABEL), 'Shell Command: Install \'code\' command in PATH', category);
|
||||
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(UninstallAction, UninstallAction.ID, UninstallAction.LABEL), 'Shell Command: Uninstall \'code\' command from PATH', category);
|
||||
}
|
||||
16
src/vs/workbench/parts/codeEditor/codeEditor.contribution.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import './electron-browser/accessibility';
|
||||
import './electron-browser/inspectKeybindings';
|
||||
import './electron-browser/menuPreventer';
|
||||
import './electron-browser/selectionClipboard';
|
||||
import './electron-browser/textMate/inspectTMScopes';
|
||||
import './electron-browser/toggleMinimap';
|
||||
import './electron-browser/toggleMultiCursorModifier';
|
||||
import './electron-browser/toggleRenderControlCharacter';
|
||||
import './electron-browser/toggleRenderWhitespace';
|
||||
import './electron-browser/toggleWordWrap';
|
||||
import './electron-browser/wordWrapMigration';
|
||||
@@ -0,0 +1,9 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .accessibilityHelpWidget {
|
||||
padding: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./accessibility';
|
||||
import * as nls from 'vs/nls';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { renderFormattedText } from 'vs/base/browser/htmlContentRenderer';
|
||||
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ICommonCodeEditor, IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { editorAction, CommonEditorRegistry, EditorAction, EditorCommand } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser';
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import { ToggleTabFocusModeAction } from 'vs/editor/contrib/toggleTabFocusMode/common/toggleTabFocusMode';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { editorWidgetBackground, widgetShadow, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import * as editorOptions from 'vs/editor/common/config/editorOptions';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
|
||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import URI from 'vs/base/common/uri';
|
||||
|
||||
const CONTEXT_ACCESSIBILITY_WIDGET_VISIBLE = new RawContextKey<boolean>('accessibilityHelpWidgetVisible', false);
|
||||
|
||||
@editorContribution
|
||||
class AccessibilityHelpController extends Disposable implements IEditorContribution {
|
||||
|
||||
private static ID = 'editor.contrib.accessibilityHelpController';
|
||||
|
||||
public static get(editor: ICommonCodeEditor): AccessibilityHelpController {
|
||||
return editor.getContribution<AccessibilityHelpController>(AccessibilityHelpController.ID);
|
||||
}
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _widget: AccessibilityHelpWidget;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._editor = editor;
|
||||
this._widget = this._register(instantiationService.createInstance(AccessibilityHelpWidget, this._editor));
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return AccessibilityHelpController.ID;
|
||||
}
|
||||
|
||||
public show(): void {
|
||||
this._widget.show();
|
||||
}
|
||||
|
||||
public hide(): void {
|
||||
this._widget.hide();
|
||||
}
|
||||
}
|
||||
|
||||
class AccessibilityHelpWidget extends Widget implements IOverlayWidget {
|
||||
|
||||
private static ID = 'editor.contrib.accessibilityHelpWidget';
|
||||
private static WIDTH = 500;
|
||||
private static HEIGHT = 300;
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _domNode: FastDomNode<HTMLElement>;
|
||||
private _contentDomNode: FastDomNode<HTMLElement>;
|
||||
private _isVisible: boolean;
|
||||
private _isVisibleKey: IContextKey<boolean>;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@IContextKeyService private _contextKeyService: IContextKeyService,
|
||||
@IKeybindingService private _keybindingService: IKeybindingService,
|
||||
@IConfigurationService private _configurationService: IConfigurationService,
|
||||
@IConfigurationEditingService private _configurationEditingService: IConfigurationEditingService,
|
||||
@IOpenerService private _openerService: IOpenerService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._editor = editor;
|
||||
this._isVisibleKey = CONTEXT_ACCESSIBILITY_WIDGET_VISIBLE.bindTo(this._contextKeyService);
|
||||
|
||||
this._domNode = createFastDomNode(document.createElement('div'));
|
||||
this._domNode.setClassName('accessibilityHelpWidget');
|
||||
this._domNode.setWidth(AccessibilityHelpWidget.WIDTH);
|
||||
this._domNode.setHeight(AccessibilityHelpWidget.HEIGHT);
|
||||
this._domNode.setDisplay('none');
|
||||
this._domNode.setAttribute('role', 'dialog');
|
||||
this._domNode.setAttribute('aria-hidden', 'true');
|
||||
|
||||
this._contentDomNode = createFastDomNode(document.createElement('div'));
|
||||
this._contentDomNode.setAttribute('role', 'document');
|
||||
this._domNode.appendChild(this._contentDomNode);
|
||||
|
||||
this._isVisible = false;
|
||||
|
||||
this._register(this._editor.onDidLayoutChange(() => {
|
||||
if (this._isVisible) {
|
||||
this._layout();
|
||||
}
|
||||
}));
|
||||
|
||||
// Intentionally not configurable!
|
||||
this._register(dom.addStandardDisposableListener(this._contentDomNode.domNode, 'keydown', (e) => {
|
||||
if (!this._isVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.equals(KeyMod.CtrlCmd | KeyCode.KEY_E)) {
|
||||
alert(nls.localize('emergencyConfOn', "Now changing the setting `editor.accessibilitySupport` to 'on'."));
|
||||
|
||||
this._configurationEditingService.writeConfiguration(ConfigurationTarget.USER, {
|
||||
key: 'editor.accessibilitySupport',
|
||||
value: 'on'
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
if (e.equals(KeyMod.CtrlCmd | KeyCode.KEY_H)) {
|
||||
alert(nls.localize('openingDocs', "Now opening the VS Code Accessibility documentation page."));
|
||||
|
||||
this._openerService.open(URI.parse('https://go.microsoft.com/fwlink/?linkid=851010'));
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}));
|
||||
|
||||
this.onblur(this._contentDomNode.domNode, () => {
|
||||
this.hide();
|
||||
});
|
||||
|
||||
this._editor.addOverlayWidget(this);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._editor.removeOverlayWidget(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return AccessibilityHelpWidget.ID;
|
||||
}
|
||||
|
||||
public getDomNode(): HTMLElement {
|
||||
return this._domNode.domNode;
|
||||
}
|
||||
|
||||
public getPosition(): IOverlayWidgetPosition {
|
||||
return {
|
||||
preference: null
|
||||
};
|
||||
}
|
||||
|
||||
public show(): void {
|
||||
if (this._isVisible) {
|
||||
return;
|
||||
}
|
||||
this._isVisible = true;
|
||||
this._isVisibleKey.set(true);
|
||||
this._layout();
|
||||
this._domNode.setDisplay('block');
|
||||
this._domNode.setAttribute('aria-hidden', 'false');
|
||||
this._contentDomNode.domNode.tabIndex = 0;
|
||||
this._buildContent();
|
||||
this._contentDomNode.domNode.focus();
|
||||
}
|
||||
|
||||
private _descriptionForCommand(commandId: string, msg: string, noKbMsg: string): string {
|
||||
let kb = this._keybindingService.lookupKeybinding(commandId);
|
||||
if (kb) {
|
||||
return strings.format(msg, kb.getAriaLabel());
|
||||
}
|
||||
return strings.format(noKbMsg, commandId);
|
||||
}
|
||||
|
||||
private _buildContent() {
|
||||
let opts = this._editor.getConfiguration();
|
||||
let text = nls.localize('introMsg', "Thank you for trying out VS Code's accessibility options.");
|
||||
|
||||
text += '\n\n' + nls.localize('status', "Status:");
|
||||
|
||||
const configuredValue = this._configurationService.getConfiguration<editorOptions.IEditorOptions>('editor').accessibilitySupport;
|
||||
const actualValue = opts.accessibilitySupport;
|
||||
|
||||
const emergencyTurnOnMessage = (
|
||||
platform.isMacintosh
|
||||
? nls.localize('changeConfigToOnMac', "To configure the editor to be permanently optimized for usage with a Screen Reader press Command+E now.")
|
||||
: nls.localize('changeConfigToOnWinLinux', "To configure the editor to be permanently optimized for usage with a Screen Reader press Control+E now.")
|
||||
);
|
||||
|
||||
switch (configuredValue) {
|
||||
case 'auto':
|
||||
switch (actualValue) {
|
||||
case platform.AccessibilitySupport.Unknown:
|
||||
// Should never happen in VS Code
|
||||
text += '\n\n - ' + nls.localize('auto_unknown', "The editor is configured to use platform APIs to detect when a Screen Reader is attached, but the current runtime does not support this.");
|
||||
break;
|
||||
case platform.AccessibilitySupport.Enabled:
|
||||
text += '\n\n - ' + nls.localize('auto_on', "The editor has automatically detected a Screen Reader is attached.");
|
||||
break;
|
||||
case platform.AccessibilitySupport.Disabled:
|
||||
text += '\n\n - ' + nls.localize('auto_off', "The editor is configured to automatically detect when a Screen Reader is attached, which is not the case at this time.");
|
||||
text += ' ' + emergencyTurnOnMessage;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'on':
|
||||
text += '\n\n - ' + nls.localize('configuredOn', "The editor is configured to be permanently optimized for usage with a Screen Reader - you can change this by editing the setting `editor.accessibilitySupport`.");
|
||||
break;
|
||||
case 'off':
|
||||
text += '\n\n - ' + nls.localize('configuredOff', "The editor is configured to never be optimized for usage with a Screen Reader.");
|
||||
text += ' ' + emergencyTurnOnMessage;
|
||||
break;
|
||||
}
|
||||
|
||||
const NLS_TAB_FOCUS_MODE_ON = nls.localize('tabFocusModeOnMsg', "Pressing Tab in the current editor will move focus to the next focusable element. Toggle this behavior by pressing {0}.");
|
||||
const NLS_TAB_FOCUS_MODE_ON_NO_KB = nls.localize('tabFocusModeOnMsgNoKb', "Pressing Tab in the current editor will move focus to the next focusable element. The command {0} is currently not triggerable by a keybinding.");
|
||||
const NLS_TAB_FOCUS_MODE_OFF = nls.localize('tabFocusModeOffMsg', "Pressing Tab in the current editor will insert the tab character. Toggle this behavior by pressing {0}.");
|
||||
const NLS_TAB_FOCUS_MODE_OFF_NO_KB = nls.localize('tabFocusModeOffMsgNoKb', "Pressing Tab in the current editor will insert the tab character. The command {0} is currently not triggerable by a keybinding.");
|
||||
|
||||
if (opts.tabFocusMode) {
|
||||
text += '\n\n - ' + this._descriptionForCommand(ToggleTabFocusModeAction.ID, NLS_TAB_FOCUS_MODE_ON, NLS_TAB_FOCUS_MODE_ON_NO_KB);
|
||||
} else {
|
||||
text += '\n\n - ' + this._descriptionForCommand(ToggleTabFocusModeAction.ID, NLS_TAB_FOCUS_MODE_OFF, NLS_TAB_FOCUS_MODE_OFF_NO_KB);
|
||||
}
|
||||
|
||||
const openDocMessage = (
|
||||
platform.isMacintosh
|
||||
? nls.localize('openDocMac', "Press Command+H now to open a browser window with more VS Code information related to Accessibility.")
|
||||
: nls.localize('openDocWinLinux', "Press Control+H now to open a browser window with more VS Code information related to Accessibility.")
|
||||
);
|
||||
|
||||
text += '\n\n' + openDocMessage;
|
||||
|
||||
text += '\n\n' + nls.localize('outroMsg', "You can dismiss this tooltip and return to the editor by pressing Escape or Shift+Escape.");
|
||||
|
||||
this._contentDomNode.domNode.appendChild(renderFormattedText(text));
|
||||
// Per https://www.w3.org/TR/wai-aria/roles#document, Authors SHOULD provide a title or label for documents
|
||||
this._contentDomNode.domNode.setAttribute('aria-label', text);
|
||||
}
|
||||
|
||||
public hide(): void {
|
||||
if (!this._isVisible) {
|
||||
return;
|
||||
}
|
||||
this._isVisible = false;
|
||||
this._isVisibleKey.reset();
|
||||
this._domNode.setDisplay('none');
|
||||
this._domNode.setAttribute('aria-hidden', 'true');
|
||||
this._contentDomNode.domNode.tabIndex = -1;
|
||||
dom.clearNode(this._contentDomNode.domNode);
|
||||
|
||||
this._editor.focus();
|
||||
}
|
||||
|
||||
private _layout(): void {
|
||||
let editorLayout = this._editor.getLayoutInfo();
|
||||
|
||||
let top = Math.round((editorLayout.height - AccessibilityHelpWidget.HEIGHT) / 2);
|
||||
this._domNode.setTop(top);
|
||||
|
||||
let left = Math.round((editorLayout.width - AccessibilityHelpWidget.WIDTH) / 2);
|
||||
this._domNode.setLeft(left);
|
||||
}
|
||||
}
|
||||
|
||||
@editorAction
|
||||
class ShowAccessibilityHelpAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.showAccessibilityHelp',
|
||||
label: nls.localize('ShowAccessibilityHelpAction', "Show Accessibility Help"),
|
||||
alias: 'Show Accessibility Help',
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.focus,
|
||||
primary: KeyMod.Alt | KeyCode.F1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
|
||||
let controller = AccessibilityHelpController.get(editor);
|
||||
if (controller) {
|
||||
controller.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const AccessibilityHelpCommand = EditorCommand.bindToContribution<AccessibilityHelpController>(AccessibilityHelpController.get);
|
||||
|
||||
CommonEditorRegistry.registerEditorCommand(new AccessibilityHelpCommand({
|
||||
id: 'closeAccessibilityHelp',
|
||||
precondition: CONTEXT_ACCESSIBILITY_WIDGET_VISIBLE,
|
||||
handler: x => x.hide(),
|
||||
kbOpts: {
|
||||
weight: CommonEditorRegistry.commandWeight(100),
|
||||
kbExpr: EditorContextKeys.focus,
|
||||
primary: KeyCode.Escape, secondary: [KeyMod.Shift | KeyCode.Escape]
|
||||
}
|
||||
}));
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
let widgetBackground = theme.getColor(editorWidgetBackground);
|
||||
if (widgetBackground) {
|
||||
collector.addRule(`.monaco-editor .accessibilityHelpWidget { background-color: ${widgetBackground}; }`);
|
||||
}
|
||||
|
||||
let widgetShadowColor = theme.getColor(widgetShadow);
|
||||
if (widgetShadowColor) {
|
||||
collector.addRule(`.monaco-editor .accessibilityHelpWidget { box-shadow: 0 2px 8px ${widgetShadowColor}; }`);
|
||||
}
|
||||
|
||||
let hcBorder = theme.getColor(contrastBorder);
|
||||
if (hcBorder) {
|
||||
collector.addRule(`.monaco-editor .accessibilityHelpWidget { border: 2px solid ${hcBorder}; }`);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { ICommonCodeEditor } from 'vs/editor/common/editorCommon';
|
||||
import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { WorkbenchKeybindingService } from 'vs/workbench/services/keybinding/electron-browser/keybindingService';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IUntitledResourceInput } from 'vs/platform/editor/common/editor';
|
||||
|
||||
@editorAction
|
||||
class InspectKeyMap extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'workbench.action.inspectKeyMappings',
|
||||
label: nls.localize('workbench.action.inspectKeyMap', "Developer: Inspect Key Mappings"),
|
||||
alias: 'Developer: Inspect Key Mappings',
|
||||
precondition: null
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
|
||||
const keybindingService = accessor.get(IKeybindingService);
|
||||
const editorService = accessor.get(IWorkbenchEditorService);
|
||||
|
||||
if (keybindingService instanceof WorkbenchKeybindingService) {
|
||||
editorService.openEditor({ contents: keybindingService.dumpDebugInfo(), options: { pinned: true } } as IUntitledResourceInput);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { parse, ParseError } from 'vs/base/common/json';
|
||||
import { readFile } from 'vs/base/node/pfs';
|
||||
import { CharacterPair, LanguageConfiguration, IAutoClosingPair, IAutoClosingPairConditional, IndentationRule, CommentRule } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import { LanguageIdentifier } from 'vs/editor/common/modes';
|
||||
import { ITextMateService } from 'vs/workbench/services/textMate/electron-browser/textMateService';
|
||||
|
||||
interface IRegExp {
|
||||
pattern: string;
|
||||
flags?: string;
|
||||
}
|
||||
|
||||
interface IIndentationRules {
|
||||
decreaseIndentPattern: string | IRegExp;
|
||||
increaseIndentPattern: string | IRegExp;
|
||||
indentNextLinePattern?: string | IRegExp;
|
||||
unIndentedLinePattern?: string | IRegExp;
|
||||
}
|
||||
|
||||
interface ILanguageConfiguration {
|
||||
comments?: CommentRule;
|
||||
brackets?: CharacterPair[];
|
||||
autoClosingPairs?: (CharacterPair | IAutoClosingPairConditional)[];
|
||||
surroundingPairs?: (CharacterPair | IAutoClosingPair)[];
|
||||
wordPattern?: string | IRegExp;
|
||||
indentationRules?: IIndentationRules;
|
||||
}
|
||||
|
||||
export class LanguageConfigurationFileHandler {
|
||||
|
||||
private _modeService: IModeService;
|
||||
private _done: boolean[];
|
||||
|
||||
constructor(
|
||||
@ITextMateService textMateService: ITextMateService,
|
||||
@IModeService modeService: IModeService
|
||||
) {
|
||||
this._modeService = modeService;
|
||||
this._done = [];
|
||||
|
||||
// Listen for hints that a language configuration is needed/usefull and then load it once
|
||||
this._modeService.onDidCreateMode((mode) => this._loadConfigurationsForMode(mode.getLanguageIdentifier()));
|
||||
textMateService.onDidEncounterLanguage((languageId) => {
|
||||
this._loadConfigurationsForMode(this._modeService.getLanguageIdentifier(languageId));
|
||||
});
|
||||
}
|
||||
|
||||
private _loadConfigurationsForMode(languageIdentifier: LanguageIdentifier): void {
|
||||
if (this._done[languageIdentifier.id]) {
|
||||
return;
|
||||
}
|
||||
this._done[languageIdentifier.id] = true;
|
||||
|
||||
let configurationFiles = this._modeService.getConfigurationFiles(languageIdentifier.language);
|
||||
configurationFiles.forEach((configFilePath) => this._handleConfigFile(languageIdentifier, configFilePath));
|
||||
}
|
||||
|
||||
private _handleConfigFile(languageIdentifier: LanguageIdentifier, configFilePath: string): void {
|
||||
readFile(configFilePath).then((fileContents) => {
|
||||
const errors: ParseError[] = [];
|
||||
const configuration = <ILanguageConfiguration>parse(fileContents.toString(), errors);
|
||||
if (errors.length) {
|
||||
console.error(nls.localize('parseErrors', "Errors parsing {0}: {1}", configFilePath, errors.join('\n')));
|
||||
}
|
||||
this._handleConfig(languageIdentifier, configuration);
|
||||
}, (err) => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
private _handleConfig(languageIdentifier: LanguageIdentifier, configuration: ILanguageConfiguration): void {
|
||||
|
||||
let richEditConfig: LanguageConfiguration = {};
|
||||
|
||||
if (configuration.comments) {
|
||||
richEditConfig.comments = configuration.comments;
|
||||
}
|
||||
|
||||
if (configuration.brackets) {
|
||||
richEditConfig.brackets = configuration.brackets;
|
||||
}
|
||||
|
||||
if (configuration.autoClosingPairs) {
|
||||
richEditConfig.autoClosingPairs = this._mapCharacterPairs(configuration.autoClosingPairs);
|
||||
}
|
||||
|
||||
if (configuration.surroundingPairs) {
|
||||
richEditConfig.surroundingPairs = this._mapCharacterPairs(configuration.surroundingPairs);
|
||||
}
|
||||
|
||||
if (configuration.wordPattern) {
|
||||
try {
|
||||
let wordPattern = this._parseRegex(configuration.wordPattern);
|
||||
if (wordPattern) {
|
||||
richEditConfig.wordPattern = wordPattern;
|
||||
}
|
||||
} catch (error) {
|
||||
// Malformed regexes are ignored
|
||||
}
|
||||
}
|
||||
|
||||
if (configuration.indentationRules) {
|
||||
let indentationRules = this._mapIndentationRules(configuration.indentationRules);
|
||||
if (indentationRules) {
|
||||
richEditConfig.indentationRules = indentationRules;
|
||||
}
|
||||
}
|
||||
|
||||
LanguageConfigurationRegistry.register(languageIdentifier, richEditConfig);
|
||||
}
|
||||
|
||||
private _parseRegex(value: string | IRegExp) {
|
||||
if (typeof value === 'string') {
|
||||
return new RegExp(value, '');
|
||||
} else if (typeof value === 'object') {
|
||||
return new RegExp(value.pattern, value.flags);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private _mapIndentationRules(indentationRules: IIndentationRules): IndentationRule {
|
||||
try {
|
||||
let increaseIndentPattern = this._parseRegex(indentationRules.increaseIndentPattern);
|
||||
let decreaseIndentPattern = this._parseRegex(indentationRules.decreaseIndentPattern);
|
||||
|
||||
if (increaseIndentPattern && decreaseIndentPattern) {
|
||||
let result: IndentationRule = {
|
||||
increaseIndentPattern: increaseIndentPattern,
|
||||
decreaseIndentPattern: decreaseIndentPattern
|
||||
};
|
||||
|
||||
if (indentationRules.indentNextLinePattern) {
|
||||
result.indentNextLinePattern = this._parseRegex(indentationRules.indentNextLinePattern);
|
||||
}
|
||||
if (indentationRules.unIndentedLinePattern) {
|
||||
result.unIndentedLinePattern = this._parseRegex(indentationRules.unIndentedLinePattern);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
} catch (error) {
|
||||
// Malformed regexes are ignored
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private _mapCharacterPairs(pairs: (CharacterPair | IAutoClosingPairConditional)[]): IAutoClosingPairConditional[] {
|
||||
return pairs.map(pair => {
|
||||
if (Array.isArray(pair)) {
|
||||
return { open: pair[0], close: pair[1] };
|
||||
}
|
||||
return <IAutoClosingPairConditional>pair;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const schemaId = 'vscode://schemas/language-configuration';
|
||||
const schema: IJSONSchema = {
|
||||
default: {
|
||||
comments: {
|
||||
blockComment: ['/*', '*/'],
|
||||
lineComment: '//'
|
||||
},
|
||||
brackets: [['(', ')'], ['[', ']'], ['{', '}']],
|
||||
autoClosingPairs: [['(', ')'], ['[', ']'], ['{', '}']],
|
||||
surroundingPairs: [['(', ')'], ['[', ']'], ['{', '}']]
|
||||
},
|
||||
definitions: {
|
||||
openBracket: {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.openBracket', 'The opening bracket character or string sequence.')
|
||||
},
|
||||
closeBracket: {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.closeBracket', 'The closing bracket character or string sequence.')
|
||||
},
|
||||
bracketPair: {
|
||||
type: 'array',
|
||||
items: [{
|
||||
$ref: '#definitions/openBracket'
|
||||
}, {
|
||||
$ref: '#definitions/closeBracket'
|
||||
}]
|
||||
}
|
||||
},
|
||||
properties: {
|
||||
comments: {
|
||||
default: {
|
||||
blockComment: ['/*', '*/'],
|
||||
lineComment: '//'
|
||||
},
|
||||
description: nls.localize('schema.comments', 'Defines the comment symbols'),
|
||||
type: 'object',
|
||||
properties: {
|
||||
blockComment: {
|
||||
type: 'array',
|
||||
description: nls.localize('schema.blockComments', 'Defines how block comments are marked.'),
|
||||
items: [{
|
||||
type: 'string',
|
||||
description: nls.localize('schema.blockComment.begin', 'The character sequence that starts a block comment.')
|
||||
}, {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.blockComment.end', 'The character sequence that ends a block comment.')
|
||||
}]
|
||||
},
|
||||
lineComment: {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.lineComment', 'The character sequence that starts a line comment.')
|
||||
}
|
||||
}
|
||||
},
|
||||
brackets: {
|
||||
default: [['(', ')'], ['[', ']'], ['{', '}']],
|
||||
description: nls.localize('schema.brackets', 'Defines the bracket symbols that increase or decrease the indentation.'),
|
||||
type: 'array',
|
||||
items: {
|
||||
$ref: '#definitions/bracketPair'
|
||||
}
|
||||
},
|
||||
autoClosingPairs: {
|
||||
default: [['(', ')'], ['[', ']'], ['{', '}']],
|
||||
description: nls.localize('schema.autoClosingPairs', 'Defines the bracket pairs. When a opening bracket is entered, the closing bracket is inserted automatically.'),
|
||||
type: 'array',
|
||||
items: {
|
||||
oneOf: [{
|
||||
$ref: '#definitions/bracketPair'
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
open: {
|
||||
$ref: '#definitions/openBracket'
|
||||
},
|
||||
close: {
|
||||
$ref: '#definitions/closeBracket'
|
||||
},
|
||||
notIn: {
|
||||
type: 'array',
|
||||
description: nls.localize('schema.autoClosingPairs.notIn', 'Defines a list of scopes where the auto pairs are disabled.'),
|
||||
items: {
|
||||
enum: ['string', 'comment']
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
surroundingPairs: {
|
||||
default: [['(', ')'], ['[', ']'], ['{', '}']],
|
||||
description: nls.localize('schema.surroundingPairs', 'Defines the bracket pairs that can be used to surround a selected string.'),
|
||||
type: 'array',
|
||||
items: {
|
||||
oneOf: [{
|
||||
$ref: '#definitions/bracketPair'
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
open: {
|
||||
$ref: '#definitions/openBracket'
|
||||
},
|
||||
close: {
|
||||
$ref: '#definitions/closeBracket'
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
wordPattern: {
|
||||
default: '',
|
||||
description: nls.localize('schema.wordPattern', 'The word definition for the language.'),
|
||||
type: ['string', 'object'],
|
||||
properties: {
|
||||
pattern: {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.wordPattern.pattern', 'The RegExp pattern used to match words.'),
|
||||
default: '',
|
||||
},
|
||||
flags: {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.wordPattern.flags', 'The RegExp flags used to match words.'),
|
||||
default: 'g',
|
||||
pattern: '^([gimuy]+)$',
|
||||
patternErrorMessage: nls.localize('schema.wordPattern.flags.errorMessage', 'Must match the pattern `/^([gimuy]+)$/`.')
|
||||
}
|
||||
}
|
||||
},
|
||||
indentationRules: {
|
||||
default: {
|
||||
increaseIndentPattern: '',
|
||||
decreaseIndentPattern: ''
|
||||
},
|
||||
description: nls.localize('schema.indentationRules', 'The language\'s indentation settings.'),
|
||||
type: 'object',
|
||||
properties: {
|
||||
increaseIndentPattern: {
|
||||
type: ['string', 'object'],
|
||||
description: nls.localize('schema.indentationRules.increaseIndentPattern', 'If a line matches this pattern, then all the lines after it should be indented once (until another rule matches).'),
|
||||
properties: {
|
||||
pattern: {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.indentationRules.increaseIndentPattern.pattern', 'The RegExp pattern for increaseIndentPattern.'),
|
||||
default: '',
|
||||
},
|
||||
flags: {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.indentationRules.increaseIndentPattern.flags', 'The RegExp flags for increaseIndentPattern.'),
|
||||
default: '',
|
||||
pattern: '^([gimuy]+)$',
|
||||
patternErrorMessage: nls.localize('schema.indentationRules.increaseIndentPattern.errorMessage', 'Must match the pattern `/^([gimuy]+)$/`.')
|
||||
}
|
||||
}
|
||||
},
|
||||
decreaseIndentPattern: {
|
||||
type: ['string', 'object'],
|
||||
description: nls.localize('schema.indentationRules.decreaseIndentPattern', 'If a line matches this pattern, then all the lines after it should be unindendented once (until another rule matches).'),
|
||||
properties: {
|
||||
pattern: {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.indentationRules.decreaseIndentPattern.pattern', 'The RegExp pattern for decreaseIndentPattern.'),
|
||||
default: '',
|
||||
},
|
||||
flags: {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.indentationRules.decreaseIndentPattern.flags', 'The RegExp flags for decreaseIndentPattern.'),
|
||||
default: '',
|
||||
pattern: '^([gimuy]+)$',
|
||||
patternErrorMessage: nls.localize('schema.indentationRules.decreaseIndentPattern.errorMessage', 'Must match the pattern `/^([gimuy]+)$/`.')
|
||||
}
|
||||
}
|
||||
},
|
||||
indentNextLinePattern: {
|
||||
type: ['string', 'object'],
|
||||
description: nls.localize('schema.indentationRules.indentNextLinePattern', 'If a line matches this pattern, then **only the next line** after it should be indented once.'),
|
||||
properties: {
|
||||
pattern: {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.indentationRules.indentNextLinePattern.pattern', 'The RegExp pattern for indentNextLinePattern.'),
|
||||
default: '',
|
||||
},
|
||||
flags: {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.indentationRules.indentNextLinePattern.flags', 'The RegExp flags for indentNextLinePattern.'),
|
||||
default: '',
|
||||
pattern: '^([gimuy]+)$',
|
||||
patternErrorMessage: nls.localize('schema.indentationRules.indentNextLinePattern.errorMessage', 'Must match the pattern `/^([gimuy]+)$/`.')
|
||||
}
|
||||
}
|
||||
},
|
||||
unIndentedLinePattern: {
|
||||
type: ['string', 'object'],
|
||||
description: nls.localize('schema.indentationRules.unIndentedLinePattern', 'If a line matches this pattern, then its indentation should not be changed and it should not be evaluated against the other rules.'),
|
||||
properties: {
|
||||
pattern: {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.indentationRules.unIndentedLinePattern.pattern', 'The RegExp pattern for unIndentedLinePattern.'),
|
||||
default: '',
|
||||
},
|
||||
flags: {
|
||||
type: 'string',
|
||||
description: nls.localize('schema.indentationRules.unIndentedLinePattern.flags', 'The RegExp flags for unIndentedLinePattern.'),
|
||||
default: '',
|
||||
pattern: '^([gimuy]+)$',
|
||||
patternErrorMessage: nls.localize('schema.indentationRules.unIndentedLinePattern.errorMessage', 'Must match the pattern `/^([gimuy]+)$/`.')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let schemaRegistry = <IJSONContributionRegistry>Registry.as(Extensions.JSONContribution);
|
||||
schemaRegistry.registerSchema(schemaId, schema);
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.st0{opacity:0}.st0,.st1{fill:#f6f6f6}.st2{fill:#424242}</style><g id="outline"><path class="st0" d="M0 0h16v16H0z"/><path class="st1" d="M16 3H9v.445c-.034-.07-.062-.145-.1-.21a2.318 2.318 0 0 0-.759-.793C7.81 2.229 7 2.117 7 2.109V0H4v2.438c-.078-.042-.15-.092-.233-.125a2.685 2.685 0 0 0-1.013-.188c-.184 0-.392.016-.619.055a5.422 5.422 0 0 0-.506.115c-.149.045-.337.096-.493.162-.173.077-.39.151-.533.25L0 3.006v3.17c0 .297.045.56.136.821.1.291.255.525.454.736.207.224.462.351.75.467.065.027.137.026.205.039a2.827 2.827 0 0 0-.651.532 3.064 3.064 0 0 0-.6 1.061 3.81 3.81 0 0 0-.188 1.21c0 .402.062.784.185 1.137.132.377.323.709.562.978a2.748 2.748 0 0 0 2.131.942c.333 0 .595-.042.876-.13a2.61 2.61 0 0 0 .678-.333L5 13.225v-1.811L8.586 15h4.828l-2-2H16V3zM5 10.586V8.523l-.556-.404c-.081-.043-.152-.083-.228-.119h1.96c.196 0 .409.266.634.266.187 0 .366-.007.538-.029L5 10.586z"/></g><g id="icon_x5F_bg"><path class="st2" d="M10 4v2h3v4H9l2-2H9l-3 3 3 3h2l-2-2h6V4zM3.869 3.568a1.21 1.21 0 0 0-.473-.329c-.274-.111-.623-.15-1.055-.076a3.5 3.5 0 0 0-.711.208 1.501 1.501 0 0 0-.234.125l-.043.03v1.056l.168-.139c.149-.124.326-.225.527-.303.196-.074.399-.113.604-.113.188 0 .33.051.431.157.087.095.137.248.147.456l-.962.144c-.219.03-.41.086-.57.166a1.245 1.245 0 0 0-.398.311 1.234 1.234 0 0 0-.229.426 1.714 1.714 0 0 0 .011 1.008 1.096 1.096 0 0 0 .638.67c.155.063.328.093.528.093a1.25 1.25 0 0 0 .978-.441v.345h1.007V4.769c0-.255-.03-.484-.089-.681a1.423 1.423 0 0 0-.275-.52zm-.636 1.896V5.7c0 .119-.018.231-.055.341a.745.745 0 0 1-.377.447.694.694 0 0 1-.512.027.454.454 0 0 1-.156-.094.389.389 0 0 1-.094-.139.474.474 0 0 1-.035-.186c0-.077.009-.147.024-.212a.33.33 0 0 1 .078-.141.436.436 0 0 1 .161-.109 1.3 1.3 0 0 1 .305-.073l.661-.097zM8.284 4.397a2.253 2.253 0 0 0-.244-.656 1.354 1.354 0 0 0-.436-.459 1.165 1.165 0 0 0-.642-.173 1.136 1.136 0 0 0-.69.223 1.312 1.312 0 0 0-.264.266V1.119H5.09v6.224h.918v-.281a1.023 1.023 0 0 0 .472.328c.098.032.208.047.33.047.255 0 .483-.06.677-.177.192-.115.355-.278.486-.486a2.29 2.29 0 0 0 .293-.718 3.87 3.87 0 0 0 .096-.886 3.76 3.76 0 0 0-.078-.773zm-.861.758c0 .232-.02.439-.059.613-.036.172-.09.315-.159.424a.639.639 0 0 1-.233.237.582.582 0 0 1-.565.014.683.683 0 0 1-.211-.183.925.925 0 0 1-.141-.283 1.187 1.187 0 0 1-.054-.358v-.517c0-.164.02-.314.059-.447.037-.132.088-.242.157-.336a.668.668 0 0 1 .228-.208.584.584 0 0 1 .289-.071.554.554 0 0 1 .497.279c.063.099.108.214.143.354.031.143.049.306.049.482zM2.409 10.019a.913.913 0 0 1 .316-.239c.218-.1.547-.105.766-.018.104.042.204.1.32.184l.329.26V9.064l-.096-.062a1.932 1.932 0 0 0-.905-.215c-.308 0-.593.057-.846.168-.25.11-.467.27-.647.475a2.072 2.072 0 0 0-.403.717c-.09.272-.137.57-.137.895 0 .289.043.561.129.808.087.249.212.471.374.652.161.185.361.333.597.441.232.104.493.155.778.155.233 0 .434-.028.613-.084a1.85 1.85 0 0 0 .466-.217l.078-.061v-.889l-.2.095a.402.402 0 0 1-.076.026c-.05.017-.099.035-.128.049-.036.023-.227.09-.227.09-.06.024-.14.043-.218.059a.977.977 0 0 1-.599-.057.827.827 0 0 1-.306-.225 1.088 1.088 0 0 1-.205-.376 1.728 1.728 0 0 1-.076-.529c0-.21.028-.399.083-.56.054-.158.129-.294.22-.4z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
@@ -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.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.toggle-word-wrap-action {
|
||||
background: url('WordWrap_16x.svg') center center no-repeat;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
|
||||
/**
|
||||
* Prevents the top-level menu from showing up when doing Alt + Click in the editor
|
||||
*/
|
||||
@editorContribution
|
||||
export class MenuPreventer extends Disposable implements IEditorContribution {
|
||||
|
||||
private static ID = 'editor.contrib.menuPreventer';
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _altListeningMouse: boolean;
|
||||
private _altMouseTriggered: boolean;
|
||||
|
||||
constructor(editor: ICodeEditor) {
|
||||
super();
|
||||
this._editor = editor;
|
||||
this._altListeningMouse = false;
|
||||
this._altMouseTriggered = false;
|
||||
|
||||
// A global crossover handler to prevent menu bar from showing up
|
||||
// When <alt> is hold, we will listen to mouse events and prevent
|
||||
// the release event up <alt> if the mouse is triggered.
|
||||
|
||||
this._register(this._editor.onMouseDown((e) => {
|
||||
if (this._altListeningMouse) {
|
||||
this._altMouseTriggered = true;
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this._editor.onKeyDown((e) => {
|
||||
if (e.equals(KeyMod.Alt)) {
|
||||
if (!this._altListeningMouse) {
|
||||
this._altMouseTriggered = false;
|
||||
}
|
||||
this._altListeningMouse = true;
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this._editor.onKeyUp((e) => {
|
||||
if (e.equals(KeyMod.Alt)) {
|
||||
if (this._altMouseTriggered) {
|
||||
e.preventDefault();
|
||||
}
|
||||
this._altListeningMouse = false;
|
||||
this._altMouseTriggered = false;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return MenuPreventer.ID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { clipboard } from 'electron';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { ICodeEditor, IEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { EndOfLinePreference, IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
|
||||
import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
|
||||
@editorContribution
|
||||
export class SelectionClipboard extends Disposable implements IEditorContribution {
|
||||
|
||||
private static ID = 'editor.contrib.selectionClipboard';
|
||||
|
||||
constructor(editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService) {
|
||||
super();
|
||||
|
||||
if (platform.isLinux) {
|
||||
let isEnabled = editor.getConfiguration().contribInfo.selectionClipboard;
|
||||
|
||||
this._register(editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => {
|
||||
if (e.contribInfo) {
|
||||
isEnabled = editor.getConfiguration().contribInfo.selectionClipboard;
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(editor.onMouseDown((e: IEditorMouseEvent) => {
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
if (!editor.getModel()) {
|
||||
return;
|
||||
}
|
||||
if (e.event.middleButton) {
|
||||
e.event.preventDefault();
|
||||
editor.focus();
|
||||
|
||||
if (e.target.position) {
|
||||
editor.setPosition(e.target.position);
|
||||
}
|
||||
|
||||
process.nextTick(() => {
|
||||
// TODO@Alex: electron weirdness: calling clipboard.readText('selection') generates a paste event, so no need to execute paste ourselves
|
||||
clipboard.readText('selection');
|
||||
// keybindingService.executeCommand(Handler.Paste, {
|
||||
// text: clipboard.readText('selection'),
|
||||
// pasteOnNewLine: false
|
||||
// });
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
let setSelectionToClipboard = this._register(new RunOnceScheduler(() => {
|
||||
let model = editor.getModel();
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
let selections = editor.getSelections();
|
||||
selections = selections.slice(0);
|
||||
selections.sort(Range.compareRangesUsingStarts);
|
||||
|
||||
let result: string[] = [];
|
||||
for (let i = 0; i < selections.length; i++) {
|
||||
let sel = selections[i];
|
||||
if (sel.isEmpty()) {
|
||||
// Only write if all cursors have selection
|
||||
return;
|
||||
}
|
||||
result.push(model.getValueInRange(sel, EndOfLinePreference.TextDefined));
|
||||
}
|
||||
|
||||
let textToCopy = result.join(model.getEOL());
|
||||
clipboard.writeText(textToCopy, 'selection');
|
||||
}, 100));
|
||||
|
||||
this._register(editor.onDidChangeCursorSelection((e: ICursorSelectionChangedEvent) => {
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
setSelectionToClipboard.schedule();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return SelectionClipboard.ID;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.tm-inspect-widget {
|
||||
z-index: 50;
|
||||
-webkit-user-select: text;
|
||||
-ms-user-select: text;
|
||||
-khtml-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-o-user-select: text;
|
||||
user-select: text;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.tm-token {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.tm-metadata-separator {
|
||||
height: 1px;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.tm-token-length {
|
||||
font-weight: normal;
|
||||
font-size: 60%;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.tm-metadata-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tm-metadata-value {
|
||||
font-family: monospace;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.tm-theme-selector {
|
||||
font-family: monospace;
|
||||
}
|
||||
@@ -0,0 +1,390 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./inspectTMScopes';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { ICommonCodeEditor, IEditorContribution, IModel } from 'vs/editor/common/editorCommon';
|
||||
import { editorAction, EditorAction, ServicesAccessor } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { ICodeEditor, ContentWidgetPositionPreference, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IGrammar, StackElement, IToken } from 'vscode-textmate';
|
||||
import { ITextMateService } from 'vs/workbench/services/textMate/electron-browser/textMateService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { TokenMetadata } from 'vs/editor/common/model/tokensBinaryEncoding';
|
||||
import { TokenizationRegistry, LanguageIdentifier, FontStyle, StandardTokenType } from 'vs/editor/common/modes';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { findMatchingThemeRule } from 'vs/workbench/services/textMate/electron-browser/TMHelper';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { IMessageService } from 'vs/platform/message/common/message';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { registerThemingParticipant, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService';
|
||||
import { editorHoverBackground, editorHoverBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
||||
@editorContribution
|
||||
class InspectTMScopesController extends Disposable implements IEditorContribution {
|
||||
|
||||
private static ID = 'editor.contrib.inspectTMScopes';
|
||||
|
||||
public static get(editor: ICommonCodeEditor): InspectTMScopesController {
|
||||
return editor.getContribution<InspectTMScopesController>(InspectTMScopesController.ID);
|
||||
}
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _textMateService: ITextMateService;
|
||||
private _themeService: IWorkbenchThemeService;
|
||||
private _modeService: IModeService;
|
||||
private _messageService: IMessageService;
|
||||
private _widget: InspectTMScopesWidget;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@ITextMateService textMateService: ITextMateService,
|
||||
@IModeService modeService: IModeService,
|
||||
@IWorkbenchThemeService themeService: IWorkbenchThemeService,
|
||||
@IMessageService messageService: IMessageService,
|
||||
) {
|
||||
super();
|
||||
this._editor = editor;
|
||||
this._textMateService = textMateService;
|
||||
this._themeService = themeService;
|
||||
this._modeService = modeService;
|
||||
this._messageService = messageService;
|
||||
this._widget = null;
|
||||
|
||||
this._register(this._editor.onDidChangeModel((e) => this.stop()));
|
||||
this._register(this._editor.onDidChangeModelLanguage((e) => this.stop()));
|
||||
this._register(this._editor.onKeyUp((e) => e.keyCode === KeyCode.Escape && this.stop()));
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return InspectTMScopesController.ID;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.stop();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public launch(): void {
|
||||
if (this._widget) {
|
||||
return;
|
||||
}
|
||||
if (!this._editor.getModel()) {
|
||||
return;
|
||||
}
|
||||
this._widget = new InspectTMScopesWidget(this._editor, this._textMateService, this._modeService, this._themeService, this._messageService);
|
||||
}
|
||||
|
||||
public stop(): void {
|
||||
if (this._widget) {
|
||||
this._widget.dispose();
|
||||
this._widget = null;
|
||||
}
|
||||
}
|
||||
|
||||
public toggle(): void {
|
||||
if (!this._widget) {
|
||||
this.launch();
|
||||
} else {
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@editorAction
|
||||
class InspectTMScopes extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.inspectTMScopes',
|
||||
label: nls.localize('inspectTMScopes', "Developer: Inspect TM Scopes"),
|
||||
alias: 'Developer: Inspect TM Scopes',
|
||||
precondition: null
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
|
||||
let controller = InspectTMScopesController.get(editor);
|
||||
if (controller) {
|
||||
controller.toggle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface ICompleteLineTokenization {
|
||||
startState: StackElement;
|
||||
tokens1: IToken[];
|
||||
tokens2: Uint32Array;
|
||||
endState: StackElement;
|
||||
}
|
||||
|
||||
interface IDecodedMetadata {
|
||||
languageIdentifier: LanguageIdentifier;
|
||||
tokenType: StandardTokenType;
|
||||
fontStyle: FontStyle;
|
||||
foreground: Color;
|
||||
background: Color;
|
||||
}
|
||||
|
||||
function renderTokenText(tokenText: string): string {
|
||||
if (tokenText.length > 40) {
|
||||
tokenText = tokenText.substr(0, 20) + '…' + tokenText.substr(tokenText.length - 20);
|
||||
}
|
||||
let result: string = '';
|
||||
for (let charIndex = 0, len = tokenText.length; charIndex < len; charIndex++) {
|
||||
let charCode = tokenText.charCodeAt(charIndex);
|
||||
switch (charCode) {
|
||||
case CharCode.Tab:
|
||||
result += '→';
|
||||
break;
|
||||
|
||||
case CharCode.Space:
|
||||
result += '·';
|
||||
break;
|
||||
|
||||
case CharCode.LessThan:
|
||||
result += '<';
|
||||
break;
|
||||
|
||||
case CharCode.GreaterThan:
|
||||
result += '>';
|
||||
break;
|
||||
|
||||
case CharCode.Ampersand:
|
||||
result += '&';
|
||||
break;
|
||||
|
||||
default:
|
||||
result += String.fromCharCode(charCode);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
class InspectTMScopesWidget extends Disposable implements IContentWidget {
|
||||
|
||||
private static _ID = 'editor.contrib.inspectTMScopesWidget';
|
||||
|
||||
// Editor.IContentWidget.allowEditorOverflow
|
||||
public readonly allowEditorOverflow = true;
|
||||
|
||||
private _isDisposed: boolean;
|
||||
private readonly _editor: ICodeEditor;
|
||||
private readonly _modeService: IModeService;
|
||||
private readonly _themeService: IWorkbenchThemeService;
|
||||
private readonly _messageService: IMessageService;
|
||||
private readonly _model: IModel;
|
||||
private readonly _domNode: HTMLElement;
|
||||
private readonly _grammar: TPromise<IGrammar>;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
textMateService: ITextMateService,
|
||||
modeService: IModeService,
|
||||
themeService: IWorkbenchThemeService,
|
||||
messageService: IMessageService
|
||||
) {
|
||||
super();
|
||||
this._isDisposed = false;
|
||||
this._editor = editor;
|
||||
this._modeService = modeService;
|
||||
this._themeService = themeService;
|
||||
this._messageService = messageService;
|
||||
this._model = this._editor.getModel();
|
||||
this._domNode = document.createElement('div');
|
||||
this._domNode.className = 'tm-inspect-widget';
|
||||
this._grammar = textMateService.createGrammar(this._model.getLanguageIdentifier().language);
|
||||
this._beginCompute(this._editor.getPosition());
|
||||
this._register(this._editor.onDidChangeCursorPosition((e) => this._beginCompute(this._editor.getPosition())));
|
||||
this._editor.addContentWidget(this);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._isDisposed = true;
|
||||
this._editor.removeContentWidget(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return InspectTMScopesWidget._ID;
|
||||
}
|
||||
|
||||
private _beginCompute(position: Position): void {
|
||||
dom.clearNode(this._domNode);
|
||||
this._domNode.appendChild(document.createTextNode(nls.localize('inspectTMScopesWidget.loading', "Loading...")));
|
||||
this._grammar.then(
|
||||
(grammar) => this._compute(grammar, position),
|
||||
(err) => {
|
||||
this._messageService.show(Severity.Warning, err);
|
||||
setTimeout(() => {
|
||||
InspectTMScopesController.get(this._editor).stop();
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _compute(grammar: IGrammar, position: Position): void {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
let data = this._getTokensAtLine(grammar, position.lineNumber);
|
||||
|
||||
let token1Index = 0;
|
||||
for (let i = data.tokens1.length - 1; i >= 0; i--) {
|
||||
let t = data.tokens1[i];
|
||||
if (position.column - 1 >= t.startIndex) {
|
||||
token1Index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let token2Index = 0;
|
||||
for (let i = (data.tokens2.length >>> 1); i >= 0; i--) {
|
||||
if (position.column - 1 >= data.tokens2[(i << 1)]) {
|
||||
token2Index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let result = '';
|
||||
|
||||
let tokenStartIndex = data.tokens1[token1Index].startIndex;
|
||||
let tokenEndIndex = data.tokens1[token1Index].endIndex;
|
||||
let tokenText = this._model.getLineContent(position.lineNumber).substring(tokenStartIndex, tokenEndIndex);
|
||||
result += `<h2 class="tm-token">${renderTokenText(tokenText)}<span class="tm-token-length">(${tokenText.length} ${tokenText.length === 1 ? 'char' : 'chars'})</span></h2>`;
|
||||
|
||||
result += `<hr class="tm-metadata-separator" style="clear:both"/>`;
|
||||
|
||||
let metadata = this._decodeMetadata(data.tokens2[(token2Index << 1) + 1]);
|
||||
result += `<table class="tm-metadata-table"><tbody>`;
|
||||
result += `<tr><td class="tm-metadata-key">language</td><td class="tm-metadata-value">${escape(metadata.languageIdentifier.language)}</td>`;
|
||||
result += `<tr><td class="tm-metadata-key">token type</td><td class="tm-metadata-value">${this._tokenTypeToString(metadata.tokenType)}</td>`;
|
||||
result += `<tr><td class="tm-metadata-key">font style</td><td class="tm-metadata-value">${this._fontStyleToString(metadata.fontStyle)}</td>`;
|
||||
result += `<tr><td class="tm-metadata-key">foreground</td><td class="tm-metadata-value">${Color.Format.CSS.formatHexA(metadata.foreground)}</td>`;
|
||||
result += `<tr><td class="tm-metadata-key">background</td><td class="tm-metadata-value">${Color.Format.CSS.formatHexA(metadata.background)}</td>`;
|
||||
result += `</tbody></table>`;
|
||||
|
||||
let theme = this._themeService.getColorTheme();
|
||||
result += `<hr class="tm-metadata-separator"/>`;
|
||||
let matchingRule = findMatchingThemeRule(theme, data.tokens1[token1Index].scopes);
|
||||
if (matchingRule) {
|
||||
result += `<code class="tm-theme-selector">${matchingRule.rawSelector}\n${JSON.stringify(matchingRule.settings, null, '\t')}</code>`;
|
||||
} else {
|
||||
result += `<span class="tm-theme-selector">No theme selector.</span>`;
|
||||
}
|
||||
|
||||
result += `<hr class="tm-metadata-separator"/>`;
|
||||
|
||||
result += `<ul>`;
|
||||
for (let i = data.tokens1[token1Index].scopes.length - 1; i >= 0; i--) {
|
||||
result += `<li>${escape(data.tokens1[token1Index].scopes[i])}</li>`;
|
||||
}
|
||||
result += `</ul>`;
|
||||
|
||||
|
||||
this._domNode.innerHTML = result;
|
||||
this._editor.layoutContentWidget(this);
|
||||
}
|
||||
|
||||
private _decodeMetadata(metadata: number): IDecodedMetadata {
|
||||
let colorMap = TokenizationRegistry.getColorMap();
|
||||
let languageId = TokenMetadata.getLanguageId(metadata);
|
||||
let tokenType = TokenMetadata.getTokenType(metadata);
|
||||
let fontStyle = TokenMetadata.getFontStyle(metadata);
|
||||
let foreground = TokenMetadata.getForeground(metadata);
|
||||
let background = TokenMetadata.getBackground(metadata);
|
||||
return {
|
||||
languageIdentifier: this._modeService.getLanguageIdentifier(languageId),
|
||||
tokenType: tokenType,
|
||||
fontStyle: fontStyle,
|
||||
foreground: colorMap[foreground],
|
||||
background: colorMap[background]
|
||||
};
|
||||
}
|
||||
|
||||
private _tokenTypeToString(tokenType: StandardTokenType): string {
|
||||
switch (tokenType) {
|
||||
case StandardTokenType.Other: return 'Other';
|
||||
case StandardTokenType.Comment: return 'Comment';
|
||||
case StandardTokenType.String: return 'String';
|
||||
case StandardTokenType.RegEx: return 'RegEx';
|
||||
}
|
||||
return '??';
|
||||
}
|
||||
|
||||
private _fontStyleToString(fontStyle: FontStyle): string {
|
||||
let r = '';
|
||||
if (fontStyle & FontStyle.Italic) {
|
||||
r += 'italic ';
|
||||
}
|
||||
if (fontStyle & FontStyle.Bold) {
|
||||
r += 'bold ';
|
||||
}
|
||||
if (fontStyle & FontStyle.Underline) {
|
||||
r += 'underline ';
|
||||
}
|
||||
if (r.length === 0) {
|
||||
r = '---';
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
private _getTokensAtLine(grammar: IGrammar, lineNumber: number): ICompleteLineTokenization {
|
||||
let stateBeforeLine = this._getStateBeforeLine(grammar, lineNumber);
|
||||
|
||||
let tokenizationResult1 = grammar.tokenizeLine(this._model.getLineContent(lineNumber), stateBeforeLine);
|
||||
let tokenizationResult2 = grammar.tokenizeLine2(this._model.getLineContent(lineNumber), stateBeforeLine);
|
||||
|
||||
return {
|
||||
startState: stateBeforeLine,
|
||||
tokens1: tokenizationResult1.tokens,
|
||||
tokens2: tokenizationResult2.tokens,
|
||||
endState: tokenizationResult1.ruleStack
|
||||
};
|
||||
}
|
||||
|
||||
private _getStateBeforeLine(grammar: IGrammar, lineNumber: number): StackElement {
|
||||
let state: StackElement = null;
|
||||
|
||||
for (let i = 1; i < lineNumber; i++) {
|
||||
let tokenizationResult = grammar.tokenizeLine(this._model.getLineContent(i), state);
|
||||
state = tokenizationResult.ruleStack;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
public getDomNode(): HTMLElement {
|
||||
return this._domNode;
|
||||
}
|
||||
|
||||
public getPosition(): IContentWidgetPosition {
|
||||
return {
|
||||
position: this._editor.getPosition(),
|
||||
preference: [ContentWidgetPositionPreference.BELOW, ContentWidgetPositionPreference.ABOVE]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
let border = theme.getColor(editorHoverBorder);
|
||||
if (border) {
|
||||
let borderWidth = theme.type === HIGH_CONTRAST ? 2 : 1;
|
||||
collector.addRule(`.monaco-editor .tm-inspect-widget { border: ${borderWidth}px solid ${border}; }`);
|
||||
collector.addRule(`.monaco-editor .tm-inspect-widget .tm-metadata-separator { background-color: ${border}; }`);
|
||||
}
|
||||
let background = theme.getColor(editorHoverBackground);
|
||||
if (background) {
|
||||
collector.addRule(`.monaco-editor .tm-inspect-widget { background-color: ${background}; }`);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { ICommonCodeEditor } from 'vs/editor/common/editorCommon';
|
||||
import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
|
||||
|
||||
@editorAction
|
||||
export class ToggleMinimapAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.toggleMinimap',
|
||||
label: nls.localize('toggleMinimap', "View: Toggle Minimap"),
|
||||
alias: 'View: Toggle Minimap',
|
||||
precondition: null
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
|
||||
const configurationEditingService = accessor.get(IConfigurationEditingService);
|
||||
|
||||
const newValue = !editor.getConfiguration().viewInfo.minimap.enabled;
|
||||
|
||||
configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: 'editor.minimap.enabled', value: newValue });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry';
|
||||
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
export class ToggleMultiCursorModifierAction extends Action {
|
||||
|
||||
public static ID = 'workbench.action.toggleMultiCursorModifier';
|
||||
public static LABEL = nls.localize('toggleLocation', "Toggle Multi-Cursor Modifier");
|
||||
|
||||
private static multiCursorModifierConfigurationKey = 'editor.multiCursorModifier';
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IConfigurationEditingService private configurationEditingService: IConfigurationEditingService
|
||||
) {
|
||||
super(id, label);
|
||||
|
||||
this.enabled = !!this.configurationService && !!this.configurationEditingService;
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
const editorConf = this.configurationService.getConfiguration<{ multiCursorModifier: 'ctrlCmd' | 'alt' }>('editor');
|
||||
const newValue: 'ctrlCmd' | 'alt' = (editorConf.multiCursorModifier === 'ctrlCmd' ? 'alt' : 'ctrlCmd');
|
||||
|
||||
this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleMultiCursorModifierAction.multiCursorModifierConfigurationKey, value: newValue });
|
||||
|
||||
return TPromise.as(null);
|
||||
}
|
||||
}
|
||||
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMultiCursorModifierAction, ToggleMultiCursorModifierAction.ID, ToggleMultiCursorModifierAction.LABEL), 'Toggle Multi-Cursor Modifier');
|
||||
@@ -0,0 +1,31 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { ICommonCodeEditor } from 'vs/editor/common/editorCommon';
|
||||
import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
|
||||
|
||||
@editorAction
|
||||
export class ToggleRenderControlCharacterAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.toggleRenderControlCharacter',
|
||||
label: nls.localize('toggleRenderControlCharacters', "View: Toggle Control Characters"),
|
||||
alias: 'View: Toggle Control Characters',
|
||||
precondition: null
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
|
||||
const configurationEditingService = accessor.get(IConfigurationEditingService);
|
||||
|
||||
let newRenderControlCharacters = !editor.getConfiguration().viewInfo.renderControlCharacters;
|
||||
|
||||
configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: 'editor.renderControlCharacters', value: newRenderControlCharacters });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { ICommonCodeEditor } from 'vs/editor/common/editorCommon';
|
||||
import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
|
||||
|
||||
@editorAction
|
||||
export class ToggleRenderWhitespaceAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.toggleRenderWhitespace',
|
||||
label: nls.localize('toggleRenderWhitespace', "View: Toggle Render Whitespace"),
|
||||
alias: 'View: Toggle Render Whitespace',
|
||||
precondition: null
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
|
||||
const configurationEditingService = accessor.get(IConfigurationEditingService);
|
||||
|
||||
let renderWhitespace = editor.getConfiguration().viewInfo.renderWhitespace;
|
||||
let newRenderWhitespace: string;
|
||||
if (renderWhitespace === 'none') {
|
||||
newRenderWhitespace = 'all';
|
||||
} else {
|
||||
newRenderWhitespace = 'none';
|
||||
}
|
||||
|
||||
configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: 'editor.renderWhitespace', value: newRenderWhitespace });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./media/codeEditor';
|
||||
import * as nls from 'vs/nls';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { ICommonCodeEditor, IEditorContribution, IModel } from 'vs/editor/common/editorCommon';
|
||||
import { editorAction, ServicesAccessor, EditorAction, commonEditorContribution } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IMessageService } from 'vs/platform/message/common/message';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { InternalEditorOptions, EDITOR_DEFAULTS } from 'vs/editor/common/config/editorOptions';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
||||
|
||||
const transientWordWrapState = 'transientWordWrapState';
|
||||
const isWordWrapMinifiedKey = 'isWordWrapMinified';
|
||||
const isDominatedByLongLinesKey = 'isDominatedByLongLines';
|
||||
const inDiffEditorKey = 'inDiffEditor';
|
||||
|
||||
/**
|
||||
* State written/read by the toggle word wrap action and associated with a particular model.
|
||||
*/
|
||||
interface IWordWrapTransientState {
|
||||
readonly forceWordWrap: 'on' | 'off' | 'wordWrapColumn' | 'bounded';
|
||||
readonly forceWordWrapMinified: boolean;
|
||||
}
|
||||
|
||||
interface IWordWrapState {
|
||||
readonly configuredWordWrap: 'on' | 'off' | 'wordWrapColumn' | 'bounded';
|
||||
readonly configuredWordWrapMinified: boolean;
|
||||
readonly transientState: IWordWrapTransientState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store (in memory) the word wrap state for a particular model.
|
||||
*/
|
||||
function writeTransientState(model: IModel, state: IWordWrapTransientState, codeEditorService: ICodeEditorService): void {
|
||||
codeEditorService.setTransientModelProperty(model, transientWordWrapState, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read (in memory) the word wrap state for a particular model.
|
||||
*/
|
||||
function readTransientState(model: IModel, codeEditorService: ICodeEditorService): IWordWrapTransientState {
|
||||
return codeEditorService.getTransientModelProperty(model, transientWordWrapState);
|
||||
}
|
||||
|
||||
function readWordWrapState(model: IModel, configurationService: ITextResourceConfigurationService, codeEditorService: ICodeEditorService): IWordWrapState {
|
||||
const editorConfig = configurationService.getConfiguration(model.uri, 'editor') as { wordWrap: 'on' | 'off' | 'wordWrapColumn' | 'bounded'; wordWrapMinified: boolean };
|
||||
let _configuredWordWrap = editorConfig && (typeof editorConfig.wordWrap === 'string' || typeof editorConfig.wordWrap === 'boolean') ? editorConfig.wordWrap : void 0;
|
||||
|
||||
// Compatibility with old true or false values
|
||||
if (<any>_configuredWordWrap === true) {
|
||||
_configuredWordWrap = 'on';
|
||||
} else if (<any>_configuredWordWrap === false) {
|
||||
_configuredWordWrap = 'off';
|
||||
}
|
||||
|
||||
const _configuredWordWrapMinified = editorConfig && typeof editorConfig.wordWrapMinified === 'boolean' ? editorConfig.wordWrapMinified : void 0;
|
||||
const _transientState = readTransientState(model, codeEditorService);
|
||||
return {
|
||||
configuredWordWrap: _configuredWordWrap,
|
||||
configuredWordWrapMinified: (typeof _configuredWordWrapMinified === 'boolean' ? _configuredWordWrapMinified : EDITOR_DEFAULTS.wordWrapMinified),
|
||||
transientState: _transientState
|
||||
};
|
||||
}
|
||||
|
||||
function toggleWordWrap(editor: ICommonCodeEditor, state: IWordWrapState): IWordWrapState {
|
||||
if (state.transientState) {
|
||||
// toggle off => go to null
|
||||
return {
|
||||
configuredWordWrap: state.configuredWordWrap,
|
||||
configuredWordWrapMinified: state.configuredWordWrapMinified,
|
||||
transientState: null
|
||||
};
|
||||
}
|
||||
|
||||
const config = editor.getConfiguration();
|
||||
let transientState: IWordWrapTransientState;
|
||||
|
||||
const actualWrappingInfo = config.wrappingInfo;
|
||||
if (actualWrappingInfo.isWordWrapMinified) {
|
||||
// => wrapping due to minified file
|
||||
transientState = {
|
||||
forceWordWrap: 'off',
|
||||
forceWordWrapMinified: false
|
||||
};
|
||||
} else if (state.configuredWordWrap !== 'off') {
|
||||
// => wrapping is configured to be on (or some variant)
|
||||
transientState = {
|
||||
forceWordWrap: 'off',
|
||||
forceWordWrapMinified: false
|
||||
};
|
||||
} else {
|
||||
// => wrapping is configured to be off
|
||||
transientState = {
|
||||
forceWordWrap: 'on',
|
||||
forceWordWrapMinified: state.configuredWordWrapMinified
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
configuredWordWrap: state.configuredWordWrap,
|
||||
configuredWordWrapMinified: state.configuredWordWrapMinified,
|
||||
transientState: transientState
|
||||
};
|
||||
}
|
||||
|
||||
function applyWordWrapState(editor: ICommonCodeEditor, state: IWordWrapState): void {
|
||||
if (state.transientState) {
|
||||
// toggle is on
|
||||
editor.updateOptions({
|
||||
wordWrap: state.transientState.forceWordWrap,
|
||||
wordWrapMinified: state.transientState.forceWordWrapMinified
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// toggle is off
|
||||
editor.updateOptions({
|
||||
wordWrap: state.configuredWordWrap,
|
||||
wordWrapMinified: state.configuredWordWrapMinified
|
||||
});
|
||||
}
|
||||
|
||||
@editorAction
|
||||
class ToggleWordWrapAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.toggleWordWrap',
|
||||
label: nls.localize('toggle.wordwrap', "View: Toggle Word Wrap"),
|
||||
alias: 'View: Toggle Word Wrap',
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
kbExpr: null,
|
||||
primary: KeyMod.Alt | KeyCode.KEY_Z
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
|
||||
const editorConfiguration = editor.getConfiguration();
|
||||
if (editorConfiguration.wrappingInfo.inDiffEditor) {
|
||||
// Cannot change wrapping settings inside the diff editor
|
||||
const messageService = accessor.get(IMessageService);
|
||||
messageService.show(Severity.Info, nls.localize('wordWrap.notInDiffEditor', "Cannot toggle word wrap in a diff editor."));
|
||||
return;
|
||||
}
|
||||
|
||||
const textResourceConfigurationService = accessor.get(ITextResourceConfigurationService);
|
||||
const codeEditorService = accessor.get(ICodeEditorService);
|
||||
const model = editor.getModel();
|
||||
|
||||
if (!canToggleWordWrap(model.uri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the current state
|
||||
const currentState = readWordWrapState(model, textResourceConfigurationService, codeEditorService);
|
||||
// Compute the new state
|
||||
const newState = toggleWordWrap(editor, currentState);
|
||||
// Write the new state
|
||||
writeTransientState(model, newState.transientState, codeEditorService);
|
||||
// Apply the new state
|
||||
applyWordWrapState(editor, newState);
|
||||
}
|
||||
}
|
||||
|
||||
@commonEditorContribution
|
||||
class ToggleWordWrapController extends Disposable implements IEditorContribution {
|
||||
|
||||
private static _ID = 'editor.contrib.toggleWordWrapController';
|
||||
|
||||
constructor(
|
||||
private readonly editor: ICommonCodeEditor,
|
||||
@IContextKeyService readonly contextKeyService: IContextKeyService,
|
||||
@ITextResourceConfigurationService readonly configurationService: ITextResourceConfigurationService,
|
||||
@ICodeEditorService readonly codeEditorService: ICodeEditorService
|
||||
) {
|
||||
super();
|
||||
|
||||
const configuration = this.editor.getConfiguration();
|
||||
const isWordWrapMinified = this.contextKeyService.createKey(isWordWrapMinifiedKey, this._isWordWrapMinified(configuration));
|
||||
const isDominatedByLongLines = this.contextKeyService.createKey(isDominatedByLongLinesKey, this._isDominatedByLongLines(configuration));
|
||||
const inDiffEditor = this.contextKeyService.createKey(inDiffEditorKey, this._inDiffEditor(configuration));
|
||||
|
||||
this._register(editor.onDidChangeConfiguration((e) => {
|
||||
if (!e.wrappingInfo) {
|
||||
return;
|
||||
}
|
||||
const configuration = this.editor.getConfiguration();
|
||||
isWordWrapMinified.set(this._isWordWrapMinified(configuration));
|
||||
isDominatedByLongLines.set(this._isDominatedByLongLines(configuration));
|
||||
inDiffEditor.set(this._inDiffEditor(configuration));
|
||||
}));
|
||||
|
||||
this._register(editor.onDidChangeModel((e) => {
|
||||
// Ensure correct word wrap settings
|
||||
const newModel = this.editor.getModel();
|
||||
if (!newModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const configuration = this.editor.getConfiguration();
|
||||
if (this._inDiffEditor(configuration)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canToggleWordWrap(newModel.uri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Read current configured values and toggle state
|
||||
const desiredState = readWordWrapState(newModel, this.configurationService, this.codeEditorService);
|
||||
|
||||
// Apply the state
|
||||
applyWordWrapState(editor, desiredState);
|
||||
}));
|
||||
}
|
||||
|
||||
private _isWordWrapMinified(config: InternalEditorOptions): boolean {
|
||||
return config.wrappingInfo.isWordWrapMinified;
|
||||
}
|
||||
|
||||
private _isDominatedByLongLines(config: InternalEditorOptions): boolean {
|
||||
return config.wrappingInfo.isDominatedByLongLines;
|
||||
}
|
||||
|
||||
private _inDiffEditor(config: InternalEditorOptions): boolean {
|
||||
return config.wrappingInfo.inDiffEditor;
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return ToggleWordWrapController._ID;
|
||||
}
|
||||
}
|
||||
|
||||
function canToggleWordWrap(uri: URI): boolean {
|
||||
if (!uri) {
|
||||
return false;
|
||||
}
|
||||
return (uri.scheme !== 'output' && uri.scheme !== 'vscode');
|
||||
}
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
|
||||
command: {
|
||||
id: 'editor.action.toggleWordWrap',
|
||||
title: nls.localize('unwrapMinified', "Disable wrapping for this file"),
|
||||
iconClass: 'toggle-word-wrap-action'
|
||||
},
|
||||
group: 'navigation',
|
||||
order: 1,
|
||||
when: ContextKeyExpr.and(
|
||||
ContextKeyExpr.not(inDiffEditorKey),
|
||||
ContextKeyExpr.has(isDominatedByLongLinesKey),
|
||||
ContextKeyExpr.has(isWordWrapMinifiedKey)
|
||||
)
|
||||
});
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
|
||||
command: {
|
||||
id: 'editor.action.toggleWordWrap',
|
||||
title: nls.localize('wrapMinified', "Enable wrapping for this file"),
|
||||
iconClass: 'toggle-word-wrap-action'
|
||||
},
|
||||
group: 'navigation',
|
||||
order: 1,
|
||||
when: ContextKeyExpr.and(
|
||||
ContextKeyExpr.not(inDiffEditorKey),
|
||||
ContextKeyExpr.has(isDominatedByLongLinesKey),
|
||||
ContextKeyExpr.not(isWordWrapMinifiedKey)
|
||||
)
|
||||
});
|
||||
@@ -0,0 +1,142 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IMessageService } from 'vs/platform/message/common/message';
|
||||
import { IPreferencesService } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
|
||||
interface IStorageData {
|
||||
dontShowPrompt: boolean;
|
||||
}
|
||||
|
||||
class WordWrapMigrationStorage {
|
||||
private static KEY = 'wordWrapMigration';
|
||||
|
||||
private _storageService: IStorageService;
|
||||
private _value: IStorageData;
|
||||
|
||||
constructor(storageService: IStorageService) {
|
||||
this._storageService = storageService;
|
||||
this._value = this._read();
|
||||
}
|
||||
|
||||
private _read(): IStorageData {
|
||||
let jsonValue = this._storageService.get(WordWrapMigrationStorage.KEY, StorageScope.GLOBAL);
|
||||
if (!jsonValue) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(jsonValue);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public get(): IStorageData {
|
||||
return this._value;
|
||||
}
|
||||
|
||||
public set(data: IStorageData): void {
|
||||
this._value = data;
|
||||
this._storageService.store(WordWrapMigrationStorage.KEY, JSON.stringify(this._value), StorageScope.GLOBAL);
|
||||
}
|
||||
}
|
||||
|
||||
@editorContribution
|
||||
class WordWrapMigrationController extends Disposable implements IEditorContribution {
|
||||
|
||||
private static ID = 'editor.contrib.wordWrapMigrationController';
|
||||
private static _checked = false;
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IMessageService private messageService: IMessageService,
|
||||
@IStorageService private storageService: IStorageService,
|
||||
@IPreferencesService private preferencesService: IPreferencesService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._promptIfNecessary();
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return WordWrapMigrationController.ID;
|
||||
}
|
||||
|
||||
private _promptIfNecessary(): void {
|
||||
if (WordWrapMigrationController._checked) {
|
||||
// Already checked
|
||||
return;
|
||||
}
|
||||
WordWrapMigrationController._checked = true;
|
||||
|
||||
let result = this.configurationService.lookup('editor.wrappingColumn');
|
||||
if (typeof result.value === 'undefined') {
|
||||
// Setting is not used
|
||||
return;
|
||||
}
|
||||
|
||||
const storage = new WordWrapMigrationStorage(this.storageService);
|
||||
const storedData = storage.get();
|
||||
if (storedData && storedData.dontShowPrompt) {
|
||||
// Do not prompt stored
|
||||
return;
|
||||
}
|
||||
|
||||
let isUserSetting = (typeof result.user !== 'undefined');
|
||||
this._prompt(storage, isUserSetting);
|
||||
}
|
||||
|
||||
private _prompt(storage: WordWrapMigrationStorage, userSettings: boolean): void {
|
||||
const okAction = new Action(
|
||||
'wordWrapMigration.ok',
|
||||
nls.localize('wordWrapMigration.ok', "OK"),
|
||||
null,
|
||||
true,
|
||||
() => TPromise.as(true)
|
||||
);
|
||||
const dontShowAgainAction = new Action(
|
||||
'wordWrapMigration.dontShowAgain',
|
||||
nls.localize('wordWrapMigration.dontShowAgain', "Don't show again"),
|
||||
null,
|
||||
true,
|
||||
() => {
|
||||
storage.set({
|
||||
dontShowPrompt: true
|
||||
});
|
||||
return TPromise.as(true);
|
||||
}
|
||||
);
|
||||
const openSettings = new Action(
|
||||
'wordWrapMigration.openSettings',
|
||||
nls.localize('wordWrapMigration.openSettings', "Open Settings"),
|
||||
null,
|
||||
true,
|
||||
() => {
|
||||
if (userSettings) {
|
||||
this.preferencesService.openGlobalSettings();
|
||||
} else {
|
||||
this.preferencesService.openWorkspaceSettings();
|
||||
}
|
||||
return TPromise.as(true);
|
||||
}
|
||||
);
|
||||
this.messageService.show(Severity.Info, {
|
||||
message: nls.localize('wordWrapMigration.prompt', "The setting `editor.wrappingColumn` has been deprecated in favor of `editor.wordWrap`."),
|
||||
actions: [okAction, openSettings, dontShowAgainAction]
|
||||
});
|
||||
}
|
||||
}
|
||||
158
src/vs/workbench/parts/debug/browser/breakpointWidget.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!../browser/media/breakpointWidget';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { isWindows, isMacintosh } from 'vs/base/common/platform';
|
||||
import { SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/browser/zoneWidget';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IDebugService, IBreakpoint, IRawBreakpoint } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { once } from 'vs/base/common/functional';
|
||||
import { attachInputBoxStyler, attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
const $ = dom.$;
|
||||
const EXPRESSION_PLACEHOLDER = nls.localize('breakpointWidgetExpressionPlaceholder', "Break when expression evaluates to true. 'Enter' to accept, 'esc' to cancel.");
|
||||
const EXPRESSION_ARIA_LABEL = nls.localize('breakpointWidgetAriaLabel', "The program will only stop here if this condition is true. Press Enter to accept or Escape to cancel.");
|
||||
const HIT_COUNT_PLACEHOLDER = nls.localize('breakpointWidgetHitCountPlaceholder', "Break when hit count condition is met. 'Enter' to accept, 'esc' to cancel.");
|
||||
const HIT_COUNT_ARIA_LABEL = nls.localize('breakpointWidgetHitCountAriaLabel', "The program will only stop here if the hit count is met. Press Enter to accept or Escape to cancel.");
|
||||
|
||||
export class BreakpointWidget extends ZoneWidget {
|
||||
|
||||
private inputBox: InputBox;
|
||||
private toDispose: lifecycle.IDisposable[];
|
||||
private hitCountContext: boolean;
|
||||
private hitCountInput: string;
|
||||
private conditionInput: string;
|
||||
|
||||
constructor(editor: ICodeEditor, private lineNumber: number, private column: number,
|
||||
@IContextViewService private contextViewService: IContextViewService,
|
||||
@IDebugService private debugService: IDebugService,
|
||||
@IThemeService private themeService: IThemeService
|
||||
) {
|
||||
super(editor, { showFrame: true, showArrow: false, frameWidth: 1 });
|
||||
|
||||
this.toDispose = [];
|
||||
this.hitCountInput = '';
|
||||
this.conditionInput = '';
|
||||
this.create();
|
||||
}
|
||||
|
||||
private get placeholder(): string {
|
||||
return this.hitCountContext ? HIT_COUNT_PLACEHOLDER : EXPRESSION_PLACEHOLDER;
|
||||
}
|
||||
|
||||
private get ariaLabel(): string {
|
||||
return this.hitCountContext ? HIT_COUNT_ARIA_LABEL : EXPRESSION_ARIA_LABEL;
|
||||
}
|
||||
|
||||
private getInputBoxValue(breakpoint: IBreakpoint): string {
|
||||
if (this.hitCountContext) {
|
||||
return breakpoint && breakpoint.hitCondition ? breakpoint.hitCondition : this.hitCountInput;
|
||||
}
|
||||
|
||||
return breakpoint && breakpoint.condition ? breakpoint.condition : this.conditionInput;
|
||||
}
|
||||
|
||||
protected _fillContainer(container: HTMLElement): void {
|
||||
this.setCssClass('breakpoint-widget');
|
||||
const uri = this.editor.getModel().uri;
|
||||
const breakpoint = this.debugService.getModel().getBreakpoints().filter(bp => bp.lineNumber === this.lineNumber && bp.column === this.column && bp.uri.toString() === uri.toString()).pop();
|
||||
|
||||
this.hitCountContext = breakpoint && breakpoint.hitCondition && !breakpoint.condition;
|
||||
const selected = this.hitCountContext ? 1 : 0;
|
||||
const selectBox = new SelectBox([nls.localize('expression', "Expression"), nls.localize('hitCount', "Hit Count")], selected);
|
||||
this.toDispose.push(attachSelectBoxStyler(selectBox, this.themeService));
|
||||
selectBox.render(dom.append(container, $('.breakpoint-select-container')));
|
||||
selectBox.onDidSelect(e => {
|
||||
this.hitCountContext = e.selected === 'Hit Count';
|
||||
if (this.hitCountContext) {
|
||||
this.conditionInput = this.inputBox.value;
|
||||
} else {
|
||||
this.hitCountInput = this.inputBox.value;
|
||||
}
|
||||
|
||||
this.inputBox.setAriaLabel(this.ariaLabel);
|
||||
this.inputBox.setPlaceHolder(this.placeholder);
|
||||
this.inputBox.value = this.getInputBoxValue(breakpoint);
|
||||
});
|
||||
|
||||
const inputBoxContainer = dom.append(container, $('.inputBoxContainer'));
|
||||
this.inputBox = new InputBox(inputBoxContainer, this.contextViewService, {
|
||||
placeholder: this.placeholder,
|
||||
ariaLabel: this.ariaLabel
|
||||
});
|
||||
this.toDispose.push(attachInputBoxStyler(this.inputBox, this.themeService));
|
||||
this.toDispose.push(this.inputBox);
|
||||
|
||||
dom.addClass(this.inputBox.inputElement, isWindows ? 'windows' : isMacintosh ? 'mac' : 'linux');
|
||||
this.inputBox.value = this.getInputBoxValue(breakpoint);
|
||||
// Due to an electron bug we have to do the timeout, otherwise we do not get focus
|
||||
setTimeout(() => this.inputBox.focus(), 0);
|
||||
|
||||
let disposed = false;
|
||||
const wrapUp = once((success: boolean) => {
|
||||
if (!disposed) {
|
||||
disposed = true;
|
||||
if (success) {
|
||||
// if there is already a breakpoint on this location - remove it.
|
||||
const oldBreakpoint = this.debugService.getModel().getBreakpoints()
|
||||
.filter(bp => bp.lineNumber === this.lineNumber && bp.column === this.column && bp.uri.toString() === uri.toString()).pop();
|
||||
|
||||
const raw: IRawBreakpoint = {
|
||||
lineNumber: this.lineNumber,
|
||||
column: oldBreakpoint ? oldBreakpoint.column : undefined,
|
||||
enabled: true,
|
||||
condition: oldBreakpoint && oldBreakpoint.condition,
|
||||
hitCondition: oldBreakpoint && oldBreakpoint.hitCondition
|
||||
};
|
||||
|
||||
if (this.hitCountContext) {
|
||||
raw.hitCondition = this.inputBox.value;
|
||||
if (this.conditionInput) {
|
||||
raw.condition = this.conditionInput;
|
||||
}
|
||||
} else {
|
||||
raw.condition = this.inputBox.value;
|
||||
if (this.hitCountInput) {
|
||||
raw.hitCondition = this.hitCountInput;
|
||||
}
|
||||
}
|
||||
|
||||
if (oldBreakpoint) {
|
||||
this.debugService.removeBreakpoints(oldBreakpoint.getId()).done(null, errors.onUnexpectedError);
|
||||
}
|
||||
|
||||
this.debugService.addBreakpoints(uri, [raw]).done(null, errors.onUnexpectedError);
|
||||
}
|
||||
|
||||
this.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
this.toDispose.push(dom.addStandardDisposableListener(this.inputBox.inputElement, 'keydown', (e: IKeyboardEvent) => {
|
||||
const isEscape = e.equals(KeyCode.Escape);
|
||||
const isEnter = e.equals(KeyCode.Enter);
|
||||
if (isEscape || isEnter) {
|
||||
e.stopPropagation();
|
||||
wrapUp(isEnter);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
lifecycle.dispose(this.toDispose);
|
||||
setTimeout(() => this.editor.focus(), 0);
|
||||
}
|
||||
}
|
||||
216
src/vs/workbench/parts/debug/browser/debugActionItems.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { IAction, IActionRunner } from 'vs/base/common/actions';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
import { SelectActionItem, IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { EventEmitter } from 'vs/base/common/eventEmitter';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import { IDebugService } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { selectBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
export class StartDebugActionItem extends EventEmitter implements IActionItem {
|
||||
|
||||
private static SEPARATOR = '─────────';
|
||||
|
||||
public actionRunner: IActionRunner;
|
||||
private container: HTMLElement;
|
||||
private start: HTMLElement;
|
||||
private selectBox: SelectBox;
|
||||
private options: { label: string, handler: (() => boolean) }[];
|
||||
private toDispose: lifecycle.IDisposable[];
|
||||
private selected: number;
|
||||
|
||||
constructor(
|
||||
private context: any,
|
||||
private action: IAction,
|
||||
@IDebugService private debugService: IDebugService,
|
||||
@IThemeService private themeService: IThemeService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@ICommandService private commandService: ICommandService,
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService
|
||||
) {
|
||||
super();
|
||||
this.toDispose = [];
|
||||
this.selectBox = new SelectBox([], -1);
|
||||
this.toDispose.push(attachSelectBoxStyler(this.selectBox, themeService, {
|
||||
selectBackground: SIDE_BAR_BACKGROUND
|
||||
}));
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => {
|
||||
if (e.sourceConfig.launch) {
|
||||
this.updateOptions();
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(this.selectBox.onDidSelect(e => {
|
||||
if (this.options[e.index].handler()) {
|
||||
this.selected = e.index;
|
||||
} else {
|
||||
// Some select options should not remain selected https://github.com/Microsoft/vscode/issues/31526
|
||||
this.selectBox.select(this.selected);
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(this.debugService.getConfigurationManager().onDidSelectConfiguration(() => {
|
||||
this.updateOptions();
|
||||
}));
|
||||
}
|
||||
|
||||
public render(container: HTMLElement): void {
|
||||
this.container = container;
|
||||
dom.addClass(container, 'start-debug-action-item');
|
||||
this.start = dom.append(container, $('.icon'));
|
||||
this.start.title = this.action.label;
|
||||
this.start.tabIndex = 0;
|
||||
|
||||
this.toDispose.push(dom.addDisposableListener(this.start, dom.EventType.CLICK, () => {
|
||||
this.start.blur();
|
||||
this.actionRunner.run(this.action, this.context).done(null, errors.onUnexpectedError);
|
||||
}));
|
||||
|
||||
this.toDispose.push(dom.addDisposableListener(this.start, dom.EventType.MOUSE_DOWN, (e: MouseEvent) => {
|
||||
if (this.action.enabled && e.button === 0) {
|
||||
dom.addClass(this.start, 'active');
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(dom.addDisposableListener(this.start, dom.EventType.MOUSE_UP, () => {
|
||||
dom.removeClass(this.start, 'active');
|
||||
}));
|
||||
this.toDispose.push(dom.addDisposableListener(this.start, dom.EventType.MOUSE_OUT, () => {
|
||||
dom.removeClass(this.start, 'active');
|
||||
}));
|
||||
|
||||
this.toDispose.push(dom.addDisposableListener(this.start, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
if (event.equals(KeyCode.Enter)) {
|
||||
this.actionRunner.run(this.action, this.context).done(null, errors.onUnexpectedError);
|
||||
}
|
||||
if (event.equals(KeyCode.RightArrow)) {
|
||||
this.selectBox.focus();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}));
|
||||
|
||||
const selectBoxContainer = $('.configuration');
|
||||
this.selectBox.render(dom.append(container, selectBoxContainer));
|
||||
this.toDispose.push(dom.addDisposableListener(selectBoxContainer, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
if (event.equals(KeyCode.LeftArrow)) {
|
||||
this.start.focus();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(attachStylerCallback(this.themeService, { selectBorder }, colors => {
|
||||
this.container.style.border = colors.selectBorder ? `1px solid ${colors.selectBorder}` : null;
|
||||
selectBoxContainer.style.borderLeft = colors.selectBorder ? `1px solid ${colors.selectBorder}` : null;
|
||||
}));
|
||||
|
||||
this.updateOptions();
|
||||
}
|
||||
|
||||
public setActionContext(context: any): void {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public isEnabled(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
public focus(fromRight?: boolean): void {
|
||||
if (fromRight) {
|
||||
this.selectBox.focus();
|
||||
} else {
|
||||
this.start.focus();
|
||||
}
|
||||
}
|
||||
|
||||
public blur(): void {
|
||||
this.container.blur();
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.toDispose = lifecycle.dispose(this.toDispose);
|
||||
}
|
||||
|
||||
private updateOptions(): void {
|
||||
this.selected = 0;
|
||||
this.options = [];
|
||||
const manager = this.debugService.getConfigurationManager();
|
||||
const launches = manager.getLaunches();
|
||||
manager.getLaunches().forEach(launch =>
|
||||
launch.getConfigurationNames().forEach(name => {
|
||||
if (name === manager.selectedName && launch === manager.selectedLaunch) {
|
||||
this.selected = this.options.length;
|
||||
}
|
||||
const label = launches.length > 1 ? `${name} (${launch.name})` : name;
|
||||
this.options.push({ label, handler: () => { manager.selectConfiguration(launch, name); return true; } });
|
||||
}));
|
||||
|
||||
if (this.options.length === 0) {
|
||||
this.options.push({ label: nls.localize('noConfigurations', "No Configurations"), handler: () => false });
|
||||
}
|
||||
this.options.push({ label: StartDebugActionItem.SEPARATOR, handler: undefined });
|
||||
|
||||
const disabledIdx = this.options.length - 1;
|
||||
launches.forEach(l => {
|
||||
const label = launches.length > 1 ? nls.localize("addConfigTo", "Add Config ({0})...", l.name) : nls.localize('addConfiguration', "Add Configuration...");
|
||||
this.options.push({
|
||||
label, handler: () => {
|
||||
this.commandService.executeCommand('debug.addConfiguration', l.workspaceUri.toString()).done(undefined, errors.onUnexpectedError);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.selectBox.setOptions(this.options.map(data => data.label), this.selected, disabledIdx);
|
||||
}
|
||||
}
|
||||
|
||||
export class FocusProcessActionItem extends SelectActionItem {
|
||||
constructor(
|
||||
action: IAction,
|
||||
@IDebugService private debugService: IDebugService,
|
||||
@IThemeService themeService: IThemeService
|
||||
) {
|
||||
super(null, action, [], -1);
|
||||
|
||||
this.toDispose.push(attachSelectBoxStyler(this.selectBox, themeService));
|
||||
|
||||
this.debugService.getViewModel().onDidFocusStackFrame(() => {
|
||||
const process = this.debugService.getViewModel().focusedProcess;
|
||||
if (process) {
|
||||
const index = this.debugService.getModel().getProcesses().indexOf(process);
|
||||
this.select(index);
|
||||
}
|
||||
});
|
||||
|
||||
this.debugService.getModel().onDidChangeCallStack(() => this.update());
|
||||
this.update();
|
||||
}
|
||||
|
||||
private update() {
|
||||
const process = this.debugService.getViewModel().focusedProcess;
|
||||
const processes = this.debugService.getModel().getProcesses();
|
||||
const showRootName = this.debugService.getConfigurationManager().getLaunches().length > 1;
|
||||
const names = processes.map(p => p.getName(showRootName));
|
||||
this.setOptions(names, process ? processes.indexOf(process) : undefined);
|
||||
}
|
||||
}
|
||||
840
src/vs/workbench/parts/debug/browser/debugActions.ts
Normal file
@@ -0,0 +1,840 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IMessageService } from 'vs/platform/message/common/message';
|
||||
import { IDebugService, State, IProcess, IThread, IEnablement, IBreakpoint, IStackFrame, IFunctionBreakpoint, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, IExpression, REPL_ID, ProcessState }
|
||||
from 'vs/workbench/parts/debug/common/debug';
|
||||
import { Variable, Expression, Thread, Breakpoint, Process } from 'vs/workbench/parts/debug/common/debugModel';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { TogglePanelAction } from 'vs/workbench/browser/panel';
|
||||
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
|
||||
export abstract class AbstractDebugAction extends Action {
|
||||
|
||||
protected toDispose: lifecycle.IDisposable[];
|
||||
|
||||
constructor(
|
||||
id: string, label: string, cssClass: string,
|
||||
@IDebugService protected debugService: IDebugService,
|
||||
@IKeybindingService private keybindingService: IKeybindingService,
|
||||
public weight?: number
|
||||
) {
|
||||
super(id, label, cssClass, false);
|
||||
this.toDispose = [];
|
||||
this.toDispose.push(this.debugService.onDidChangeState(state => this.updateEnablement(state)));
|
||||
|
||||
this.updateLabel(label);
|
||||
this.updateEnablement();
|
||||
}
|
||||
|
||||
public run(e?: any): TPromise<any> {
|
||||
throw new Error('implement me');
|
||||
}
|
||||
|
||||
public get tooltip(): string {
|
||||
const keybinding = this.keybindingService.lookupKeybinding(this.id);
|
||||
const keybindingLabel = keybinding && keybinding.getLabel();
|
||||
|
||||
return keybindingLabel ? `${this.label} (${keybindingLabel})` : this.label;
|
||||
}
|
||||
|
||||
protected updateLabel(newLabel: string): void {
|
||||
this.label = newLabel;
|
||||
}
|
||||
|
||||
protected updateEnablement(state = this.debugService.state): void {
|
||||
this.enabled = this.isEnabled(state);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
this.toDispose = lifecycle.dispose(this.toDispose);
|
||||
}
|
||||
}
|
||||
|
||||
export class ConfigureAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.configure';
|
||||
static LABEL = nls.localize('openLaunchJson', "Open {0}", 'launch.json');
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IDebugService debugService: IDebugService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService,
|
||||
@IMessageService private messageService: IMessageService
|
||||
) {
|
||||
super(id, label, 'debug-action configure', debugService, keybindingService);
|
||||
this.toDispose.push(debugService.getConfigurationManager().onDidSelectConfiguration(() => this.updateClass()));
|
||||
this.updateClass();
|
||||
}
|
||||
|
||||
public get tooltip(): string {
|
||||
if (this.debugService.getConfigurationManager().selectedName) {
|
||||
return ConfigureAction.LABEL;
|
||||
}
|
||||
|
||||
return nls.localize('launchJsonNeedsConfigurtion', "Configure or Fix 'launch.json'");
|
||||
}
|
||||
|
||||
private updateClass(): void {
|
||||
this.class = this.debugService.getConfigurationManager().selectedName ? 'debug-action configure' : 'debug-action configure notification';
|
||||
}
|
||||
|
||||
public run(event?: any): TPromise<any> {
|
||||
if (!this.contextService.hasWorkspace()) {
|
||||
this.messageService.show(severity.Info, nls.localize('noFolderDebugConfig', "Please first open a folder in order to do advanced debug configuration."));
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
const sideBySide = !!(event && (event.ctrlKey || event.metaKey));
|
||||
return this.debugService.getConfigurationManager().selectedLaunch.openConfigFile(sideBySide);
|
||||
}
|
||||
}
|
||||
|
||||
export class StartAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.start';
|
||||
static LABEL = nls.localize('startDebug', "Start Debugging");
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IDebugService debugService: IDebugService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService
|
||||
) {
|
||||
super(id, label, 'debug-action start', debugService, keybindingService);
|
||||
this.debugService.getConfigurationManager().onDidSelectConfiguration(() => this.updateEnablement());
|
||||
this.debugService.getModel().onDidChangeCallStack(() => this.updateEnablement());
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
const launch = this.debugService.getConfigurationManager().selectedLaunch;
|
||||
return this.debugService.startDebugging(launch ? launch.workspaceUri : undefined, undefined, this.isNoDebug());
|
||||
}
|
||||
|
||||
protected isNoDebug(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disabled if the launch drop down shows the launch config that is already running.
|
||||
protected isEnabled(state: State): boolean {
|
||||
const processes = this.debugService.getModel().getProcesses();
|
||||
const selectedName = this.debugService.getConfigurationManager().selectedName;
|
||||
const launch = this.debugService.getConfigurationManager().selectedLaunch;
|
||||
|
||||
if (state === State.Initializing) {
|
||||
return false;
|
||||
}
|
||||
if (this.contextService && !this.contextService.hasWorkspace() && processes.length > 0) {
|
||||
return false;
|
||||
}
|
||||
if (processes.some(p => p.getName(false) === selectedName && (!launch || p.session.root.toString() === launch.workspaceUri.toString()))) {
|
||||
return false;
|
||||
}
|
||||
const compound = launch && launch.getCompound(selectedName);
|
||||
if (compound && compound.configurations && processes.some(p => compound.configurations.indexOf(p.getName(false)) !== -1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class RunAction extends StartAction {
|
||||
static ID = 'workbench.action.debug.run';
|
||||
static LABEL = nls.localize('startWithoutDebugging', "Start Without Debugging");
|
||||
|
||||
protected isNoDebug(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class SelectAndStartAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.selectandstart';
|
||||
static LABEL = nls.localize('selectAndStartDebugging', "Select and Start Debugging");
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IDebugService debugService: IDebugService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IFileService fileService: IFileService,
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService
|
||||
) {
|
||||
super(id, label, undefined, debugService, keybindingService);
|
||||
this.quickOpenService = quickOpenService;
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
return this.quickOpenService.show('debug ');
|
||||
}
|
||||
}
|
||||
|
||||
export class RestartAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.restart';
|
||||
static LABEL = nls.localize('restartDebug', "Restart");
|
||||
static RECONNECT_LABEL = nls.localize('reconnectDebug', "Reconnect");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action restart', debugService, keybindingService, 70);
|
||||
this.setLabel(this.debugService.getViewModel().focusedProcess);
|
||||
this.toDispose.push(this.debugService.getViewModel().onDidFocusStackFrame(() => this.setLabel(this.debugService.getViewModel().focusedProcess)));
|
||||
}
|
||||
|
||||
private setLabel(process: IProcess): void {
|
||||
this.updateLabel(process && process.state === ProcessState.ATTACH ? RestartAction.RECONNECT_LABEL : RestartAction.LABEL);
|
||||
}
|
||||
|
||||
public run(process: IProcess): TPromise<any> {
|
||||
if (!(process instanceof Process)) {
|
||||
process = this.debugService.getViewModel().focusedProcess;
|
||||
}
|
||||
if (!process) {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
if (this.debugService.getModel().getProcesses().length <= 1) {
|
||||
this.debugService.removeReplExpressions();
|
||||
}
|
||||
return this.debugService.restartProcess(process);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return super.isEnabled(state) && state !== State.Inactive;
|
||||
}
|
||||
}
|
||||
|
||||
export class StepOverAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.stepOver';
|
||||
static LABEL = nls.localize('stepOverDebug', "Step Over");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action step-over', debugService, keybindingService, 20);
|
||||
}
|
||||
|
||||
public run(thread: IThread): TPromise<any> {
|
||||
if (!(thread instanceof Thread)) {
|
||||
thread = this.debugService.getViewModel().focusedThread;
|
||||
}
|
||||
|
||||
return thread ? thread.next() : TPromise.as(null);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return super.isEnabled(state) && state === State.Stopped;
|
||||
}
|
||||
}
|
||||
|
||||
export class StepIntoAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.stepInto';
|
||||
static LABEL = nls.localize('stepIntoDebug', "Step Into");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action step-into', debugService, keybindingService, 30);
|
||||
}
|
||||
|
||||
public run(thread: IThread): TPromise<any> {
|
||||
if (!(thread instanceof Thread)) {
|
||||
thread = this.debugService.getViewModel().focusedThread;
|
||||
}
|
||||
|
||||
return thread ? thread.stepIn() : TPromise.as(null);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return super.isEnabled(state) && state === State.Stopped;
|
||||
}
|
||||
}
|
||||
|
||||
export class StepOutAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.stepOut';
|
||||
static LABEL = nls.localize('stepOutDebug', "Step Out");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action step-out', debugService, keybindingService, 40);
|
||||
}
|
||||
|
||||
public run(thread: IThread): TPromise<any> {
|
||||
if (!(thread instanceof Thread)) {
|
||||
thread = this.debugService.getViewModel().focusedThread;
|
||||
}
|
||||
|
||||
return thread ? thread.stepOut() : TPromise.as(null);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return super.isEnabled(state) && state === State.Stopped;
|
||||
}
|
||||
}
|
||||
|
||||
export class StopAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.stop';
|
||||
static LABEL = nls.localize('stopDebug', "Stop");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action stop', debugService, keybindingService, 80);
|
||||
}
|
||||
|
||||
public run(process: IProcess): TPromise<any> {
|
||||
if (!(process instanceof Process)) {
|
||||
process = this.debugService.getViewModel().focusedProcess;
|
||||
}
|
||||
|
||||
return this.debugService.stopProcess(process);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return super.isEnabled(state) && state !== State.Inactive;
|
||||
}
|
||||
}
|
||||
|
||||
export class DisconnectAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.disconnect';
|
||||
static LABEL = nls.localize('disconnectDebug', "Disconnect");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action disconnect', debugService, keybindingService, 80);
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
const process = this.debugService.getViewModel().focusedProcess;
|
||||
return this.debugService.stopProcess(process);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return super.isEnabled(state) && state !== State.Inactive;
|
||||
}
|
||||
}
|
||||
|
||||
export class ContinueAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.continue';
|
||||
static LABEL = nls.localize('continueDebug', "Continue");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action continue', debugService, keybindingService, 10);
|
||||
}
|
||||
|
||||
public run(thread: IThread): TPromise<any> {
|
||||
if (!(thread instanceof Thread)) {
|
||||
thread = this.debugService.getViewModel().focusedThread;
|
||||
}
|
||||
|
||||
return thread ? thread.continue() : TPromise.as(null);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return super.isEnabled(state) && state === State.Stopped;
|
||||
}
|
||||
}
|
||||
|
||||
export class PauseAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.pause';
|
||||
static LABEL = nls.localize('pauseDebug', "Pause");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action pause', debugService, keybindingService, 10);
|
||||
}
|
||||
|
||||
public run(thread: IThread): TPromise<any> {
|
||||
if (!(thread instanceof Thread)) {
|
||||
thread = this.debugService.getViewModel().focusedThread;
|
||||
}
|
||||
|
||||
return thread ? thread.pause() : TPromise.as(null);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return super.isEnabled(state) && state === State.Running;
|
||||
}
|
||||
}
|
||||
|
||||
export class RestartFrameAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.restartFrame';
|
||||
static LABEL = nls.localize('restartFrame', "Restart Frame");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, undefined, debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(frame: IStackFrame): TPromise<any> {
|
||||
if (!frame) {
|
||||
frame = this.debugService.getViewModel().focusedStackFrame;
|
||||
}
|
||||
|
||||
return frame.restart();
|
||||
}
|
||||
}
|
||||
|
||||
export class RemoveBreakpointAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.removeBreakpoint';
|
||||
static LABEL = nls.localize('removeBreakpoint', "Remove Breakpoint");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action remove', debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(breakpoint: IBreakpoint): TPromise<any> {
|
||||
return breakpoint instanceof Breakpoint ? this.debugService.removeBreakpoints(breakpoint.getId())
|
||||
: this.debugService.removeFunctionBreakpoints(breakpoint.getId());
|
||||
}
|
||||
}
|
||||
|
||||
export class RemoveAllBreakpointsAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.removeAllBreakpoints';
|
||||
static LABEL = nls.localize('removeAllBreakpoints', "Remove All Breakpoints");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action remove-all', debugService, keybindingService);
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
return TPromise.join([this.debugService.removeBreakpoints(), this.debugService.removeFunctionBreakpoints()]);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
const model = this.debugService.getModel();
|
||||
return super.isEnabled(state) && (model.getBreakpoints().length > 0 || model.getFunctionBreakpoints().length > 0);
|
||||
}
|
||||
}
|
||||
|
||||
export class EnableBreakpointAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.enableBreakpoint';
|
||||
static LABEL = nls.localize('enableBreakpoint', "Enable Breakpoint");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, undefined, debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(element: IEnablement): TPromise<any> {
|
||||
return this.debugService.enableOrDisableBreakpoints(true, element);
|
||||
}
|
||||
}
|
||||
|
||||
export class DisableBreakpointAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.disableBreakpoint';
|
||||
static LABEL = nls.localize('disableBreakpoint', "Disable Breakpoint");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, undefined, debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(element: IEnablement): TPromise<any> {
|
||||
return this.debugService.enableOrDisableBreakpoints(false, element);
|
||||
}
|
||||
}
|
||||
|
||||
export class EnableAllBreakpointsAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.enableAllBreakpoints';
|
||||
static LABEL = nls.localize('enableAllBreakpoints', "Enable All Breakpoints");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action enable-all-breakpoints', debugService, keybindingService);
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
return this.debugService.enableOrDisableBreakpoints(true);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
const model = this.debugService.getModel();
|
||||
return super.isEnabled(state) && (<IEnablement[]>model.getBreakpoints()).concat(model.getFunctionBreakpoints()).concat(model.getExceptionBreakpoints()).some(bp => !bp.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
export class DisableAllBreakpointsAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.disableAllBreakpoints';
|
||||
static LABEL = nls.localize('disableAllBreakpoints', "Disable All Breakpoints");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action disable-all-breakpoints', debugService, keybindingService);
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
return this.debugService.enableOrDisableBreakpoints(false);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
const model = this.debugService.getModel();
|
||||
return super.isEnabled(state) && (<IEnablement[]>model.getBreakpoints()).concat(model.getFunctionBreakpoints()).concat(model.getExceptionBreakpoints()).some(bp => bp.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
export class ToggleBreakpointsActivatedAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.toggleBreakpointsActivatedAction';
|
||||
static ACTIVATE_LABEL = nls.localize('activateBreakpoints', "Activate Breakpoints");
|
||||
static DEACTIVATE_LABEL = nls.localize('deactivateBreakpoints', "Deactivate Breakpoints");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action breakpoints-activate', debugService, keybindingService);
|
||||
this.updateLabel(this.debugService.getModel().areBreakpointsActivated() ? ToggleBreakpointsActivatedAction.DEACTIVATE_LABEL : ToggleBreakpointsActivatedAction.ACTIVATE_LABEL);
|
||||
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => {
|
||||
this.updateLabel(this.debugService.getModel().areBreakpointsActivated() ? ToggleBreakpointsActivatedAction.DEACTIVATE_LABEL : ToggleBreakpointsActivatedAction.ACTIVATE_LABEL);
|
||||
this.updateEnablement();
|
||||
}));
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
return this.debugService.setBreakpointsActivated(!this.debugService.getModel().areBreakpointsActivated());
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return (this.debugService.getModel().getFunctionBreakpoints().length + this.debugService.getModel().getBreakpoints().length) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
export class ReapplyBreakpointsAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.reapplyBreakpointsAction';
|
||||
static LABEL = nls.localize('reapplyAllBreakpoints', "Reapply All Breakpoints");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, null, debugService, keybindingService);
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
return this.debugService.setBreakpointsActivated(true);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
const model = this.debugService.getModel();
|
||||
return super.isEnabled(state) && state !== State.Inactive &&
|
||||
(model.getFunctionBreakpoints().length + model.getBreakpoints().length + model.getExceptionBreakpoints().length > 0);
|
||||
}
|
||||
}
|
||||
|
||||
export class AddFunctionBreakpointAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.addFunctionBreakpointAction';
|
||||
static LABEL = nls.localize('addFunctionBreakpoint', "Add Function Breakpoint");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action add-function-breakpoint', debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
this.debugService.addFunctionBreakpoint();
|
||||
return TPromise.as(null);
|
||||
}
|
||||
}
|
||||
|
||||
export class RenameFunctionBreakpointAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.renameFunctionBreakpointAction';
|
||||
static LABEL = nls.localize('renameFunctionBreakpoint', "Rename Function Breakpoint");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, null, debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(fbp: IFunctionBreakpoint): TPromise<any> {
|
||||
this.debugService.getViewModel().setSelectedFunctionBreakpoint(fbp);
|
||||
return TPromise.as(null);
|
||||
}
|
||||
}
|
||||
|
||||
export class AddConditionalBreakpointAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.addConditionalBreakpointAction';
|
||||
static LABEL = nls.localize('addConditionalBreakpoint', "Add Conditional Breakpoint...");
|
||||
|
||||
constructor(id: string, label: string,
|
||||
private editor: ICodeEditor,
|
||||
private lineNumber: number,
|
||||
@IDebugService debugService: IDebugService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
) {
|
||||
super(id, label, null, debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
this.editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(this.lineNumber, undefined);
|
||||
return TPromise.as(null);
|
||||
}
|
||||
}
|
||||
|
||||
export class EditConditionalBreakpointAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.editConditionalBreakpointAction';
|
||||
static LABEL = nls.localize('editConditionalBreakpoint', "Edit Breakpoint...");
|
||||
|
||||
constructor(id: string, label: string,
|
||||
private editor: ICodeEditor,
|
||||
@IDebugService debugService: IDebugService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
) {
|
||||
super(id, label, null, debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(breakpoint: IBreakpoint): TPromise<any> {
|
||||
this.editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(breakpoint.lineNumber, breakpoint.column);
|
||||
return TPromise.as(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class SetValueAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.setValue';
|
||||
static LABEL = nls.localize('setValue', "Set Value");
|
||||
|
||||
constructor(id: string, label: string, private variable: Variable, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, null, debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
if (this.variable instanceof Variable) {
|
||||
this.debugService.getViewModel().setSelectedExpression(this.variable);
|
||||
}
|
||||
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
const process = this.debugService.getViewModel().focusedProcess;
|
||||
return super.isEnabled(state) && state === State.Stopped && process && process.session.capabilities.supportsSetVariable;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class AddWatchExpressionAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.addWatchExpression';
|
||||
static LABEL = nls.localize('addWatchExpression', "Add Expression");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action add-watch-expression', debugService, keybindingService);
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeWatchExpressions(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
return this.debugService.addWatchExpression();
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return super.isEnabled(state) && this.debugService.getModel().getWatchExpressions().every(we => !!we.name);
|
||||
}
|
||||
}
|
||||
|
||||
export class EditWatchExpressionAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.editWatchExpression';
|
||||
static LABEL = nls.localize('editWatchExpression', "Edit Expression");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, undefined, debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(expression: Expression): TPromise<any> {
|
||||
this.debugService.getViewModel().setSelectedExpression(expression);
|
||||
return TPromise.as(null);
|
||||
}
|
||||
}
|
||||
|
||||
export class AddToWatchExpressionsAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.addToWatchExpressions';
|
||||
static LABEL = nls.localize('addToWatchExpressions', "Add to Watch");
|
||||
|
||||
constructor(id: string, label: string, private expression: IExpression, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action add-to-watch', debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
const name = this.expression instanceof Variable ? this.expression.evaluateName : this.expression.name;
|
||||
return this.debugService.addWatchExpression(name);
|
||||
}
|
||||
}
|
||||
|
||||
export class RemoveWatchExpressionAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.removeWatchExpression';
|
||||
static LABEL = nls.localize('removeWatchExpression', "Remove Expression");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, undefined, debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(expression: Expression): TPromise<any> {
|
||||
this.debugService.removeWatchExpressions(expression.getId());
|
||||
return TPromise.as(null);
|
||||
}
|
||||
}
|
||||
|
||||
export class RemoveAllWatchExpressionsAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.viewlet.action.removeAllWatchExpressions';
|
||||
static LABEL = nls.localize('removeAllWatchExpressions', "Remove All Expressions");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action remove-all', debugService, keybindingService);
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeWatchExpressions(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
this.debugService.removeWatchExpressions();
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
return super.isEnabled(state) && this.debugService.getModel().getWatchExpressions().length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
export class ClearReplAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.debug.panel.action.clearReplAction';
|
||||
static LABEL = nls.localize('clearRepl', "Clear Console");
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IDebugService debugService: IDebugService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IPanelService private panelService: IPanelService
|
||||
) {
|
||||
super(id, label, 'debug-action clear-repl', debugService, keybindingService);
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
this.debugService.removeReplExpressions();
|
||||
|
||||
// focus back to repl
|
||||
return this.panelService.openPanel(REPL_ID, true);
|
||||
}
|
||||
}
|
||||
|
||||
export class ToggleReplAction extends TogglePanelAction {
|
||||
static ID = 'workbench.debug.action.toggleRepl';
|
||||
static LABEL = nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugConsoleAction' }, 'Debug Console');
|
||||
private toDispose: lifecycle.IDisposable[];
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IDebugService private debugService: IDebugService,
|
||||
@IPartService partService: IPartService,
|
||||
@IPanelService panelService: IPanelService
|
||||
) {
|
||||
super(id, label, REPL_ID, panelService, partService, 'debug-action toggle-repl');
|
||||
this.toDispose = [];
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeReplElements(() => {
|
||||
if (!this.isReplVisible()) {
|
||||
this.class = 'debug-action toggle-repl notification';
|
||||
this.tooltip = nls.localize('unreadOutput', "New Output in Debug Console");
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(this.panelService.onDidPanelOpen(panel => {
|
||||
if (panel.getId() === REPL_ID) {
|
||||
this.class = 'debug-action toggle-repl';
|
||||
this.tooltip = ToggleReplAction.LABEL;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private isReplVisible(): boolean {
|
||||
const panel = this.panelService.getActivePanel();
|
||||
return panel && panel.getId() === REPL_ID;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
this.toDispose = lifecycle.dispose(this.toDispose);
|
||||
}
|
||||
}
|
||||
|
||||
export class FocusReplAction extends Action {
|
||||
|
||||
static ID = 'workbench.debug.action.focusRepl';
|
||||
static LABEL = nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugFocusConsole' }, 'Focus Debug Console');
|
||||
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IPanelService private panelService: IPanelService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
return this.panelService.openPanel(REPL_ID, true);
|
||||
}
|
||||
}
|
||||
|
||||
export class FocusProcessAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.focusProcess';
|
||||
static LABEL = nls.localize('focusProcess', "Focus Process");
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IDebugService debugService: IDebugService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService
|
||||
) {
|
||||
super(id, label, null, debugService, keybindingService, 100);
|
||||
}
|
||||
|
||||
public run(processName: string): TPromise<any> {
|
||||
const isMultiRoot = this.debugService.getConfigurationManager().getLaunches().length > 1;
|
||||
const process = this.debugService.getModel().getProcesses().filter(p => p.getName(isMultiRoot) === processName).pop();
|
||||
return this.debugService.focusStackFrameAndEvaluate(null, process, true).then(() => {
|
||||
const stackFrame = this.debugService.getViewModel().focusedStackFrame;
|
||||
if (stackFrame) {
|
||||
return stackFrame.openInEditor(this.editorService, true);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Actions used by the chakra debugger
|
||||
export class StepBackAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.stepBack';
|
||||
static LABEL = nls.localize('stepBackDebug', "Step Back");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action step-back', debugService, keybindingService, 50);
|
||||
}
|
||||
|
||||
public run(thread: IThread): TPromise<any> {
|
||||
if (!(thread instanceof Thread)) {
|
||||
thread = this.debugService.getViewModel().focusedThread;
|
||||
}
|
||||
|
||||
return thread ? thread.stepBack() : TPromise.as(null);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
const process = this.debugService.getViewModel().focusedProcess;
|
||||
return super.isEnabled(state) && state === State.Stopped &&
|
||||
process && process.session.capabilities.supportsStepBack;
|
||||
}
|
||||
}
|
||||
|
||||
export class ReverseContinueAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.reverseContinue';
|
||||
static LABEL = nls.localize('reverseContinue', "Reverse");
|
||||
|
||||
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
|
||||
super(id, label, 'debug-action reverse-continue', debugService, keybindingService, 60);
|
||||
}
|
||||
|
||||
public run(thread: IThread): TPromise<any> {
|
||||
if (!(thread instanceof Thread)) {
|
||||
thread = this.debugService.getViewModel().focusedThread;
|
||||
}
|
||||
|
||||
return thread ? thread.reverseContinue() : TPromise.as(null);
|
||||
}
|
||||
|
||||
protected isEnabled(state: State): boolean {
|
||||
const process = this.debugService.getViewModel().focusedProcess;
|
||||
return super.isEnabled(state) && state === State.Stopped &&
|
||||
process && process.session.capabilities.supportsStepBack;
|
||||
}
|
||||
}
|
||||
278
src/vs/workbench/parts/debug/browser/debugActionsWidget.ts
Normal file
@@ -0,0 +1,278 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!vs/workbench/parts/debug/browser/media/debugActionsWidget';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import * as builder from 'vs/base/browser/builder';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { EventType } from 'vs/base/common/events';
|
||||
import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IDebugConfiguration, IDebugService, State } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { AbstractDebugAction, PauseAction, ContinueAction, StepBackAction, ReverseContinueAction, StopAction, DisconnectAction, StepOverAction, StepIntoAction, StepOutAction, RestartAction, FocusProcessAction } from 'vs/workbench/parts/debug/browser/debugActions';
|
||||
import { FocusProcessActionItem } from 'vs/workbench/parts/debug/browser/debugActionItems';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IMessageService } from 'vs/platform/message/common/message';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { Themable } from 'vs/workbench/common/theme';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { registerColor, contrastBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
const $ = builder.$;
|
||||
const DEBUG_ACTIONS_WIDGET_POSITION_KEY = 'debug.actionswidgetposition';
|
||||
|
||||
export const debugToolBarBackground = registerColor('debugToolBar.background', {
|
||||
dark: '#333333',
|
||||
light: '#F3F3F3',
|
||||
hc: '#000000'
|
||||
}, localize('debugToolBarBackground', "Debug toolbar background color."));
|
||||
|
||||
export class DebugActionsWidget extends Themable implements IWorkbenchContribution {
|
||||
private static ID = 'debug.actionsWidget';
|
||||
|
||||
private $el: builder.Builder;
|
||||
private dragArea: builder.Builder;
|
||||
private actionBar: ActionBar;
|
||||
private allActions: AbstractDebugAction[];
|
||||
private activeActions: AbstractDebugAction[];
|
||||
|
||||
private isVisible: boolean;
|
||||
private isBuilt: boolean;
|
||||
|
||||
constructor(
|
||||
@IMessageService private messageService: IMessageService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService,
|
||||
@IDebugService private debugService: IDebugService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IPartService private partService: IPartService,
|
||||
@IStorageService private storageService: IStorageService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IThemeService themeService: IThemeService
|
||||
) {
|
||||
super(themeService);
|
||||
|
||||
this.$el = $().div().addClass('debug-actions-widget').style('top', `${partService.getTitleBarOffset()}px`);
|
||||
this.dragArea = $().div().addClass('drag-area');
|
||||
this.$el.append(this.dragArea);
|
||||
|
||||
const actionBarContainter = $().div().addClass('.action-bar-container');
|
||||
this.$el.append(actionBarContainter);
|
||||
|
||||
this.activeActions = [];
|
||||
this.actionBar = new ActionBar(actionBarContainter, {
|
||||
orientation: ActionsOrientation.HORIZONTAL,
|
||||
actionItemProvider: (action: IAction) => {
|
||||
if (action.id === FocusProcessAction.ID) {
|
||||
return this.instantiationService.createInstance(FocusProcessActionItem, action);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
this.updateStyles();
|
||||
|
||||
this.toUnbind.push(this.actionBar);
|
||||
this.registerListeners();
|
||||
|
||||
this.hide();
|
||||
this.isBuilt = false;
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this.toUnbind.push(this.debugService.onDidChangeState(state => this.update(state)));
|
||||
this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(() => this.update(this.debugService.state)));
|
||||
this.toUnbind.push(this.actionBar.actionRunner.addListener(EventType.RUN, (e: any) => {
|
||||
// check for error
|
||||
if (e.error && !errors.isPromiseCanceledError(e.error)) {
|
||||
this.messageService.show(severity.Error, e.error);
|
||||
}
|
||||
|
||||
// log in telemetry
|
||||
if (this.telemetryService) {
|
||||
this.telemetryService.publicLog('workbenchActionExecuted', { id: e.action.id, from: 'debugActionsWidget' });
|
||||
}
|
||||
}));
|
||||
$(window).on(dom.EventType.RESIZE, () => this.setXCoordinate(), this.toUnbind);
|
||||
|
||||
this.dragArea.on(dom.EventType.MOUSE_UP, (event: MouseEvent) => {
|
||||
const mouseClickEvent = new StandardMouseEvent(event);
|
||||
if (mouseClickEvent.detail === 2) {
|
||||
// double click on debug bar centers it again #8250
|
||||
const widgetWidth = this.$el.getHTMLElement().clientWidth;
|
||||
this.setXCoordinate(0.5 * window.innerWidth - 0.5 * widgetWidth);
|
||||
this.storePosition();
|
||||
}
|
||||
});
|
||||
|
||||
this.dragArea.on(dom.EventType.MOUSE_DOWN, (event: MouseEvent) => {
|
||||
const $window = $(window);
|
||||
this.dragArea.addClass('dragged');
|
||||
|
||||
$window.on('mousemove', (e: MouseEvent) => {
|
||||
const mouseMoveEvent = new StandardMouseEvent(e);
|
||||
// Prevent default to stop editor selecting text #8524
|
||||
mouseMoveEvent.preventDefault();
|
||||
// Reduce x by width of drag handle to reduce jarring #16604
|
||||
this.setXCoordinate(mouseMoveEvent.posx - 14);
|
||||
}).once('mouseup', (e: MouseEvent) => {
|
||||
this.storePosition();
|
||||
this.dragArea.removeClass('dragged');
|
||||
$window.off('mousemove');
|
||||
});
|
||||
});
|
||||
|
||||
this.toUnbind.push(this.partService.onTitleBarVisibilityChange(() => this.positionDebugWidget()));
|
||||
this.toUnbind.push(browser.onDidChangeZoomLevel(() => this.positionDebugWidget()));
|
||||
}
|
||||
|
||||
private storePosition(): void {
|
||||
const position = parseFloat(this.$el.getComputedStyle().left) / window.innerWidth;
|
||||
this.storageService.store(DEBUG_ACTIONS_WIDGET_POSITION_KEY, position, StorageScope.WORKSPACE);
|
||||
this.telemetryService.publicLog(DEBUG_ACTIONS_WIDGET_POSITION_KEY, { position });
|
||||
}
|
||||
|
||||
protected updateStyles(): void {
|
||||
super.updateStyles();
|
||||
|
||||
if (this.$el) {
|
||||
this.$el.style('background-color', this.getColor(debugToolBarBackground));
|
||||
|
||||
const widgetShadowColor = this.getColor(widgetShadow);
|
||||
this.$el.style('box-shadow', widgetShadowColor ? `0 5px 8px ${widgetShadowColor}` : null);
|
||||
|
||||
const contrastBorderColor = this.getColor(contrastBorder);
|
||||
this.$el.style('border-style', contrastBorderColor ? 'solid' : null);
|
||||
this.$el.style('border-width', contrastBorderColor ? '1px' : null);
|
||||
this.$el.style('border-color', contrastBorderColor);
|
||||
}
|
||||
}
|
||||
|
||||
private positionDebugWidget(): void {
|
||||
const titlebarOffset = this.partService.getTitleBarOffset();
|
||||
|
||||
$(this.$el).style('top', `${titlebarOffset}px`);
|
||||
}
|
||||
|
||||
private setXCoordinate(x?: number): void {
|
||||
if (!this.isVisible) {
|
||||
return;
|
||||
}
|
||||
const widgetWidth = this.$el.getHTMLElement().clientWidth;
|
||||
if (x === undefined) {
|
||||
const positionPercentage = this.storageService.get(DEBUG_ACTIONS_WIDGET_POSITION_KEY, StorageScope.WORKSPACE);
|
||||
x = positionPercentage !== undefined ? parseFloat(positionPercentage) * window.innerWidth : (0.5 * window.innerWidth - 0.5 * widgetWidth);
|
||||
}
|
||||
|
||||
x = Math.max(0, Math.min(x, window.innerWidth - widgetWidth)); // do not allow the widget to overflow on the right
|
||||
this.$el.style('left', `${x}px`);
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return DebugActionsWidget.ID;
|
||||
}
|
||||
|
||||
private update(state: State): void {
|
||||
if (state === State.Inactive || this.configurationService.getConfiguration<IDebugConfiguration>('debug').hideActionBar) {
|
||||
return this.hide();
|
||||
}
|
||||
|
||||
const actions = this.getActions();
|
||||
if (!arrays.equals(actions, this.activeActions, (first, second) => first.id === second.id)) {
|
||||
this.actionBar.clear();
|
||||
this.actionBar.push(actions, { icon: true, label: false });
|
||||
this.activeActions = actions;
|
||||
}
|
||||
this.show();
|
||||
}
|
||||
|
||||
private show(): void {
|
||||
if (this.isVisible) {
|
||||
return;
|
||||
}
|
||||
if (!this.isBuilt) {
|
||||
this.isBuilt = true;
|
||||
this.$el.build(builder.withElementById(this.partService.getWorkbenchElementId()).getHTMLElement());
|
||||
}
|
||||
|
||||
this.isVisible = true;
|
||||
this.$el.show();
|
||||
this.setXCoordinate();
|
||||
}
|
||||
|
||||
private hide(): void {
|
||||
this.isVisible = false;
|
||||
this.$el.hide();
|
||||
}
|
||||
|
||||
private getActions(): AbstractDebugAction[] {
|
||||
if (!this.allActions) {
|
||||
this.allActions = [];
|
||||
this.allActions.push(this.instantiationService.createInstance(ContinueAction, ContinueAction.ID, ContinueAction.LABEL));
|
||||
this.allActions.push(this.instantiationService.createInstance(PauseAction, PauseAction.ID, PauseAction.LABEL));
|
||||
this.allActions.push(this.instantiationService.createInstance(StopAction, StopAction.ID, StopAction.LABEL));
|
||||
this.allActions.push(this.instantiationService.createInstance(DisconnectAction, DisconnectAction.ID, DisconnectAction.LABEL));
|
||||
this.allActions.push(this.instantiationService.createInstance(StepOverAction, StepOverAction.ID, StepOverAction.LABEL));
|
||||
this.allActions.push(this.instantiationService.createInstance(StepIntoAction, StepIntoAction.ID, StepIntoAction.LABEL));
|
||||
this.allActions.push(this.instantiationService.createInstance(StepOutAction, StepOutAction.ID, StepOutAction.LABEL));
|
||||
this.allActions.push(this.instantiationService.createInstance(RestartAction, RestartAction.ID, RestartAction.LABEL));
|
||||
this.allActions.push(this.instantiationService.createInstance(StepBackAction, StepBackAction.ID, StepBackAction.LABEL));
|
||||
this.allActions.push(this.instantiationService.createInstance(ReverseContinueAction, ReverseContinueAction.ID, ReverseContinueAction.LABEL));
|
||||
this.allActions.push(this.instantiationService.createInstance(FocusProcessAction, FocusProcessAction.ID, FocusProcessAction.LABEL));
|
||||
this.allActions.forEach(a => {
|
||||
this.toUnbind.push(a);
|
||||
});
|
||||
}
|
||||
|
||||
const state = this.debugService.state;
|
||||
const process = this.debugService.getViewModel().focusedProcess;
|
||||
const attached = process && process.configuration.request === 'attach' && process.configuration.type && !strings.equalsIgnoreCase(process.configuration.type, 'extensionHost');
|
||||
|
||||
return this.allActions.filter(a => {
|
||||
if (a.id === ContinueAction.ID) {
|
||||
return state !== State.Running;
|
||||
}
|
||||
if (a.id === PauseAction.ID) {
|
||||
return state === State.Running;
|
||||
}
|
||||
if (a.id === StepBackAction.ID) {
|
||||
return process && process.session.capabilities.supportsStepBack;
|
||||
}
|
||||
if (a.id === ReverseContinueAction.ID) {
|
||||
return process && process.session.capabilities.supportsStepBack;
|
||||
}
|
||||
if (a.id === DisconnectAction.ID) {
|
||||
return attached;
|
||||
}
|
||||
if (a.id === StopAction.ID) {
|
||||
return !attached;
|
||||
}
|
||||
if (a.id === FocusProcessAction.ID) {
|
||||
return this.debugService.getViewModel().isMultiProcessView();
|
||||
}
|
||||
|
||||
return true;
|
||||
}).sort((first, second) => first.weight - second.weight);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
if (this.$el) {
|
||||
this.$el.destroy();
|
||||
delete this.$el;
|
||||
}
|
||||
}
|
||||
}
|
||||
77
src/vs/workbench/parts/debug/browser/debugContentProvider.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import uri from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { guessMimeTypes, MIME_TEXT } from 'vs/base/common/mime';
|
||||
import { IModel } from 'vs/editor/common/editorCommon';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { ITextModelService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { DEBUG_SCHEME, IDebugService, IProcess } from 'vs/workbench/parts/debug/common/debug';
|
||||
|
||||
export class DebugContentProvider implements IWorkbenchContribution, ITextModelContentProvider {
|
||||
|
||||
constructor(
|
||||
@ITextModelService textModelResolverService: ITextModelService,
|
||||
@IDebugService private debugService: IDebugService,
|
||||
@IModelService private modelService: IModelService,
|
||||
@IModeService private modeService: IModeService
|
||||
) {
|
||||
textModelResolverService.registerTextModelContentProvider(DEBUG_SCHEME, this);
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return 'debug.contentprovider';
|
||||
}
|
||||
|
||||
public provideTextContent(resource: uri): TPromise<IModel> {
|
||||
|
||||
let process: IProcess;
|
||||
if (resource.query) {
|
||||
const keyvalues = resource.query.split('&');
|
||||
for (let keyvalue of keyvalues) {
|
||||
const pair = keyvalue.split('=');
|
||||
if (pair.length === 2 && pair[0] === 'session') {
|
||||
process = this.debugService.findProcessByUUID(decodeURIComponent(pair[1]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!process) {
|
||||
// fallback: use focused process
|
||||
process = this.debugService.getViewModel().focusedProcess;
|
||||
}
|
||||
|
||||
if (!process) {
|
||||
return TPromise.wrapError<IModel>(new Error(localize('unable', "Unable to resolve the resource without a debug session")));
|
||||
}
|
||||
const source = process.sources.get(resource.toString());
|
||||
let rawSource: DebugProtocol.Source;
|
||||
if (source) {
|
||||
rawSource = source.raw;
|
||||
} else {
|
||||
// Remove debug: scheme
|
||||
rawSource = { path: resource.with({ scheme: '', query: '' }).toString(true) };
|
||||
}
|
||||
|
||||
return process.session.source({ sourceReference: source ? source.reference : undefined, source: rawSource }).then(response => {
|
||||
const mime = response.body.mimeType || guessMimeTypes(resource.toString())[0];
|
||||
const modePromise = this.modeService.getOrCreateMode(mime);
|
||||
const model = this.modelService.createModel(response.body.content, modePromise, resource);
|
||||
|
||||
return model;
|
||||
}, (err: DebugProtocol.ErrorResponse) => {
|
||||
this.debugService.sourceIsNotAvailable(resource);
|
||||
const modePromise = this.modeService.getOrCreateMode(MIME_TEXT);
|
||||
const model = this.modelService.createModel(err.message, modePromise, resource);
|
||||
|
||||
return model;
|
||||
});
|
||||
}
|
||||
}
|
||||
277
src/vs/workbench/parts/debug/browser/debugEditorActions.ts
Normal file
@@ -0,0 +1,277 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ICommonCodeEditor } from 'vs/editor/common/editorCommon';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { ServicesAccessor, editorAction, EditorAction, CommonEditorRegistry, EditorCommand } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IDebugService, CONTEXT_IN_DEBUG_MODE, CONTEXT_NOT_IN_DEBUG_REPL, CONTEXT_DEBUG_STATE, State, REPL_ID, VIEWLET_ID, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, CONTEXT_BREAKPOINT_WIDGET_VISIBLE } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
|
||||
@editorAction
|
||||
class ToggleBreakpointAction extends EditorAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.debug.action.toggleBreakpoint',
|
||||
label: nls.localize('toggleBreakpointAction', "Debug: Toggle Breakpoint"),
|
||||
alias: 'Debug: Toggle Breakpoint',
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
primary: KeyCode.F9
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): TPromise<any> {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
|
||||
const position = editor.getPosition();
|
||||
const modelUri = editor.getModel().uri;
|
||||
const bps = debugService.getModel().getBreakpoints()
|
||||
.filter(bp => bp.lineNumber === position.lineNumber && bp.uri.toString() === modelUri.toString());
|
||||
|
||||
if (bps.length) {
|
||||
return TPromise.join(bps.map(bp => debugService.removeBreakpoints(bp.getId())));
|
||||
}
|
||||
if (debugService.getConfigurationManager().canSetBreakpointsIn(editor.getModel())) {
|
||||
return debugService.addBreakpoints(modelUri, [{ lineNumber: position.lineNumber }]);
|
||||
}
|
||||
|
||||
return TPromise.as(null);
|
||||
}
|
||||
}
|
||||
|
||||
function addColumnBreakpoint(accessor: ServicesAccessor, editor: ICommonCodeEditor, remove: boolean): TPromise<any> {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
|
||||
const position = editor.getPosition();
|
||||
const modelUri = editor.getModel().uri;
|
||||
const bp = debugService.getModel().getBreakpoints()
|
||||
.filter(bp => bp.lineNumber === position.lineNumber && bp.column === position.column && bp.uri.toString() === modelUri.toString()).pop();
|
||||
|
||||
if (bp) {
|
||||
return remove ? debugService.removeBreakpoints(bp.getId()) : TPromise.as(null);
|
||||
}
|
||||
if (debugService.getConfigurationManager().canSetBreakpointsIn(editor.getModel())) {
|
||||
return debugService.addBreakpoints(modelUri, [{ lineNumber: position.lineNumber, column: position.column }]);
|
||||
}
|
||||
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
@editorAction
|
||||
class ToggleColumnBreakpointAction extends EditorAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.debug.action.toggleColumnBreakpoint',
|
||||
label: nls.localize('columnBreakpointAction', "Debug: Column Breakpoint"),
|
||||
alias: 'Debug: Column Breakpoint',
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
primary: KeyMod.Shift | KeyCode.F9
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): TPromise<any> {
|
||||
return addColumnBreakpoint(accessor, editor, true);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO@Isidor merge two column breakpoints actions together
|
||||
@editorAction
|
||||
class ToggleColumnBreakpointContextMenuAction extends EditorAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.debug.action.toggleColumnBreakpointContextMenu',
|
||||
label: nls.localize('columnBreakpoint', "Add Column Breakpoint"),
|
||||
alias: 'Toggle Column Breakpoint',
|
||||
precondition: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_NOT_IN_DEBUG_REPL, EditorContextKeys.writable),
|
||||
menuOpts: {
|
||||
group: 'debug',
|
||||
order: 1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): TPromise<any> {
|
||||
return addColumnBreakpoint(accessor, editor, false);
|
||||
}
|
||||
}
|
||||
|
||||
@editorAction
|
||||
class ConditionalBreakpointAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.debug.action.conditionalBreakpoint',
|
||||
label: nls.localize('conditionalBreakpointEditorAction', "Debug: Add Conditional Breakpoint..."),
|
||||
alias: 'Debug: Add Conditional Breakpoint...',
|
||||
precondition: null
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): void {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
|
||||
const { lineNumber, column } = editor.getPosition();
|
||||
if (debugService.getConfigurationManager().canSetBreakpointsIn(editor.getModel())) {
|
||||
editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(lineNumber, column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@editorAction
|
||||
class RunToCursorAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.debug.action.runToCursor',
|
||||
label: nls.localize('runToCursor', "Run to Cursor"),
|
||||
alias: 'Debug: Run to Cursor',
|
||||
precondition: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_NOT_IN_DEBUG_REPL, EditorContextKeys.writable, CONTEXT_DEBUG_STATE.isEqualTo('stopped')),
|
||||
menuOpts: {
|
||||
group: 'debug',
|
||||
order: 2
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): TPromise<void> {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
|
||||
if (debugService.state !== State.Stopped) {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
const position = editor.getPosition();
|
||||
const uri = editor.getModel().uri;
|
||||
|
||||
const oneTimeListener = debugService.getViewModel().focusedProcess.session.onDidEvent(event => {
|
||||
if (event.event === 'stopped' || event.event === 'exit') {
|
||||
const toRemove = debugService.getModel().getBreakpoints()
|
||||
.filter(bp => bp.lineNumber === position.lineNumber && bp.uri.toString() === uri.toString()).pop();
|
||||
if (toRemove) {
|
||||
debugService.removeBreakpoints(toRemove.getId());
|
||||
}
|
||||
oneTimeListener.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
const bpExists = !!(debugService.getModel().getBreakpoints().filter(bp => bp.column === position.column && bp.lineNumber === position.lineNumber && bp.uri.toString() === uri.toString()).pop());
|
||||
return (bpExists ? TPromise.as(null) : debugService.addBreakpoints(uri, [{ lineNumber: position.lineNumber, column: position.column }])).then(() => {
|
||||
debugService.getViewModel().focusedThread.continue();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@editorAction
|
||||
class SelectionToReplAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.debug.action.selectionToRepl',
|
||||
label: nls.localize('debugEvaluate', "Debug: Evaluate"),
|
||||
alias: 'Debug: Evaluate',
|
||||
precondition: ContextKeyExpr.and(EditorContextKeys.hasNonEmptySelection, CONTEXT_IN_DEBUG_MODE, CONTEXT_NOT_IN_DEBUG_REPL),
|
||||
menuOpts: {
|
||||
group: 'debug',
|
||||
order: 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): TPromise<void> {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
const panelService = accessor.get(IPanelService);
|
||||
|
||||
const text = editor.getModel().getValueInRange(editor.getSelection());
|
||||
return debugService.addReplExpression(text)
|
||||
.then(() => panelService.openPanel(REPL_ID, true))
|
||||
.then(_ => void 0);
|
||||
}
|
||||
}
|
||||
|
||||
@editorAction
|
||||
class SelectionToWatchExpressionsAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.debug.action.selectionToWatch',
|
||||
label: nls.localize('debugAddToWatch', "Debug: Add to Watch"),
|
||||
alias: 'Debug: Add to Watch',
|
||||
precondition: ContextKeyExpr.and(EditorContextKeys.hasNonEmptySelection, CONTEXT_IN_DEBUG_MODE, CONTEXT_NOT_IN_DEBUG_REPL),
|
||||
menuOpts: {
|
||||
group: 'debug',
|
||||
order: 1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): TPromise<void> {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
const viewletService = accessor.get(IViewletService);
|
||||
|
||||
const text = editor.getModel().getValueInRange(editor.getSelection());
|
||||
return viewletService.openViewlet(VIEWLET_ID).then(() => debugService.addWatchExpression(text));
|
||||
}
|
||||
}
|
||||
|
||||
@editorAction
|
||||
class ShowDebugHoverAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.debug.action.showDebugHover',
|
||||
label: nls.localize('showDebugHover', "Debug: Show Hover"),
|
||||
alias: 'Debug: Show Hover',
|
||||
precondition: CONTEXT_IN_DEBUG_MODE,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_I)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICommonCodeEditor): TPromise<void> {
|
||||
const position = editor.getPosition();
|
||||
const word = editor.getModel().getWordAtPosition(position);
|
||||
if (!word) {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
const range = new Range(position.lineNumber, position.column, position.lineNumber, word.endColumn);
|
||||
return editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showHover(range, true);
|
||||
}
|
||||
}
|
||||
|
||||
class CloseBreakpointWidgetCommand extends EditorCommand {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'closeBreakpointWidget',
|
||||
precondition: CONTEXT_BREAKPOINT_WIDGET_VISIBLE,
|
||||
kbOpts: {
|
||||
weight: CommonEditorRegistry.commandWeight(8),
|
||||
kbExpr: EditorContextKeys.focus,
|
||||
primary: KeyCode.Escape,
|
||||
secondary: [KeyMod.Shift | KeyCode.Escape]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public runEditorCommand(accessor: ServicesAccessor, editor: ICommonCodeEditor, args: any): void {
|
||||
return editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).closeBreakpointWidget();
|
||||
}
|
||||
}
|
||||
|
||||
CommonEditorRegistry.registerEditorCommand(new CloseBreakpointWidgetCommand());
|
||||
387
src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts
Normal file
@@ -0,0 +1,387 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import { Constants } from 'vs/editor/common/core/uint';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IModel, TrackedRangeStickiness, IModelDeltaDecoration, IModelDecorationOptions } from 'vs/editor/common/editorCommon';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IDebugService, IBreakpoint, IRawBreakpoint, State } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModelDecorationsChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
interface IDebugEditorModelData {
|
||||
model: IModel;
|
||||
toDispose: lifecycle.IDisposable[];
|
||||
breakpointDecorationIds: string[];
|
||||
breakpointLines: number[];
|
||||
breakpointDecorationsAsMap: Map<string, boolean>;
|
||||
currentStackDecorations: string[];
|
||||
dirty: boolean;
|
||||
topStackFrameRange: Range;
|
||||
}
|
||||
|
||||
const stickiness = TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges;
|
||||
|
||||
export class DebugEditorModelManager implements IWorkbenchContribution {
|
||||
static ID = 'breakpointManager';
|
||||
|
||||
private modelDataMap: Map<string, IDebugEditorModelData>;
|
||||
private toDispose: lifecycle.IDisposable[];
|
||||
|
||||
constructor(
|
||||
@IModelService private modelService: IModelService,
|
||||
@IDebugService private debugService: IDebugService
|
||||
) {
|
||||
this.modelDataMap = new Map<string, IDebugEditorModelData>();
|
||||
this.toDispose = [];
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return DebugEditorModelManager.ID;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.modelDataMap.forEach(modelData => {
|
||||
lifecycle.dispose(modelData.toDispose);
|
||||
modelData.model.deltaDecorations(modelData.breakpointDecorationIds, []);
|
||||
modelData.model.deltaDecorations(modelData.currentStackDecorations, []);
|
||||
});
|
||||
this.toDispose = lifecycle.dispose(this.toDispose);
|
||||
|
||||
this.modelDataMap.clear();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this.toDispose.push(this.modelService.onModelAdded(this.onModelAdded, this));
|
||||
this.modelService.getModels().forEach(model => this.onModelAdded(model));
|
||||
this.toDispose.push(this.modelService.onModelRemoved(this.onModelRemoved, this));
|
||||
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange()));
|
||||
this.toDispose.push(this.debugService.getViewModel().onDidFocusStackFrame(() => this.onFocusStackFrame()));
|
||||
this.toDispose.push(this.debugService.onDidChangeState(state => {
|
||||
if (state === State.Inactive) {
|
||||
this.modelDataMap.forEach(modelData => {
|
||||
modelData.dirty = false;
|
||||
modelData.topStackFrameRange = undefined;
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private onModelAdded(model: IModel): void {
|
||||
const modelUrlStr = model.uri.toString();
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints().filter(bp => bp.uri.toString() === modelUrlStr);
|
||||
|
||||
const currentStackDecorations = model.deltaDecorations([], this.createCallStackDecorations(modelUrlStr));
|
||||
const breakPointDecorations = model.deltaDecorations([], this.createBreakpointDecorations(breakpoints));
|
||||
|
||||
const toDispose: lifecycle.IDisposable[] = [model.onDidChangeDecorations((e) => this.onModelDecorationsChanged(modelUrlStr, e))];
|
||||
const breakpointDecorationsAsMap = new Map<string, boolean>();
|
||||
breakPointDecorations.forEach(bpd => breakpointDecorationsAsMap.set(bpd, true));
|
||||
|
||||
this.modelDataMap.set(modelUrlStr, {
|
||||
model: model,
|
||||
toDispose: toDispose,
|
||||
breakpointDecorationIds: breakPointDecorations,
|
||||
breakpointLines: breakpoints.map(bp => bp.lineNumber),
|
||||
breakpointDecorationsAsMap,
|
||||
currentStackDecorations: currentStackDecorations,
|
||||
dirty: false,
|
||||
topStackFrameRange: undefined
|
||||
});
|
||||
}
|
||||
|
||||
private onModelRemoved(model: IModel): void {
|
||||
const modelUriStr = model.uri.toString();
|
||||
if (this.modelDataMap.has(modelUriStr)) {
|
||||
lifecycle.dispose(this.modelDataMap.get(modelUriStr).toDispose);
|
||||
this.modelDataMap.delete(modelUriStr);
|
||||
}
|
||||
}
|
||||
|
||||
// call stack management. Represent data coming from the debug service.
|
||||
|
||||
private onFocusStackFrame(): void {
|
||||
this.modelDataMap.forEach((modelData, uri) => {
|
||||
modelData.currentStackDecorations = modelData.model.deltaDecorations(modelData.currentStackDecorations, this.createCallStackDecorations(uri));
|
||||
});
|
||||
}
|
||||
|
||||
private createCallStackDecorations(modelUriStr: string): IModelDeltaDecoration[] {
|
||||
const result: IModelDeltaDecoration[] = [];
|
||||
const stackFrame = this.debugService.getViewModel().focusedStackFrame;
|
||||
if (!stackFrame || stackFrame.source.uri.toString() !== modelUriStr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// only show decorations for the currently focused thread.
|
||||
const columnUntilEOLRange = new Range(stackFrame.range.startLineNumber, stackFrame.range.startColumn, stackFrame.range.startLineNumber, Constants.MAX_SAFE_SMALL_INTEGER);
|
||||
const range = new Range(stackFrame.range.startLineNumber, stackFrame.range.startColumn, stackFrame.range.startLineNumber, stackFrame.range.startColumn + 1);
|
||||
|
||||
// compute how to decorate the editor. Different decorations are used if this is a top stack frame, focused stack frame,
|
||||
// an exception or a stack frame that did not change the line number (we only decorate the columns, not the whole line).
|
||||
const callStack = stackFrame.thread.getCallStack();
|
||||
if (callStack && callStack.length && stackFrame === callStack[0]) {
|
||||
result.push({
|
||||
options: DebugEditorModelManager.TOP_STACK_FRAME_MARGIN,
|
||||
range
|
||||
});
|
||||
|
||||
if (stackFrame.thread.stoppedDetails && stackFrame.thread.stoppedDetails.reason === 'exception') {
|
||||
result.push({
|
||||
options: DebugEditorModelManager.TOP_STACK_FRAME_EXCEPTION_DECORATION,
|
||||
range: columnUntilEOLRange
|
||||
});
|
||||
} else {
|
||||
result.push({
|
||||
options: DebugEditorModelManager.TOP_STACK_FRAME_DECORATION,
|
||||
range: columnUntilEOLRange
|
||||
});
|
||||
if (stackFrame.range.endLineNumber && stackFrame.range.endColumn) {
|
||||
result.push({
|
||||
options: { className: 'debug-top-stack-frame-range' },
|
||||
range: stackFrame.range
|
||||
});
|
||||
}
|
||||
|
||||
if (this.modelDataMap.has(modelUriStr)) {
|
||||
const modelData = this.modelDataMap.get(modelUriStr);
|
||||
if (modelData.topStackFrameRange && modelData.topStackFrameRange.startLineNumber === stackFrame.range.startLineNumber && modelData.topStackFrameRange.startColumn !== stackFrame.range.startColumn) {
|
||||
result.push({
|
||||
options: DebugEditorModelManager.TOP_STACK_FRAME_INLINE_DECORATION,
|
||||
range: columnUntilEOLRange
|
||||
});
|
||||
}
|
||||
modelData.topStackFrameRange = columnUntilEOLRange;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.push({
|
||||
options: DebugEditorModelManager.FOCUSED_STACK_FRAME_MARGIN,
|
||||
range
|
||||
});
|
||||
if (stackFrame.range.endLineNumber && stackFrame.range.endColumn) {
|
||||
result.push({
|
||||
options: { className: 'debug-focused-stack-frame-range' },
|
||||
range: stackFrame.range
|
||||
});
|
||||
}
|
||||
|
||||
result.push({
|
||||
options: DebugEditorModelManager.FOCUSED_STACK_FRAME_DECORATION,
|
||||
range: columnUntilEOLRange
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// breakpoints management. Represent data coming from the debug service and also send data back.
|
||||
private onModelDecorationsChanged(modelUrlStr: string, e: IModelDecorationsChangedEvent): void {
|
||||
const modelData = this.modelDataMap.get(modelUrlStr);
|
||||
if (modelData.breakpointDecorationsAsMap.size === 0) {
|
||||
// I have no decorations
|
||||
return;
|
||||
}
|
||||
if (!e.changedDecorations.some(decorationId => modelData.breakpointDecorationsAsMap.has(decorationId))) {
|
||||
// nothing to do, my decorations did not change.
|
||||
return;
|
||||
}
|
||||
|
||||
const data: IRawBreakpoint[] = [];
|
||||
|
||||
const lineToBreakpointDataMap = new Map<number, IBreakpoint>();
|
||||
this.debugService.getModel().getBreakpoints().filter(bp => bp.uri.toString() === modelUrlStr).forEach(bp => {
|
||||
lineToBreakpointDataMap.set(bp.lineNumber, bp);
|
||||
});
|
||||
|
||||
const modelUri = modelData.model.uri;
|
||||
for (let i = 0, len = modelData.breakpointDecorationIds.length; i < len; i++) {
|
||||
const decorationRange = modelData.model.getDecorationRange(modelData.breakpointDecorationIds[i]);
|
||||
const lineNumber = modelData.breakpointLines[i];
|
||||
// check if the line got deleted.
|
||||
if (decorationRange.endColumn - decorationRange.startColumn > 0) {
|
||||
const breakpoint = lineToBreakpointDataMap.get(lineNumber);
|
||||
// since we know it is collapsed, it cannot grow to multiple lines
|
||||
data.push({
|
||||
lineNumber: decorationRange.startLineNumber,
|
||||
enabled: breakpoint.enabled,
|
||||
condition: breakpoint.condition,
|
||||
hitCondition: breakpoint.hitCondition,
|
||||
column: breakpoint.column ? decorationRange.startColumn : undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
modelData.dirty = this.debugService.state !== State.Inactive;
|
||||
|
||||
const toRemove = this.debugService.getModel().getBreakpoints()
|
||||
.filter(bp => bp.uri.toString() === modelUri.toString());
|
||||
|
||||
TPromise.join(toRemove.map(bp => this.debugService.removeBreakpoints(bp.getId()))).then(() => {
|
||||
this.debugService.addBreakpoints(modelUri, data);
|
||||
});
|
||||
}
|
||||
|
||||
private onBreakpointsChange(): void {
|
||||
const breakpointsMap = new Map<string, IBreakpoint[]>();
|
||||
this.debugService.getModel().getBreakpoints().forEach(bp => {
|
||||
const uriStr = bp.uri.toString();
|
||||
if (breakpointsMap.has(uriStr)) {
|
||||
breakpointsMap.get(uriStr).push(bp);
|
||||
} else {
|
||||
breakpointsMap.set(uriStr, [bp]);
|
||||
}
|
||||
});
|
||||
|
||||
breakpointsMap.forEach((bps, uri) => {
|
||||
if (this.modelDataMap.has(uri)) {
|
||||
this.updateBreakpoints(this.modelDataMap.get(uri), breakpointsMap.get(uri));
|
||||
}
|
||||
});
|
||||
this.modelDataMap.forEach((modelData, uri) => {
|
||||
if (!breakpointsMap.has(uri)) {
|
||||
this.updateBreakpoints(modelData, []);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private updateBreakpoints(modelData: IDebugEditorModelData, newBreakpoints: IBreakpoint[]): void {
|
||||
modelData.breakpointDecorationIds = modelData.model.deltaDecorations(modelData.breakpointDecorationIds, this.createBreakpointDecorations(newBreakpoints));
|
||||
modelData.breakpointDecorationsAsMap.clear();
|
||||
modelData.breakpointDecorationIds.forEach(id => modelData.breakpointDecorationsAsMap.set(id, true));
|
||||
modelData.breakpointLines = newBreakpoints.map(bp => bp.lineNumber);
|
||||
}
|
||||
|
||||
private createBreakpointDecorations(breakpoints: IBreakpoint[]): IModelDeltaDecoration[] {
|
||||
return breakpoints.map((breakpoint) => {
|
||||
const range = breakpoint.column ? new Range(breakpoint.lineNumber, breakpoint.column, breakpoint.lineNumber, breakpoint.column + 1)
|
||||
: new Range(breakpoint.lineNumber, 1, breakpoint.lineNumber, Constants.MAX_SAFE_SMALL_INTEGER); // Decoration has to have a width #20688
|
||||
return {
|
||||
options: this.getBreakpointDecorationOptions(breakpoint),
|
||||
range
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private getBreakpointDecorationOptions(breakpoint: IBreakpoint): IModelDecorationOptions {
|
||||
const activated = this.debugService.getModel().areBreakpointsActivated();
|
||||
const state = this.debugService.state;
|
||||
const debugActive = state === State.Running || state === State.Stopped || state === State.Initializing;
|
||||
const modelData = this.modelDataMap.get(breakpoint.uri.toString());
|
||||
|
||||
let result = (!breakpoint.enabled || !activated) ? DebugEditorModelManager.BREAKPOINT_DISABLED_DECORATION :
|
||||
debugActive && modelData && modelData.dirty && !breakpoint.verified ? DebugEditorModelManager.BREAKPOINT_DIRTY_DECORATION :
|
||||
debugActive && !breakpoint.verified ? DebugEditorModelManager.BREAKPOINT_UNVERIFIED_DECORATION :
|
||||
!breakpoint.condition && !breakpoint.hitCondition ? DebugEditorModelManager.BREAKPOINT_DECORATION : null;
|
||||
|
||||
if (result) {
|
||||
result = objects.clone(result);
|
||||
if (breakpoint.message) {
|
||||
result.glyphMarginHoverMessage = new MarkdownString().appendText(breakpoint.message);
|
||||
}
|
||||
if (breakpoint.column) {
|
||||
result.beforeContentClassName = `debug-breakpoint-column ${result.glyphMarginClassName}-column`;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const process = this.debugService.getViewModel().focusedProcess;
|
||||
if (process && !process.session.capabilities.supportsConditionalBreakpoints) {
|
||||
return DebugEditorModelManager.BREAKPOINT_UNSUPPORTED_DECORATION;
|
||||
}
|
||||
|
||||
const modeId = modelData ? modelData.model.getLanguageIdentifier().language : '';
|
||||
let condition: string;
|
||||
if (breakpoint.condition && breakpoint.hitCondition) {
|
||||
condition = `Expression: ${breakpoint.condition}\nHitCount: ${breakpoint.hitCondition}`;
|
||||
} else {
|
||||
condition = breakpoint.condition ? breakpoint.condition : breakpoint.hitCondition;
|
||||
}
|
||||
const glyphMarginHoverMessage = new MarkdownString().appendCodeblock(modeId, condition);
|
||||
const glyphMarginClassName = 'debug-breakpoint-conditional-glyph';
|
||||
const beforeContentClassName = breakpoint.column ? `debug-breakpoint-column ${glyphMarginClassName}-column` : undefined;
|
||||
|
||||
return {
|
||||
glyphMarginClassName,
|
||||
glyphMarginHoverMessage,
|
||||
stickiness,
|
||||
beforeContentClassName
|
||||
};
|
||||
}
|
||||
|
||||
// editor decorations
|
||||
|
||||
private static BREAKPOINT_DECORATION: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-breakpoint-glyph',
|
||||
stickiness
|
||||
};
|
||||
|
||||
private static BREAKPOINT_DISABLED_DECORATION: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-breakpoint-disabled-glyph',
|
||||
glyphMarginHoverMessage: new MarkdownString().appendText(nls.localize('breakpointDisabledHover', "Disabled Breakpoint")),
|
||||
stickiness
|
||||
};
|
||||
|
||||
private static BREAKPOINT_UNVERIFIED_DECORATION: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-breakpoint-unverified-glyph',
|
||||
glyphMarginHoverMessage: new MarkdownString().appendText(nls.localize('breakpointUnverifieddHover', "Unverified Breakpoint")),
|
||||
stickiness
|
||||
};
|
||||
|
||||
private static BREAKPOINT_DIRTY_DECORATION: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-breakpoint-unverified-glyph',
|
||||
glyphMarginHoverMessage: new MarkdownString().appendText(nls.localize('breakpointDirtydHover', "Unverified breakpoint. File is modified, please restart debug session.")),
|
||||
stickiness
|
||||
};
|
||||
|
||||
private static BREAKPOINT_UNSUPPORTED_DECORATION: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-breakpoint-unsupported-glyph',
|
||||
glyphMarginHoverMessage: new MarkdownString().appendText(nls.localize('breakpointUnsupported', "Conditional breakpoints not supported by this debug type")),
|
||||
stickiness
|
||||
};
|
||||
|
||||
// we need a separate decoration for glyph margin, since we do not want it on each line of a multi line statement.
|
||||
private static TOP_STACK_FRAME_MARGIN: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-top-stack-frame-glyph',
|
||||
stickiness
|
||||
};
|
||||
|
||||
private static FOCUSED_STACK_FRAME_MARGIN: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-focused-stack-frame-glyph',
|
||||
stickiness
|
||||
};
|
||||
|
||||
private static TOP_STACK_FRAME_DECORATION: IModelDecorationOptions = {
|
||||
isWholeLine: true,
|
||||
inlineClassName: 'debug-remove-token-colors',
|
||||
className: 'debug-top-stack-frame-line',
|
||||
stickiness
|
||||
};
|
||||
|
||||
private static TOP_STACK_FRAME_EXCEPTION_DECORATION: IModelDecorationOptions = {
|
||||
isWholeLine: true,
|
||||
inlineClassName: 'debug-remove-token-colors',
|
||||
className: 'debug-top-stack-frame-exception-line',
|
||||
stickiness
|
||||
};
|
||||
|
||||
private static TOP_STACK_FRAME_INLINE_DECORATION: IModelDecorationOptions = {
|
||||
beforeContentClassName: 'debug-top-stack-frame-column'
|
||||
};
|
||||
|
||||
private static FOCUSED_STACK_FRAME_DECORATION: IModelDecorationOptions = {
|
||||
isWholeLine: true,
|
||||
inlineClassName: 'debug-remove-token-colors',
|
||||
className: 'debug-focused-stack-frame-line',
|
||||
stickiness
|
||||
};
|
||||
}
|
||||
80
src/vs/workbench/parts/debug/browser/debugQuickOpen.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import nls = require('vs/nls');
|
||||
import Filters = require('vs/base/common/filters');
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import Quickopen = require('vs/workbench/browser/quickopen');
|
||||
import QuickOpen = require('vs/base/parts/quickopen/common/quickOpen');
|
||||
import Model = require('vs/base/parts/quickopen/browser/quickOpenModel');
|
||||
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import { IDebugService, ILaunch } from 'vs/workbench/parts/debug/common/debug';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
|
||||
class DebugEntry extends Model.QuickOpenEntry {
|
||||
|
||||
constructor(private debugService: IDebugService, private launch: ILaunch, private configurationName: string, highlights: Model.IHighlight[] = []) {
|
||||
super(highlights);
|
||||
}
|
||||
|
||||
public getLabel(): string {
|
||||
return this.debugService.getConfigurationManager().getLaunches().length <= 1 ? this.configurationName : `${this.configurationName} (${this.launch.name})`;
|
||||
}
|
||||
|
||||
public getAriaLabel(): string {
|
||||
return nls.localize('entryAriaLabel', "{0}, debug", this.getLabel());
|
||||
}
|
||||
|
||||
public run(mode: QuickOpen.Mode, context: Model.IContext): boolean {
|
||||
if (mode === QuickOpen.Mode.PREVIEW) {
|
||||
return false;
|
||||
}
|
||||
// Run selected debug configuration
|
||||
this.debugService.getConfigurationManager().selectConfiguration(this.launch, this.configurationName);
|
||||
this.debugService.startDebugging(this.launch.workspaceUri).done(undefined, errors.onUnexpectedError);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class DebugQuickOpenHandler extends Quickopen.QuickOpenHandler {
|
||||
|
||||
constructor(
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService,
|
||||
@IDebugService private debugService: IDebugService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public getAriaLabel(): string {
|
||||
return nls.localize('debugAriaLabel', "Type a name of a launch configuration to run.");
|
||||
}
|
||||
|
||||
public getResults(input: string): TPromise<Model.QuickOpenModel> {
|
||||
const configurations: DebugEntry[] = [];
|
||||
|
||||
for (let launch of this.debugService.getConfigurationManager().getLaunches()) {
|
||||
launch.getConfigurationNames().map(config => ({ config: config, highlights: Filters.matchesContiguousSubString(input, config) }))
|
||||
.filter(({ highlights }) => !!highlights)
|
||||
.forEach(({ config, highlights }) => configurations.push(new DebugEntry(this.debugService, launch, config, highlights)));
|
||||
}
|
||||
|
||||
return TPromise.as(new Model.QuickOpenModel(configurations));
|
||||
}
|
||||
|
||||
public getAutoFocus(input: string): QuickOpen.IAutoFocus {
|
||||
return {
|
||||
autoFocusFirstEntry: !!input
|
||||
};
|
||||
}
|
||||
|
||||
public getEmptyLabel(searchString: string): string {
|
||||
if (searchString.length > 0) {
|
||||
return nls.localize('noConfigurationsMatching', "No debug configurations matching");
|
||||
}
|
||||
|
||||
return nls.localize('noConfigurationsFound', "No debug configurations found. Please create a 'launch.json' file.");
|
||||
}
|
||||
}
|
||||
105
src/vs/workbench/parts/debug/browser/debugViewlet.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/debugViewlet';
|
||||
import { Builder } from 'vs/base/browser/builder';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { PersistentViewsViewlet } from 'vs/workbench/parts/views/browser/views';
|
||||
import { IDebugService, VIEWLET_ID, State } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { StartAction, ToggleReplAction, ConfigureAction } from 'vs/workbench/parts/debug/browser/debugActions';
|
||||
import { StartDebugActionItem } from 'vs/workbench/parts/debug/browser/debugActionItems';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
|
||||
import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { ViewLocation } from 'vs/workbench/parts/views/browser/viewsRegistry';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
|
||||
export class DebugViewlet extends PersistentViewsViewlet {
|
||||
|
||||
private actions: IAction[];
|
||||
private startDebugActionItem: StartDebugActionItem;
|
||||
private progressRunner: IProgressRunner;
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IProgressService private progressService: IProgressService,
|
||||
@IDebugService private debugService: IDebugService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IExtensionService extensionService: IExtensionService
|
||||
) {
|
||||
super(VIEWLET_ID, ViewLocation.Debug, `${VIEWLET_ID}.state`, false, telemetryService, storageService, instantiationService, themeService, contextService, contextKeyService, contextMenuService, extensionService);
|
||||
|
||||
this.progressRunner = null;
|
||||
|
||||
this._register(this.debugService.onDidChangeState(state => this.onDebugServiceStateChange(state)));
|
||||
}
|
||||
|
||||
public create(parent: Builder): TPromise<void> {
|
||||
return super.create(parent).then(() => DOM.addClass(this.viewletContainer, 'debug-viewlet'));
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
super.focus();
|
||||
|
||||
if (!this.contextService.hasWorkspace()) {
|
||||
this.views[0].focusBody();
|
||||
}
|
||||
|
||||
if (this.startDebugActionItem) {
|
||||
this.startDebugActionItem.focus();
|
||||
}
|
||||
}
|
||||
|
||||
public getActions(): IAction[] {
|
||||
if (!this.actions) {
|
||||
this.actions = [];
|
||||
this.actions.push(this.instantiationService.createInstance(StartAction, StartAction.ID, StartAction.LABEL));
|
||||
if (this.contextService.hasWorkspace()) {
|
||||
this.actions.push(this.instantiationService.createInstance(ConfigureAction, ConfigureAction.ID, ConfigureAction.LABEL));
|
||||
}
|
||||
this.actions.push(this._register(this.instantiationService.createInstance(ToggleReplAction, ToggleReplAction.ID, ToggleReplAction.LABEL)));
|
||||
}
|
||||
|
||||
return this.actions;
|
||||
}
|
||||
|
||||
public getSecondaryActions(): IAction[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
public getActionItem(action: IAction): IActionItem {
|
||||
if (action.id === StartAction.ID && this.contextService.hasWorkspace()) {
|
||||
this.startDebugActionItem = this.instantiationService.createInstance(StartDebugActionItem, null, action);
|
||||
return this.startDebugActionItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private onDebugServiceStateChange(state: State): void {
|
||||
if (this.progressRunner) {
|
||||
this.progressRunner.done();
|
||||
}
|
||||
|
||||
if (state === State.Initializing) {
|
||||
this.progressRunner = this.progressService.show(true);
|
||||
} else {
|
||||
this.progressRunner = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
102
src/vs/workbench/parts/debug/browser/exceptionWidget.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!../browser/media/exceptionWidget';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/browser/zoneWidget';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IDebugService, IExceptionInfo } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { LinkDetector } from 'vs/workbench/parts/debug/browser/linkDetector';
|
||||
const $ = dom.$;
|
||||
|
||||
// theming
|
||||
|
||||
export const debugExceptionWidgetBorder = registerColor('debugExceptionWidget.border', { dark: '#a31515', light: '#a31515', hc: '#a31515' }, nls.localize('debugExceptionWidgetBorder', 'Exception widget border color.'));
|
||||
export const debugExceptionWidgetBackground = registerColor('debugExceptionWidget.background', { dark: '#a3151540', light: '#a315150d', hc: '#a3151573' }, nls.localize('debugExceptionWidgetBackground', 'Exception widget background color.'));
|
||||
|
||||
export class ExceptionWidget extends ZoneWidget {
|
||||
|
||||
private _backgroundColor: Color;
|
||||
|
||||
constructor(editor: ICodeEditor, private exceptionInfo: IExceptionInfo, private lineNumber: number,
|
||||
@IContextViewService private contextViewService: IContextViewService,
|
||||
@IDebugService private debugService: IDebugService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
) {
|
||||
super(editor, { showFrame: true, showArrow: true, frameWidth: 1, className: 'exception-widget-container' });
|
||||
|
||||
this._backgroundColor = Color.white;
|
||||
|
||||
this._applyTheme(themeService.getTheme());
|
||||
this._disposables.push(themeService.onThemeChange(this._applyTheme.bind(this)));
|
||||
|
||||
|
||||
this.create();
|
||||
const onDidLayoutChangeScheduler = new RunOnceScheduler(() => this._doLayout(undefined, undefined), 50);
|
||||
this._disposables.push(this.editor.onDidLayoutChange(() => onDidLayoutChangeScheduler.schedule()));
|
||||
this._disposables.push(onDidLayoutChangeScheduler);
|
||||
}
|
||||
|
||||
private _applyTheme(theme: ITheme): void {
|
||||
this._backgroundColor = theme.getColor(debugExceptionWidgetBackground);
|
||||
let frameColor = theme.getColor(debugExceptionWidgetBorder);
|
||||
this.style({
|
||||
arrowColor: frameColor,
|
||||
frameColor: frameColor
|
||||
}); // style() will trigger _applyStyles
|
||||
}
|
||||
|
||||
protected _applyStyles(): void {
|
||||
if (this.container) {
|
||||
this.container.style.backgroundColor = this._backgroundColor.toString();
|
||||
}
|
||||
super._applyStyles();
|
||||
}
|
||||
|
||||
protected _fillContainer(container: HTMLElement): void {
|
||||
this.setCssClass('exception-widget');
|
||||
// Set the font size and line height to the one from the editor configuration.
|
||||
const fontInfo = this.editor.getConfiguration().fontInfo;
|
||||
this.container.style.fontSize = `${fontInfo.fontSize}px`;
|
||||
this.container.style.lineHeight = `${fontInfo.lineHeight}px`;
|
||||
|
||||
let title = $('.title');
|
||||
title.textContent = this.exceptionInfo.id ? nls.localize('exceptionThrownWithId', 'Exception has occurred: {0}', this.exceptionInfo.id) : nls.localize('exceptionThrown', 'Exception has occurred.');
|
||||
dom.append(container, title);
|
||||
|
||||
if (this.exceptionInfo.description) {
|
||||
let description = $('.description');
|
||||
description.textContent = this.exceptionInfo.description;
|
||||
dom.append(container, description);
|
||||
}
|
||||
|
||||
if (this.exceptionInfo.details && this.exceptionInfo.details.stackTrace) {
|
||||
let stackTrace = $('.stack-trace');
|
||||
const linkDetector = this.instantiationService.createInstance(LinkDetector);
|
||||
const linkedStackTrace = linkDetector.handleLinks(this.exceptionInfo.details.stackTrace);
|
||||
typeof linkedStackTrace === 'string' ? stackTrace.textContent = linkedStackTrace : stackTrace.appendChild(linkedStackTrace);
|
||||
dom.append(container, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
protected _doLayout(heightInPixel: number, widthInPixel: number): void {
|
||||
// Reload the height with respect to the exception text content and relayout it to match the line count.
|
||||
this.container.style.height = 'initial';
|
||||
|
||||
const lineHeight = this.editor.getConfiguration().lineHeight;
|
||||
const arrowHeight = Math.round(lineHeight / 3);
|
||||
const computedLinesNumber = Math.ceil((this.container.offsetHeight + arrowHeight) / lineHeight);
|
||||
|
||||
this._relayout(computedLinesNumber);
|
||||
}
|
||||
}
|
||||
114
src/vs/workbench/parts/debug/browser/linkDetector.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import strings = require('vs/base/common/strings');
|
||||
import uri from 'vs/base/common/uri';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
|
||||
export class LinkDetector {
|
||||
private static FILE_LOCATION_PATTERNS: RegExp[] = [
|
||||
// group 0: full path with line and column
|
||||
// group 1: full path without line and column, matched by `*.*` in the end to work only on paths with extensions in the end (s.t. node:10352 would not match)
|
||||
// group 2: drive letter on windows with trailing backslash or leading slash on mac/linux
|
||||
// group 3: line number, matched by (:(\d+))
|
||||
// group 4: column number, matched by ((?::(\d+))?)
|
||||
// eg: at Context.<anonymous> (c:\Users\someone\Desktop\mocha-runner\test\test.js:26:11)
|
||||
/(?![\(])(?:file:\/\/)?((?:([a-zA-Z]+:)|[^\(\)<>\'\"\[\]:\s]+)(?:[\\/][^\(\)<>\'\"\[\]:]*)?\.[a-zA-Z]+[0-9]*):(\d+)(?::(\d+))?/g
|
||||
];
|
||||
|
||||
constructor(
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService
|
||||
) {
|
||||
// noop
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches and handles relative and absolute file links in the string provided.
|
||||
* Returns <span/> element that wraps the processed string, where matched links are replaced by <a/> and unmatched parts are surrounded by <span/> elements.
|
||||
* 'onclick' event is attached to all anchored links that opens them in the editor.
|
||||
* If no links were detected, returns the original string.
|
||||
*/
|
||||
public handleLinks(text: string): HTMLElement | string {
|
||||
let linkContainer: HTMLElement;
|
||||
|
||||
for (let pattern of LinkDetector.FILE_LOCATION_PATTERNS) {
|
||||
pattern.lastIndex = 0; // the holy grail of software development
|
||||
let lastMatchIndex = 0;
|
||||
|
||||
let match = pattern.exec(text);
|
||||
while (match !== null) {
|
||||
let resource: uri = null;
|
||||
try {
|
||||
resource = (match && !strings.startsWith(match[0], 'http'))
|
||||
&& (match[2] || strings.startsWith(match[1], '/') ? uri.file(match[1]) : this.contextService.toResource(match[1])); // TODO@Michel TODO@Isidor (https://github.com/Microsoft/vscode/issues/29190)
|
||||
} catch (e) { }
|
||||
|
||||
if (!resource) {
|
||||
match = pattern.exec(text);
|
||||
continue;
|
||||
}
|
||||
if (!linkContainer) {
|
||||
linkContainer = document.createElement('span');
|
||||
}
|
||||
|
||||
let textBeforeLink = text.substring(lastMatchIndex, match.index);
|
||||
if (textBeforeLink) {
|
||||
let span = document.createElement('span');
|
||||
span.textContent = textBeforeLink;
|
||||
linkContainer.appendChild(span);
|
||||
}
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.textContent = text.substr(match.index, match[0].length);
|
||||
link.title = isMacintosh ? nls.localize('fileLinkMac', "Click to follow (Cmd + click opens to the side)") : nls.localize('fileLink', "Click to follow (Ctrl + click opens to the side)");
|
||||
linkContainer.appendChild(link);
|
||||
const line = Number(match[3]);
|
||||
const column = match[4] ? Number(match[4]) : undefined;
|
||||
link.onclick = (e) => this.onLinkClick(new StandardMouseEvent(e), resource, line, column);
|
||||
|
||||
lastMatchIndex = pattern.lastIndex;
|
||||
const currentMatch = match;
|
||||
match = pattern.exec(text);
|
||||
|
||||
// Append last string part if no more link matches
|
||||
if (!match) {
|
||||
let textAfterLink = text.substr(currentMatch.index + currentMatch[0].length);
|
||||
if (textAfterLink) {
|
||||
let span = document.createElement('span');
|
||||
span.textContent = textAfterLink;
|
||||
linkContainer.appendChild(span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return linkContainer || text;
|
||||
}
|
||||
|
||||
private onLinkClick(event: IMouseEvent, resource: uri, line: number, column: number = 0): void {
|
||||
const selection = window.getSelection();
|
||||
if (selection.type === 'Range') {
|
||||
return; // do not navigate when user is selecting
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
this.editorService.openEditor({
|
||||
resource,
|
||||
options: {
|
||||
selection: {
|
||||
startLineNumber: line,
|
||||
startColumn: column
|
||||
}
|
||||
}
|
||||
}, event.ctrlKey || event.metaKey).done(null, errors.onUnexpectedError);
|
||||
}
|
||||
}
|
||||
1
src/vs/workbench/parts/debug/browser/media/add-focus.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><title>Layer 1</title><rect height="11" width="3" y="3" x="7" fill="#fff"/><rect height="3" width="11" y="7" x="3" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 197 B |
@@ -0,0 +1 @@
|
||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><title>Layer 1</title><rect height="11" width="3" y="3" x="7" fill="#C5C5C5"/><rect height="3" width="11" y="7" x="3" fill="#C5C5C5"/></svg>
|
||||
|
After Width: | Height: | Size: 203 B |
1
src/vs/workbench/parts/debug/browser/media/add.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><title>Layer 1</title><rect height="11" width="3" y="3" x="7" fill="#424242"/><rect height="3" width="11" y="7" x="3" fill="#424242"/></svg>
|
||||
|
After Width: | Height: | Size: 203 B |
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#CC1100;}
|
||||
</style>
|
||||
<path class="st0" d="M8,3C5.2,3,3,5.2,3,8s2.2,5,5,5s5-2.2,5-5S10.8,3,8,3z M10.8,9.9H5.2V8.7h5.7V9.9z M10.8,7.3H5.2V6.1h5.7V7.3z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 539 B |
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#E51400;}
|
||||
</style>
|
||||
<path class="st0" d="M8,3C5.2,3,3,5.2,3,8s2.2,5,5,5s5-2.2,5-5S10.8,3,8,3z M10.8,9.9H5.2V8.7h5.7V9.9z M10.8,7.3H5.2V6.1h5.7V7.3z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 539 B |
@@ -0,0 +1 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><g fill="#c10"><circle cx="8" cy="8" r="5"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 176 B |
@@ -0,0 +1 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" fill-opacity="0.8"><g fill="#5A5A5A"><circle cx="8" cy="8" r="5"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 198 B |
@@ -0,0 +1 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" fill-opacity="0.6"><g fill="#6C6C6C"><circle cx="8" cy="8" r="5"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 198 B |
@@ -0,0 +1 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" fill-opacity="0.4"><g fill="#E51400"><circle cx="8" cy="8" r="5"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 198 B |
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#CC1100;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<circle class="st0" cx="8" cy="8" r="5"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="7.3" y="10.2" class="st1" width="1.5" height="1.5"/>
|
||||
<rect x="7.3" y="4.4" class="st1" width="1.5" height="4.4"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 530 B |
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#E51400;}
|
||||
.st1{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<circle class="st0" cx="8" cy="8" r="5"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="7.3" y="10.2" class="st1" width="1.5" height="1.5"/>
|
||||
<rect x="7.3" y="4.4" class="st1" width="1.5" height="4.4"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 530 B |
@@ -0,0 +1 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><g stroke="#5A5A5A" stroke-width="3" stroke-opacity="0.8"><circle cx="8" cy="8" r="4"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 219 B |
@@ -0,0 +1 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><g stroke="#6C6C6C" stroke-width="3" stroke-opacity="0.6"><circle cx="8" cy="8" r="4"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 219 B |
@@ -0,0 +1 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><g fill="#E51400"><circle cx="8" cy="8" r="5"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 179 B |
@@ -0,0 +1,41 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.breakpoint-widget {
|
||||
height: 30px !important;
|
||||
display: flex;
|
||||
border-color: #007ACC;
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .breakpoint-select-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .inputBoxContainer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .monaco-inputbox {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.monaco-editor .breakpoint-widget .input {
|
||||
font-family: Monaco, Menlo, Consolas, "Droid Sans Mono", "Inconsolata", "Courier New", monospace, "Droid Sans Fallback";
|
||||
line-height: 22px;
|
||||
background-color: transparent;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.monaco-workbench.mac .monaco-editor .breakpoint-widget .input {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.monaco-workbench.windows .monaco-editor .breakpoint-widget .input,
|
||||
.monaco-workbench.linux .monaco-editor .breakpoint-widget .input {
|
||||
font-size: 13px;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><path fill="#1E1E1E" d="M16 5.5c0-3-2.5-5.5-5.5-5.5C7.6 0 5.3 2.2 5 5c-2.8.2-5 2.6-5 5.5 0 3 2.5 5.5 5.5 5.5 2.9 0 5.2-2.2 5.5-5 2.8-.3 5-2.6 5-5.5z"/><g fill="#C5C5C5"><path d="M10.5 1C8.2 1 6.3 2.8 6 5c.3 0 .7.1 1 .2C7.2 3.4 8.7 2 10.5 2 12.4 2 14 3.6 14 5.5c0 1.8-1.4 3.3-3.2 3.5.1.3.2.6.2 1 2.3-.2 4-2.1 4-4.5C15 3 13 1 10.5 1z"/><circle cx="5.5" cy="10.5" r="4.5"/></g></svg>
|
||||
|
After Width: | Height: | Size: 497 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><path fill="#F6F6F6" d="M16 5.5c0-3-2.5-5.5-5.5-5.5C7.6 0 5.3 2.2 5 5c-2.8.2-5 2.6-5 5.5 0 3 2.5 5.5 5.5 5.5 2.9 0 5.2-2.2 5.5-5 2.8-.3 5-2.6 5-5.5z"/><g fill="#424242"><path d="M10.5 1C8.2 1 6.3 2.8 6 5c.3 0 .7.1 1 .2C7.2 3.4 8.7 2 10.5 2 12.4 2 14 3.6 14 5.5c0 1.8-1.4 3.3-3.2 3.5.1.3.2.6.2 1 2.3-.2 4-2.1 4-4.5C15 3 13 1 10.5 1z"/><circle cx="5.5" cy="10.5" r="4.5"/></g></svg>
|
||||
|
After Width: | Height: | Size: 497 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#1E1E1E" d="M4.222 0h-2.222v.479c-.526.648-.557 1.57-.043 2.269l.043.059v3.203l-.4.296-.053.053c-.353.352-.547.822-.547 1.321s.194.967.549 1.32c.134.134.288.236.451.322v6.678h14v-16h-11.778z"/><path fill="#E8E8E8" d="M10.798 7l-1.83-2h6.032v2h-4.202zm-2.292-6h-3.207l1.337 1.52 1.87-1.52zm-5.506 8.531v1.469h12v-2h-10.813l-.024.021c-.3.299-.716.479-1.163.51zm0 5.469h12v-2h-12v2zm3.323-8h.631l-.347-.266-.284.266zm8.677-4v-2h-3.289l-1.743 2h5.032z"/><path fill="#F48771" d="M7.246 4.6l2.856-3.277-.405-.002-3.176 2.581-2.607-2.962c-.336-.221-.786-.2-1.082.096-.308.306-.319.779-.069 1.12l2.83 2.444-3.339 2.466c-.339.338-.339.887 0 1.225.339.337.888.337 1.226 0l3.063-2.867 3.33 2.555h.466l-3.093-3.379z"/></svg>
|
||||
|
After Width: | Height: | Size: 787 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fff" d="M4.222 0h-2.222v.479c-.526.648-.557 1.57-.043 2.269l.043.059v3.203l-.4.296-.053.053c-.353.352-.547.822-.547 1.321s.194.967.549 1.32c.134.134.288.236.451.322v6.678h14v-16h-11.778z"/><path fill="#424242" d="M10.798 7l-1.83-2h6.032v2h-4.202zm-2.292-6h-3.207l1.337 1.52 1.87-1.52zm-5.506 8.531v1.469h12v-2h-10.813l-.024.021c-.3.299-.716.479-1.163.51zm0 5.469h12v-2h-12v2zm3.323-8h.631l-.347-.266-.284.266zm8.677-4v-2h-3.289l-1.743 2h5.032z"/><path fill="#A1260D" d="M7.246 4.6l2.856-3.277-.405-.002-3.176 2.581-2.607-2.962c-.336-.221-.786-.2-1.082.096-.308.306-.319.779-.069 1.12l2.83 2.444-3.339 2.466c-.339.338-.339.887 0 1.225.339.337.888.337 1.226 0l3.063-2.867 3.33 2.555h.466l-3.093-3.379z"/></svg>
|
||||
|
After Width: | Height: | Size: 784 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#C5C5C5"><path d="M12.714 9.603c-.07.207-.15.407-.246.601l1.017 2.139c-.335.424-.718.807-1.142 1.143l-2.14-1.018c-.193.097-.394.176-.601.247l-.795 2.235c-.265.03-.534.05-.807.05-.272 0-.541-.02-.806-.05l-.795-2.235c-.207-.071-.408-.15-.602-.247l-2.14 1.017c-.424-.336-.807-.719-1.143-1.143l1.017-2.139c-.094-.193-.175-.393-.245-.6l-2.236-.796c-.03-.265-.05-.534-.05-.807s.02-.542.05-.807l2.236-.795c.07-.207.15-.407.246-.601l-1.016-2.139c.336-.423.719-.807 1.143-1.142l2.14 1.017c.193-.096.394-.176.602-.247l.793-2.236c.265-.03.534-.05.806-.05.273 0 .542.02.808.05l.795 2.236c.207.07.407.15.601.246l2.14-1.017c.424.335.807.719 1.142 1.142l-1.017 2.139c.096.194.176.394.246.601l2.236.795c.029.266.049.535.049.808s-.02.542-.05.807l-2.236.796zm-4.714-4.603c-1.657 0-3 1.343-3 3s1.343 3 3 3 3-1.343 3-3-1.343-3-3-3z"/><circle cx="8" cy="8" r="1.5"/></g></svg>
|
||||
|
After Width: | Height: | Size: 927 B |
1
src/vs/workbench/parts/debug/browser/media/configure.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#424242"><path d="M12.714 9.603c-.07.207-.15.407-.246.601l1.017 2.139c-.335.424-.718.807-1.142 1.143l-2.14-1.018c-.193.097-.394.176-.601.247l-.795 2.235c-.265.03-.534.05-.807.05-.272 0-.541-.02-.806-.05l-.795-2.235c-.207-.071-.408-.15-.602-.247l-2.14 1.017c-.424-.336-.807-.719-1.143-1.143l1.017-2.139c-.094-.193-.175-.393-.245-.6l-2.236-.796c-.03-.265-.05-.534-.05-.807s.02-.542.05-.807l2.236-.795c.07-.207.15-.407.246-.601l-1.016-2.139c.336-.423.719-.807 1.143-1.142l2.14 1.017c.193-.096.394-.176.602-.247l.793-2.236c.265-.03.534-.05.806-.05.273 0 .542.02.808.05l.795 2.236c.207.07.407.15.601.246l2.14-1.017c.424.335.807.719 1.142 1.142l-1.017 2.139c.096.194.176.394.246.601l2.236.795c.029.266.049.535.049.808s-.02.542-.05.807l-2.236.796zm-4.714-4.603c-1.657 0-3 1.343-3 3s1.343 3 3 3 3-1.343 3-3-1.343-3-3-3z"/><circle cx="8" cy="8" r="1.5"/></g></svg>
|
||||
|
After Width: | Height: | Size: 927 B |
@@ -0,0 +1,3 @@
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
||||
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
|
||||
]><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="-3 0 16 16" enable-background="new -3 0 16 16"><path fill="#89D185" d="M1 2v12l8-6-8-6z"/></svg>
|
||||
|
After Width: | Height: | Size: 323 B |
3
src/vs/workbench/parts/debug/browser/media/continue.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
||||
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
|
||||
]><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="-3 0 16 16" enable-background="new -3 0 16 16"><path fill="#388A34" d="M1 2v12l8-6-8-6z"/></svg>
|
||||
|
After Width: | Height: | Size: 323 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-red{fill:#e51400}.icon-vs-yellow{fill:#fc0}.icon-vs-bg{fill:#424242}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-bg" d="M14.414 8l-5 6H3V2h6.414l5 6z" id="outline" style="display: none;"/><path class="icon-vs-yellow" d="M13 8l-4 5H4V3h5l4 5z" id="iconBg"/><g id="iconFg"><path class="icon-vs-red" d="M10.5 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 530 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-yellow{fill:#fc0}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-bg" d="M14.414 8l-5 6H3V2h6.414l5 6z" id="outline" style="display: none;"/><g id="iconBg"><path class="icon-vs-yellow" d="M13 8l-4 5H4V3h5l4 5z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 424 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M17 19.488v4.248c0 .462.09 1.264-.373 1.264H15v-1h1v-3.19l-.173-.18c-1.453 1.205-3.528 1.248-4.67.108C10 19.578 10.118 18 11.376 16H8v1H7v-1.627C7 14.91 7.802 15 8.264 15h4.105L17 19.488zM14 9h-1V8h1.955c.46 0 1.045.22 1.045.682v3.345l.736.875c.18-.973.89-1.71 1.914-1.71.143 0 .35.014.35.04V9h1v2.618c0 .117.265.382.382.382H23v1h-2.233c.027 0 .042.154.042.298 0 1.025-.74 1.753-1.712 1.932l.875.77H23.318c.462 0 .682.583.682 1.045V19h-1v-1h-2.52L14 11.698V9zM16 4C9.373 4 4 9.373 4 16s5.373 12 12 12 12-5.373 12-12S22.627 4 16 4zm10 12c0 2.397-.85 4.6-2.262 6.324L9.676 8.262C11.4 6.85 13.602 6 16 6c5.514 0 10 4.486 10 10zM6 16c0-2.398.85-4.6 2.262-6.324L22.324 23.74C20.6 25.15 18.397 26 16 26c-5.514 0-10-4.486-10-10z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 834 B |
@@ -0,0 +1,263 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* Activity Bar */
|
||||
.monaco-workbench > .activitybar .monaco-action-bar .action-label.debug {
|
||||
-webkit-mask: url('debug-dark.svg') no-repeat 50% 50%;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame-line,
|
||||
.monaco-editor .debug-top-stack-frame-exception-line {
|
||||
background: rgba(255, 255, 102, 0.45);
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame-range {
|
||||
background: #ffeca0;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame-column::before {
|
||||
background: url('current-arrow.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-focused-stack-frame-line {
|
||||
background: rgba(206, 231, 206, 0.45);
|
||||
}
|
||||
|
||||
.monaco-editor .debug-focused-stack-frame-range {
|
||||
background: rgba(206, 231, 206, 1);
|
||||
}
|
||||
|
||||
.monaco-editor .debug-breakpoint-hint-glyph {
|
||||
background: url('breakpoint-hint.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-breakpoint-disabled-glyph,
|
||||
.monaco-editor .debug-breakpoint-column.debug-breakpoint-disabled-glyph-column::before {
|
||||
background: url('breakpoint-disabled.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-breakpoint-unverified-glyph,
|
||||
.monaco-editor .debug-breakpoint-column.debug-breakpoint-unverified-glyph-column::before {
|
||||
background: url('breakpoint-unverified.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame-glyph {
|
||||
background: url('current-arrow.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-focused-stack-frame-glyph {
|
||||
background: url('stackframe-arrow.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-breakpoint-glyph,
|
||||
.monaco-editor .debug-breakpoint-column.debug-breakpoint-glyph-column::before {
|
||||
background: url('breakpoint.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-breakpoint-column::before,
|
||||
.monaco-editor .debug-top-stack-frame-column::before {
|
||||
content: " ";
|
||||
width: 0.9em;
|
||||
height: 0.8em;
|
||||
display: inline-block;
|
||||
margin-right: 2px;
|
||||
margin-left: 2px;
|
||||
background-size: 110% !important;
|
||||
background-position: initial !important;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-breakpoint-conditional-glyph,
|
||||
.monaco-editor .debug-breakpoint-column.debug-breakpoint-conditional-glyph-column::before {
|
||||
background: url('breakpoint-conditional.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-breakpoint-unsupported-glyph,
|
||||
.monaco-editor .debug-breakpoint-column.debug-breakpoint-unsupported-glyph-column::before {
|
||||
background: url('breakpoint-unsupported.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame-glyph.debug-breakpoint-glyph,
|
||||
.monaco-editor .debug-top-stack-frame-glyph.debug-breakpoint-conditional-glyph,
|
||||
.monaco-editor .debug-breakpoint-column.debug-breakpoint-glyph-column.debug-top-stack-frame-column::before,
|
||||
.monaco-editor.vs-dark .debug-top-stack-frame-glyph.debug-breakpoint-glyph,
|
||||
.monaco-editor.vs-dark .debug-top-stack-frame-glyph.debug-breakpoint-conditional-glyph,
|
||||
.monaco-editor.vs-dark .debug-breakpoint-column.debug-breakpoint-glyph-column.debug-top-stack-frame-column::before {
|
||||
background: url('current-and-breakpoint.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-focused-stack-frame-glyph.debug-breakpoint-glyph,
|
||||
.monaco-editor .debug-focused-stack-frame-glyph.debug-breakpoint-conditional-glyph {
|
||||
background: url('stackframe-and-breakpoint.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
/* Error editor */
|
||||
.debug-error-editor:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.debug-error-editor {
|
||||
padding: 5px 0 0 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Expressions */
|
||||
|
||||
.monaco-workbench .monaco-tree-row .expression {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-family: Monaco, Menlo, Consolas, "Droid Sans Mono", "Inconsolata", "Courier New", monospace, "Droid Sans Fallback";
|
||||
}
|
||||
|
||||
.monaco-workbench.mac .monaco-tree-row .expression {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.monaco-workbench.windows .monaco-tree-row .expression,
|
||||
.monaco-workbench.linux .monaco-tree-row .expression {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-tree-row .expression .value {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-tree-row:not(.selected) .expression .name {
|
||||
color: #9B46B0;
|
||||
}
|
||||
|
||||
.monaco-workbench > .monaco-tree-row:not(.selected) .expression .value {
|
||||
color: rgba(108, 108, 108, 0.8);
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-tree-row .expression .unavailable {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-tree-row:not(.selected) .expression .error {
|
||||
color: #E51400;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-tree-row:not(.selected) .expression .value.number {
|
||||
color: #09885A;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-tree-row:not(.selected) .expression .value.boolean {
|
||||
color: #0000FF;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-tree-row:not(.selected) .expression .value.string {
|
||||
color: #A31515;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench > .monaco-tree-row:not(.selected) .expression .value {
|
||||
color: rgba(204, 204, 204, 0.6);
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .monaco-tree-row:not(.selected) .expression .error {
|
||||
color: #F48771;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .monaco-tree-row:not(.selected) .expression .value.number {
|
||||
color: #B5CEA8;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .monaco-tree-row:not(.selected) .expression .value.number {
|
||||
color: #89d185;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .monaco-tree-row:not(.selected) .expression .value.boolean {
|
||||
color: #75bdfe;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .monaco-tree-row:not(.selected) .expression .value.string {
|
||||
color: #f48771;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .monaco-tree-row:not(.selected) .expression .value.boolean {
|
||||
color: #4E94CE;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .monaco-tree-row:not(.selected) .expression .value.string {
|
||||
color: #CE9178;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .monaco-tree-row:not(.selected) .expression .error {
|
||||
color: #F48771;
|
||||
}
|
||||
|
||||
/* Dark theme */
|
||||
|
||||
.vs-dark .monaco-workbench .monaco-tree-row:not(.selected) .expression .name {
|
||||
color: #C586C0;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-focused-stack-frame-line {
|
||||
background: rgba(122, 189, 122, 0.3);
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-focused-stack-frame-range {
|
||||
background: rgba(122, 189, 122, 0.5);
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-top-stack-frame-line,
|
||||
.monaco-editor.vs-dark .debug-top-stack-frame-exception-line {
|
||||
background-color: rgba(255, 255, 0, 0.2)
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-top-stack-frame-range {
|
||||
background-color: rgba(255, 255, 0, 0.3)
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-breakpoint-glyph,
|
||||
.monaco-editor.vs-dark .debug-breakpoint-column.debug-breakpoint-glyph-column::before {
|
||||
background: url('breakpoint-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-breakpoint-conditional-glyph,
|
||||
.monaco-editor.vs-dark .debug-breakpoint-column.debug-breakpoint-conditional-glyph-column::before {
|
||||
background: url('breakpoint-conditional-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-breakpoint-unsupported-glyph,
|
||||
.monaco-editor.vs-dark .debug-breakpoint-column.debug-breakpoint-unsupported-glyph-column::before {
|
||||
background: url('breakpoint-unsupported-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-breakpoint-disabled-glyph,
|
||||
.monaco-editor.vs-dark .debug-breakpoint-column.debug-breakpoint-disabled-glyph-column::before {
|
||||
background: url('breakpoint-disabled-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-breakpoint-unverified-glyph,
|
||||
.monaco-editor.vs-dark .debug-breakpoint-column.debug-breakpoint-unverified-glyph-column::before {
|
||||
background: url('breakpoint-unverified-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-focused-stack-frame-glyph {
|
||||
background: url('stackframe-arrow-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-focused-stack-frame-glyph.debug-breakpoint-glyph,
|
||||
.monaco-editor.vs-dark .debug-focused-stack-frame-glyph.debug-breakpoint-conditional-glyph {
|
||||
background: url('stackframe-and-breakpoint-dark.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
/* High Contrast Theming */
|
||||
|
||||
.monaco-editor.hc-black .debug-focused-stack-frame-line {
|
||||
background: rgba(206, 231, 206, 1);
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .monaco-tree-row:not(.selected) .expression .name {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.hc-black .monaco-editor .debug-top-stack-frame-line {
|
||||
background: rgba(255, 246, 0, 1);
|
||||
}
|
||||
|
||||
.hc-black .monaco-editor .debug-remove-token-colors {
|
||||
color:black;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* Debug actions widget */
|
||||
|
||||
.monaco-workbench .debug-actions-widget {
|
||||
position: absolute;
|
||||
z-index: 200;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
padding-left: 7px;
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-actions-widget .monaco-action-bar .action-item.select-container {
|
||||
margin-right: 7px;
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-actions-widget .monaco-action-bar .action-item .select-box {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-actions-widget .drag-area {
|
||||
cursor: -webkit-grab;
|
||||
height: 32px;
|
||||
width: 10px;
|
||||
background: url('drag.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-actions-widget .drag-area.dragged {
|
||||
cursor: -webkit-grabbing;
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-actions-widget .monaco-action-bar .action-item > .action-label {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-right: 0;
|
||||
background-size: 16px;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
/* Debug actionbar actions */
|
||||
|
||||
.monaco-workbench .debug-actions-widget .debug-action.step-over,
|
||||
.monaco-workbench .debug-actions-widget .debug-action.step-back {
|
||||
background-image: url('step-over.svg');
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-actions-widget .debug-action.step-into {
|
||||
background-image: url('step-into.svg');
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-actions-widget .debug-action.step-out {
|
||||
background-image: url('step-out.svg');
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-actions-widget .debug-action.step-back,
|
||||
.monaco-workbench .debug-actions-widget .debug-action.reverse-continue {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-actions-widget .debug-action.continue,
|
||||
.monaco-workbench .debug-actions-widget .debug-action.reverse-continue {
|
||||
background-image: url('continue.svg');
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-actions-widget .debug-action.restart {
|
||||
background-image: url('restart.svg');
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-actions-widget .debug-action.pause {
|
||||
background-image: url('pause.svg');
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-actions-widget .debug-action.stop {
|
||||
background-image: url('stop.svg');
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-actions-widget .debug-action.disconnect {
|
||||
background-image: url('disconnect.svg');
|
||||
}
|
||||
|
||||
/* Dark and hc theme actions */
|
||||
|
||||
.vs-dark .monaco-workbench .debug-actions-widget .debug-action.step-over,
|
||||
.vs-dark .monaco-workbench .debug-actions-widget .debug-action.step-back,
|
||||
.hc-black .monaco-workbench .debug-actions-widget .debug-action.step-over,
|
||||
.hc-black .monaco-workbench .debug-actions-widget .debug-action.step-back {
|
||||
background-image: url('step-over-inverse.svg');
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-actions-widget .debug-action.step-into,
|
||||
.hc-black .monaco-workbench .debug-actions-widget .debug-action.step-into {
|
||||
background-image: url('step-into-inverse.svg');
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-actions-widget .debug-action.step-out,
|
||||
.hc-black .monaco-workbench .debug-actions-widget .debug-action.step-out {
|
||||
background-image: url('step-out-inverse.svg');
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-actions-widget .debug-action.continue,
|
||||
.vs-dark .monaco-workbench .debug-actions-widget .debug-action.reverse-continue,
|
||||
.hc-black .monaco-workbench .debug-actions-widget .debug-action.continue,
|
||||
.hc-black .monaco-workbench .debug-actions-widget .debug-action.reverse-continue {
|
||||
background-image: url('continue-inverse.svg');
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-actions-widget .debug-action.restart,
|
||||
.hc-black .monaco-workbench .debug-actions-widget .debug-action.restart {
|
||||
background-image: url('restart-inverse.svg');
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-actions-widget .debug-action.pause,
|
||||
.hc-black .monaco-workbench .debug-actions-widget .debug-action.pause {
|
||||
background-image: url('pause-inverse.svg');
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-actions-widget .debug-action.stop,
|
||||
.hc-black .monaco-workbench .debug-actions-widget .debug-action.stop {
|
||||
background-image: url('stop-inverse.svg');
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-actions-widget .debug-action.disconnect,
|
||||
.hc-black .monaco-workbench .debug-actions-widget .debug-action.disconnect {
|
||||
background-image: url('disconnect-inverse.svg');
|
||||
}
|
||||
117
src/vs/workbench/parts/debug/browser/media/debugHover.css
Normal file
@@ -0,0 +1,117 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .debug-hover-widget {
|
||||
position: absolute;
|
||||
margin-top: -1px;
|
||||
cursor: default;
|
||||
z-index: 50;
|
||||
animation-duration: 0.15s;
|
||||
animation-name: fadeIn;
|
||||
-webkit-user-select: text;
|
||||
word-break: break-all;
|
||||
padding: 4px 5px;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .complex-value {
|
||||
width: 324px;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .complex-value .title {
|
||||
padding-left: 15px;
|
||||
padding-right: 2px;
|
||||
font-size: 11px;
|
||||
word-break: normal;
|
||||
text-overflow: ellipsis;
|
||||
height: 18px;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid rgba(128, 128, 128, 0.35);
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .debug-hover-tree {
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .debug-hover-tree .monaco-tree .monaco-tree-row > .content {
|
||||
-webkit-user-select: text;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
/* Disable tree highlight in debug hover tree. */
|
||||
.monaco-editor .debug-hover-widget .debug-hover-tree .monaco-tree .monaco-tree-rows > .monaco-tree-row:hover:not(.highlighted):not(.selected):not(.focused) {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .debug-hover-tree .monaco-tree .monaco-tree-rows > .monaco-tree-row {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .debug-hover-tree .monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.monaco-editor .debugHoverHighlight {
|
||||
background-color: rgba(173, 214, 255, 0.15);
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .value {
|
||||
white-space: pre-wrap;
|
||||
color: rgba(108, 108, 108, 0.8);
|
||||
overflow: auto;
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .error {
|
||||
color: #E51400;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .value.number {
|
||||
color: #09885A;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .value.boolean {
|
||||
color: #0000FF;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-hover-widget .value.string {
|
||||
color: #A31515;
|
||||
}
|
||||
|
||||
/* Dark theme */
|
||||
|
||||
.monaco-editor.vs-dark .debug-hover-widget .value,
|
||||
.monaco-editor.hc-black .debug-hover-widget .value {
|
||||
color: rgba(204, 204, 204, 0.6);
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-hover-widget .error,
|
||||
.monaco-editor.hc-black .debug-hover-widget .error {
|
||||
color: #F48771;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-hover-widget .value.number,
|
||||
.monaco-editor.hc-black .debug-hover-widget .value.number {
|
||||
color: #B5CEA8;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-hover-widget .value.boolean,
|
||||
.monaco-editor.hc-black .debug-hover-widget .value.boolean {
|
||||
color: #4E94CE;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debug-hover-widget .value.string,
|
||||
.monaco-editor.hc-black .debug-hover-widget .value.string {
|
||||
color: #CE9178;
|
||||
}
|
||||
|
||||
.monaco-editor.vs-dark .debugHoverHighlight,
|
||||
.monaco-editor.hc-theme .debugHoverHighlight {
|
||||
background-color: rgba(38, 79, 120, 0.25);
|
||||
}
|
||||
396
src/vs/workbench/parts/debug/browser/media/debugViewlet.css
Normal file
@@ -0,0 +1,396 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* Debug viewlet */
|
||||
|
||||
.debug-viewlet {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Actionbar actions */
|
||||
|
||||
.monaco-workbench .debug-action.configure {
|
||||
background: url('configure.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-action.start {
|
||||
background: url('continue.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-action.toggle-repl {
|
||||
background: url('repl.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-action.notification:before {
|
||||
content: '';
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background-color: #CC6633;
|
||||
position: absolute;
|
||||
top: 11px;
|
||||
right: 5px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-action.start,
|
||||
.hc-black .monaco-workbench .debug-action.start {
|
||||
background: url('continue-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-action.configure,
|
||||
.hc-black .monaco-workbench .debug-action.configure {
|
||||
background: url('configure-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-action.toggle-repl,
|
||||
.hc-black .monaco-workbench .debug-action.toggle-repl {
|
||||
background: url('repl-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part > .title > .title-actions .start-debug-action-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 11px;
|
||||
margin-right: 0.3em;
|
||||
height: 20px;
|
||||
flex-shrink: 1;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.monaco-workbench.mac > .part > .title > .title-actions .start-debug-action-item {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part > .title > .title-actions .start-debug-action-item .icon {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
background: url('continue.svg') center center no-repeat;
|
||||
flex-shrink: 0;
|
||||
transition: transform 50ms ease;
|
||||
-webkit-transition: -webkit-transform 50ms ease;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench > .part > .title > .title-actions .start-debug-action-item .icon,
|
||||
.hc-black .monaco-workbench > .part > .title > .title-actions .start-debug-action-item .icon {
|
||||
background: url('continue-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-action-bar .start-debug-action-item .configuration .select-box {
|
||||
border: none;
|
||||
margin-top: 0px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.monaco-workbench .monaco-action-bar .start-debug-action-item .configuration.disabled .select-box {
|
||||
opacity: 0.7;
|
||||
font-style: italic;
|
||||
cursor: initial;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part > .title > .title-actions .start-debug-action-item .icon.active {
|
||||
-webkit-transform: scale(1.272019649, 1.272019649);
|
||||
transform: scale(1.272019649, 1.272019649);
|
||||
}
|
||||
|
||||
/* Debug viewlet trees */
|
||||
|
||||
.debug-viewlet .monaco-tree .monaco-tree-row > .content {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.debug-viewlet .line-number {
|
||||
background: rgba(136, 136, 136, 0.3);
|
||||
border-radius: 2px;
|
||||
font-size: 0.9em;
|
||||
padding: 0 3px;
|
||||
margin-left: 0.8em;
|
||||
}
|
||||
|
||||
.debug-viewlet .monaco-tree .monaco-tree-row.selected .line-number,
|
||||
.debug-viewlet .monaco-tree .monaco-tree-row.selected .thread > .state > .label,
|
||||
.debug-viewlet .monaco-tree .monaco-tree-row.selected .process > .state > .label {
|
||||
background-color: #ffffff;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.debug-viewlet .monaco-tree .monaco-tree-row .content .monaco-action-bar {
|
||||
visibility: hidden;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.debug-viewlet .monaco-tree .monaco-tree-row .content .monaco-action-bar .action-label {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.debug-viewlet .monaco-tree .monaco-tree-row:hover .content .monaco-action-bar,
|
||||
.debug-viewlet .monaco-tree.focused .monaco-tree-row.focused .content .monaco-action-bar {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.debug-viewlet .disabled {
|
||||
opacity: 0.35;
|
||||
}
|
||||
|
||||
/* Call stack */
|
||||
|
||||
.debug-viewlet .debug-call-stack-title {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack-title > .pause-message {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
margin: 0px 10px;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack-title > .pause-message > .label {
|
||||
border-radius: 3px;
|
||||
padding: 1px 2px;
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack-title > .pause-message > .label.exception {
|
||||
background-color: #A31515;
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-call-stack-title > .pause-message > .label.exception {
|
||||
background-color: #6C2022;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.hc-black .debug-viewlet .debug-call-stack-title > .pause-message > .label.exception {
|
||||
background-color: #6C2022;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .thread,
|
||||
.debug-viewlet .debug-call-stack .process {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .thread > .state,
|
||||
.debug-viewlet .debug-call-stack .process > .state {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding: 0 10px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .thread > .state > .label,
|
||||
.debug-viewlet .debug-call-stack .process > .state > .label {
|
||||
background: rgba(136, 136, 136, 0.3);
|
||||
border-radius: 2px;
|
||||
font-size: 0.8em;
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .stack-frame {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-right: 0.8em;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .stack-frame.label {
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .stack-frame.subtle {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .stack-frame.label > .file {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .stack-frame > .file {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .stack-frame > .file > .line-number.unavailable {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack > .monaco-tree-row:not(.selected) .stack-frame > .file {
|
||||
color: rgba(108, 108, 108, 0.8);
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-call-stack > .monaco-tree-row:not(.selected) .stack-frame > .file {
|
||||
color: rgba(204, 204, 204, 0.6);
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .stack-frame > .file:not(:first-child) {
|
||||
margin-left: 0.8em;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .load-more {
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.monaco-workbench .debug-viewlet .monaco-tree-row .expression {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-call-stack .error {
|
||||
font-style: italic;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Variables & Expression view */
|
||||
|
||||
.debug-viewlet .scope {
|
||||
font-weight: bold;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* Animation of changed values in Debug viewlet */
|
||||
@keyframes debugViewletValueChanged {
|
||||
0% { background-color: rgba(86, 156, 214, 0) }
|
||||
5% { background-color: rgba(86, 156, 214, .75) }
|
||||
100% { background-color: rgba(86, 156, 214, .3) }
|
||||
}
|
||||
|
||||
@keyframes debugViewletValueChangedDark {
|
||||
0% { background-color: rgba(86, 156, 214, 0) }
|
||||
5% { background-color: rgba(86, 156, 214, .5) }
|
||||
100% { background-color: rgba(86, 156, 214, .2) }
|
||||
}
|
||||
|
||||
.debug-viewlet .monaco-tree-row .expression .value.changed {
|
||||
padding: 2px;
|
||||
margin: 4px;
|
||||
border-radius: 4px;
|
||||
background-color: rgba(86, 156, 214, .5);
|
||||
animation-name: debugViewletValueChanged;
|
||||
animation-duration: .75s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
.debug-viewlet .monaco-inputbox {
|
||||
width: 100%;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.debug-viewlet .inputBoxContainer {
|
||||
box-sizing: border-box;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-watch .monaco-inputbox {
|
||||
font-family: Monaco, Menlo, Consolas, "Droid Sans Mono", "Inconsolata", "Courier New", monospace, "Droid Sans Fallback";
|
||||
}
|
||||
|
||||
.debug-viewlet .monaco-inputbox > .wrapper {
|
||||
height: 19px;
|
||||
}
|
||||
|
||||
.debug-viewlet .monaco-inputbox > .wrapper > .input {
|
||||
padding: 0px;
|
||||
color: initial;
|
||||
}
|
||||
|
||||
.debug-viewlet .watch-expression {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.debug-viewlet .watch-expression .expression {
|
||||
flex : 1;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-action.add-watch-expression,
|
||||
.debug-viewlet .debug-action.add-function-breakpoint {
|
||||
background: url('add.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .focused .monaco-tree-row.selected:not(.highlighted) > .content.actions .debug-action.add-watch-expression {
|
||||
background: url("add-focus.svg") center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-action.add-watch-expression,
|
||||
.vs-dark .debug-viewlet .debug-action.add-function-breakpoint,
|
||||
.hc-black .debug-viewlet .debug-action.add-watch-expression {
|
||||
background: url('add-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .monaco-tree-row .expression .value.changed {
|
||||
animation-name: debugViewletValueChanged;
|
||||
}
|
||||
|
||||
/* Breakpoints */
|
||||
|
||||
.debug-viewlet .debug-breakpoints .breakpoint {
|
||||
display: flex;
|
||||
padding-right: 0.8em;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-breakpoints .breakpoint input {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-breakpoints .breakpoint > .file-path {
|
||||
opacity: 0.7;
|
||||
font-size: 0.9em;
|
||||
margin-left: 0.8em;
|
||||
flex: 1;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
.debug-viewlet .debug-action.remove {
|
||||
background: url('remove.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-action.remove-all {
|
||||
background: url('remove-all.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .debug-action.breakpoints-activate {
|
||||
background: url('breakpoints-activate.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-viewlet .focused .monaco-tree-row.selected:not(.highlighted) > .content.actions .debug-action.remove,
|
||||
.vs-dark .debug-viewlet .focused .monaco-tree-row.selected:not(.highlighted) > .content.actions .debug-action.remove {
|
||||
background: url("remove-focus.svg") center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-action.remove,
|
||||
.hc-black .debug-viewlet .debug-action.remove {
|
||||
background: url('remove-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-action.remove-all,
|
||||
.hc-black .debug-viewlet .debug-action.remove-all {
|
||||
background: url('remove-all-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .debug-viewlet .debug-action.breakpoints-activate,
|
||||
.hc-black .debug-viewlet .debug-action.breakpoints-activate {
|
||||
background: url('breakpoints-activate-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
/* No workspace view */
|
||||
|
||||
.debug-viewlet > .noworkspace-view {
|
||||
padding: 0 20px 0 20px;
|
||||
}
|
||||
|
||||
.debug-viewlet > .noworkspace-view > p {
|
||||
line-height: 1.5em;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><defs><style>.cls-1{fill:#f48771;}</style></defs><title>Plan de travail 1</title><path class="cls-1" d="M61.8,64H2.2A2.2,2.2,0,0,1,0,61.8V2.2A2.2,2.2,0,0,1,2.2,0H61.8A2.2,2.2,0,0,1,64,2.2V61.8A2.2,2.2,0,0,1,61.8,64ZM46,21.1H42V9.1h-5v12H26.9V9.1H22v12H18v4.1h1V42.4l9,7.3v7.7h8V49.7l9-7.3V25.2h1Z"/></svg>
|
||||
|
After Width: | Height: | Size: 423 B |
@@ -0,0 +1 @@
|
||||
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><defs><style>.cls-1{fill:#ac4747;}</style></defs><title>Plan de travail 1</title><path class="cls-1" d="M61.8,64H2.2A2.2,2.2,0,0,1,0,61.8V2.2A2.2,2.2,0,0,1,2.2,0H61.8A2.2,2.2,0,0,1,64,2.2V61.8A2.2,2.2,0,0,1,61.8,64ZM46,21.1H42V9.1h-5v12H26.9V9.1H22v12H18v4.1h1V42.4l9,7.3v7.7h8V49.7l9-7.3V25.2h1Z"/></svg>
|
||||
|
After Width: | Height: | Size: 423 B |
8
src/vs/workbench/parts/debug/browser/media/drag.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="16px" height="32px" fill="#999">
|
||||
<circle cx="5px" cy="11px" r="1.2"/>
|
||||
<circle cx="10px" cy="11px" r="1.2"/>
|
||||
<circle cx="5px" cy="16px" r="1.2"/>
|
||||
<circle cx="10px" cy="16px" r="1.2"/>
|
||||
<circle cx="5px" cy="21px" r="1.2"/>
|
||||
<circle cx="10px" cy="21px" r="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 337 B |
@@ -0,0 +1,48 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .zone-widget.exception-widget-container {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.exception-widget {
|
||||
padding: 6px 10px;
|
||||
white-space: pre-wrap;
|
||||
-webkit-user-select: text;
|
||||
-ms-user-select: text;
|
||||
-khtml-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-o-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.exception-widget .title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.exception-widget .description,
|
||||
.monaco-editor .zone-widget .zone-widget-container.exception-widget .stack-trace {
|
||||
font-family: Monaco, Menlo, Consolas, "Droid Sans Mono", "Inconsolata", "Courier New", monospace, "Droid Sans Fallback";
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.exception-widget .stack-trace {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.exception-widget a {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* High Contrast Theming */
|
||||
|
||||
.monaco-workbench.mac .zone-widget .zone-widget-container.exception-widget {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.monaco-workbench.windows .zone-widget .zone-widget-container.exception-widget,
|
||||
.monaco-workbench.linux .zone-widget .zone-widget-container.exception-widget {
|
||||
font-size: 13px;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><path d="M13 13H3V2h10v11z" fill="#1E1E1E"/><path d="M7 12H4V3h3v9zm5-9H9v9h3V3z" fill="#75BEFF"/></svg>
|
||||
|
After Width: | Height: | Size: 221 B |
1
src/vs/workbench/parts/debug/browser/media/pause.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><path d="M13 13H3V2h10v11z" fill="#F6F6F6"/><path d="M7 12H4V3h3v9zm5-9H9v9h3V3z" fill="#00539C"/></svg>
|
||||
|
After Width: | Height: | Size: 221 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><path fill="#1E1E1E" d="M16 12h-2v2h-2v2H0V5h2V3h2V1h12v11z"/><g fill="#C5C5C5"><path d="M3 5h9v8h1V4H3zM5 2v1h9v8h1V2zM1 6v9h10V6H1zm8 7H7.5L6 11.5 4.5 13H3l2.3-2.3L3 8.5h1.5L6 10l1.5-1.5H9l-2.3 2.3L9 13z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 335 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><path fill="#F6F6F6" d="M16 12h-2v2h-2v2H0V5h2V3h2V1h12v11z"/><g fill="#424242"><path d="M3 5h9v8h1V4H3zM5 2v1h9v8h1V2zM1 6v9h10V6H1zm8 7H7.5L6 11.5 4.5 13H3l2.3-2.3L3 8.5h1.5L6 10l1.5-1.5H9l-2.3 2.3L9 13z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 335 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="3 3 16 16" enable-background="new 3 3 16 16"><polygon fill="#FFF" points="12.597,11.042 15.4,13.845 13.844,15.4 11.042,12.598 8.239,15.4 6.683,13.845 9.485,11.042 6.683,8.239 8.238,6.683 11.042,9.486 13.845,6.683 15.4,8.239"/></svg>
|
||||
|
After Width: | Height: | Size: 304 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="3 3 16 16" enable-background="new 3 3 16 16"><polygon fill="#e8e8e8" points="12.597,11.042 15.4,13.845 13.844,15.4 11.042,12.598 8.239,15.4 6.683,13.845 9.485,11.042 6.683,8.239 8.238,6.683 11.042,9.486 13.845,6.683 15.4,8.239"/></svg>
|
||||
|
After Width: | Height: | Size: 307 B |
1
src/vs/workbench/parts/debug/browser/media/remove.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="3 3 16 16" enable-background="new 3 3 16 16"><polygon fill="#424242" points="12.597,11.042 15.4,13.845 13.844,15.4 11.042,12.598 8.239,15.4 6.683,13.845 9.485,11.042 6.683,8.239 8.238,6.683 11.042,9.486 13.845,6.683 15.4,8.239"/></svg>
|
||||
|
After Width: | Height: | Size: 307 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{fill:#252526;} .icon-vs-bg{fill:#c5c5c5;} .icon-vs-fg{fill:#2a292c;}</style><path class="icon-canvas-transparent" d="M32 32h-32v-32h32v32z" id="canvas"/><path class="icon-vs-out" d="M32 28h-32v-24h32v24z" id="outline"/><path class="icon-vs-bg" d="M2 6v20h28v-20h-28zm26 18h-24v-16h24v16zm-13-8l-5.25 5.5-1.75-1.833 3.5-3.667-3.5-3.667 1.75-1.833 5.25 5.5z" id="iconBg"/><g id="iconFg"><path class="icon-vs-fg" d="M4 8v16h24v-16h-24zm5.75 13.5l-1.75-1.833 3.5-3.667-3.5-3.667 1.75-1.833 5.25 5.5-5.25 5.5z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 686 B |
182
src/vs/workbench/parts/debug/browser/media/repl.css
Normal file
@@ -0,0 +1,182 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* Debug repl */
|
||||
|
||||
.monaco-workbench .repl {
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .surveyor {
|
||||
font-family: Monaco, Menlo, Consolas, "Droid Sans Mono", "Inconsolata", "Courier New", monospace, "Droid Sans Fallback";
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
width : auto;
|
||||
top: 0;
|
||||
left: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content {
|
||||
line-height: 18px;
|
||||
-webkit-user-select: text;
|
||||
/* Wrap words but also do not trim whitespace #6275 */
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
/* Break on all #7533 */
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.monaco-workbench.mac .repl .repl-tree .monaco-tree-row .input.expression,
|
||||
.monaco-workbench.mac .repl .repl-tree .monaco-tree-row .output.expression {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.monaco-workbench.windows .repl .repl-tree .monaco-tree-row .input.expression,
|
||||
.monaco-workbench.windows .repl .repl-tree .monaco-tree-row .output.expression,
|
||||
.monaco-workbench.linux .repl .repl-tree .monaco-tree-row .input.expression,
|
||||
.monaco-workbench.linux .repl .repl-tree .monaco-tree-row .output.expression {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree-row .output.expression > .value {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree-row .output.expression > .annotation {
|
||||
font-size: inherit;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree-row .output.expression .name:not(:empty) {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
/* Allign twistie since repl tree is smaller and sometimes has paired elements */
|
||||
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row.has-children > .content.input-output-pair:before {
|
||||
top: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row.has-children > .content.input-output-pair:after {
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-input-wrapper {
|
||||
padding-left: 20px;
|
||||
border-top: 1px solid rgba(128, 128, 128, 0.35);
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-rows > .monaco-tree-row {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children .content .expression {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Disable repl hover highlight in tree. */
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-rows > .monaco-tree-row:hover:not(.highlighted):not(.selected):not(.focused) {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
/* Only show 'stale expansion' info when the element gets expanded. */
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-rows > .monaco-tree-row:not(.expanded) > .content.input-output-pair > .output > .annotation::before {
|
||||
content: '';
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .repl .repl-input-wrapper {
|
||||
border-top-color: #6FC3DF;
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-input-wrapper:before {
|
||||
left: 8px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.monaco-workbench .repl .repl-input-wrapper:before {
|
||||
content: '\276f';
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.monaco-workbench.linux .repl .repl-input-wrapper:before {
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
/* Actions */
|
||||
|
||||
.monaco-workbench .debug-action.clear-repl {
|
||||
background: url('clear-repl.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .debug-action.clear-repl,
|
||||
.hc-black .monaco-workbench .debug-action.clear-repl {
|
||||
background: url('clear-repl-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
/* Output coloring */
|
||||
|
||||
.vs .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression > .warn {
|
||||
color: #cd9731;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression > .warn {
|
||||
color: #cd9731;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression > .warn {
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
.vs .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression > .annotation {
|
||||
color: #007ACC;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression > .annotation {
|
||||
color: #1B80B2;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression > .annotation {
|
||||
color: #0000FF;
|
||||
}
|
||||
|
||||
/* ANSI Codes */
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code-bold { font-weight: bold; }
|
||||
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code30, .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code90 { color: gray; }
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code31, .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code91 { color: #BE1717; }
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code32, .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code92 { color: #338A2F; }
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code33, .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code93 { color: #BEB817; }
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code34, .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code94 { color: darkblue; }
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code35, .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code95 { color: darkmagenta; }
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code36, .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code96 { color: darkcyan; }
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code37, .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code97 { color: #BDBDBD; }
|
||||
|
||||
.vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code30, .vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code90 { color: #A0A0A0; }
|
||||
.vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code31, .vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code91 { color: #A74747; }
|
||||
.vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code32, .vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code92 { color: #348F34; }
|
||||
.vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code33, .vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code93 { color: #5F4C29; }
|
||||
.vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code34, .vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code94 { color: #6286BB; }
|
||||
.vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code35, .vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code95 { color: #914191; }
|
||||
.vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code36, .vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code96 { color: #218D8D; }
|
||||
.vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code37, .vs-dark .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code97 { color: #707070; }
|
||||
|
||||
.hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code30, .hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code90 { color: gray; }
|
||||
.hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code31, .hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code91 { color: #A74747; }
|
||||
.hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code32, .hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code92 { color: #348F34; }
|
||||
.hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code33, .hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code93 { color: #5F4C29; }
|
||||
.hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code34, .hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code94 { color: #6286BB; }
|
||||
.hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code35, .hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code95 { color: #914191; }
|
||||
.hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code36, .hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code96 { color: #218D8D; }
|
||||
.hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code37, .hc-black .monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression .code97 { color: #707070; }
|
||||
|
||||
/* Links */
|
||||
.monaco-workbench .repl .repl-tree .monaco-tree .monaco-tree-row > .content > .output.expression a {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
1
src/vs/workbench/parts/debug/browser/media/repl.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{fill:#F6F6F6;} .icon-vs-bg{fill:#424242;} .icon-vs-fg{fill:#F0EFF1;}</style><path class="icon-canvas-transparent" d="M32 32h-32v-32h32v32z" id="canvas"/><path class="icon-vs-out" d="M32 28h-32v-24h32v24z" id="outline"/><path class="icon-vs-bg" d="M2 6v20h28v-20h-28zm26 18h-24v-16h24v16zm-13-8l-5.25 5.5-1.75-1.833 3.5-3.667-3.5-3.667 1.75-1.833 5.25 5.5z" id="iconBg"/><g id="iconFg"><path class="icon-vs-fg" d="M4 8v16h24v-16h-24zm5.75 13.5l-1.75-1.833 3.5-3.667-3.5-3.667 1.75-1.833 5.25 5.5-5.25 5.5z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 686 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill="#1E1E1E" d="M9.3 2.1L11.4 0H5.6l-4 4 .8.8-.4.6C1.4 6.5 1 7.7 1 9c0 3.9 3.1 7 7 7s7-3.1 7-7c0-3.4-2.5-6.3-5.7-6.9zM8 12c-1.7 0-3-1.3-3-3 0-.4.1-.8.3-1.2v-.1l.3.3h5.2c.1.3.2.6.2 1 0 1.7-1.3 3-3 3z"/><path fill="#89D185" d="M8 3H7l2-2H6L3 4l3 3h3L7 5h1c2.2 0 4 1.8 4 4s-1.8 4-4 4-4-1.8-4-4c0-.6.1-1.1.4-1.6L2.9 5.9c-.6.9-.9 2-.9 3.1 0 3.3 2.7 6 6 6s6-2.7 6-6-2.7-6-6-6z"/></svg>
|
||||
|
After Width: | Height: | Size: 470 B |
1
src/vs/workbench/parts/debug/browser/media/restart.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill="#F6F6F6" d="M9.3 2.1L11.4 0H5.6l-4 4 .8.8-.4.6C1.4 6.5 1 7.7 1 9c0 3.9 3.1 7 7 7s7-3.1 7-7c0-3.4-2.5-6.3-5.7-6.9zM8 12c-1.7 0-3-1.3-3-3 0-.4.1-.8.3-1.2v-.1l.3.3h5.2c.1.3.2.6.2 1 0 1.7-1.3 3-3 3z"/><path fill="#388A34" d="M8 3H7l2-2H6L3 4l3 3h3L7 5h1c2.2 0 4 1.8 4 4s-1.8 4-4 4-4-1.8-4-4c0-.6.1-1.1.4-1.6L2.9 5.9c-.6.9-.9 2-.9 3.1 0 3.3 2.7 6 6 6s6-2.7 6-6-2.7-6-6-6z"/></svg>
|
||||
|
After Width: | Height: | Size: 470 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-red{fill:#e51400}.icon-vs-yellow{fill:#9CCE9C}.icon-vs-bg{fill:#424242}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-bg" d="M14.414 8l-5 6H3V2h6.414l5 6z" id="outline" style="display: none;"/><path class="icon-vs-yellow" d="M13 8l-4 5H4V3h5l4 5z" id="iconBg"/><g id="iconFg"><path class="icon-vs-red" d="M10.5 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 533 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-red{fill:#e51400}.icon-vs-yellow{fill:#CEE7CE}.icon-vs-bg{fill:#424242}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-bg" d="M14.414 8l-5 6H3V2h6.414l5 6z" id="outline" style="display: none;"/><path class="icon-vs-yellow" d="M13 8l-4 5H4V3h5l4 5z" id="iconBg"/><g id="iconFg"><path class="icon-vs-red" d="M10.5 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 533 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-yellow{fill:#9CCE9C}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-bg" d="M14.414 8l-5 6H3V2h6.414l5 6z" id="outline" style="display: none;"/><g id="iconBg"><path class="icon-vs-yellow" d="M13 8l-4 5H4V3h5l4 5z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 427 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-yellow{fill:#CEE7CE}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-bg" d="M14.414 8l-5 6H3V2h6.414l5 6z" id="outline" style="display: none;"/><g id="iconBg"><path class="icon-vs-yellow" d="M13 8l-4 5H4V3h5l4 5z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 427 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#2D2D30;} .icon-vs-out{fill:#2D2D30;} .icon-vs-bg{fill:#C5C5C5;} .icon-vs-action-blue{fill:#75BEFF;}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M11 13c0-1.526-1.15-2.775-2.624-2.962L12 6.414V1.586l-2 2V1H6v2.586l-2-2v4.828l3.624 3.624C6.15 10.225 5 11.474 5 13c0 1.654 1.346 3 3 3s3-1.346 3-3z" id="outline"/><path class="icon-vs-bg" d="M8 11c1.104 0 2 .896 2 2s-.896 2-2 2-2-.896-2-2 .896-2 2-2z" id="iconBg"/><path class="icon-vs-action-blue" d="M8 9L5 6V4l2 2V2h2v4l2-2v2L8 9z" id="colorAction"/></svg>
|
||||
|
After Width: | Height: | Size: 717 B |
1
src/vs/workbench/parts/debug/browser/media/step-into.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{fill:#F6F6F6;} .icon-vs-bg{fill:#424242;} .icon-vs-action-blue{fill:#00539C;}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M11 13c0-1.526-1.15-2.775-2.624-2.962L12 6.414V1.586l-2 2V1H6v2.586l-2-2v4.828l3.624 3.624C6.15 10.225 5 11.474 5 13c0 1.654 1.346 3 3 3s3-1.346 3-3z" id="outline"/><path class="icon-vs-bg" d="M8 11c1.104 0 2 .896 2 2s-.896 2-2 2-2-.896-2-2 .896-2 2-2z" id="iconBg"/><path class="icon-vs-action-blue" d="M8 9L5 6V4l2 2V2h2v4l2-2v2L8 9z" id="colorAction"/></svg>
|
||||
|
After Width: | Height: | Size: 717 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#2D2D30;} .icon-vs-out{fill:#2D2D30;} .icon-vs-bg{fill:#C5C5C5;} .icon-vs-action-blue{fill:#75BEFF;}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><g id="outline"><path class="icon-vs-out" d="M10 7.414l2 2V4.586l-4-4-4 4v4.828l2-2V10h4z"/><circle class="icon-vs-out" cx="8" cy="13" r="3"/></g><path class="icon-vs-bg" d="M8 11c1.104 0 2 .896 2 2s-.896 2-2 2-2-.896-2-2 .896-2 2-2z" id="iconBg"/><path class="icon-vs-action-blue" d="M11 5v2L9 5v4H7V5L5 7V5l3-3 3 3z" id="colorAction"/></svg>
|
||||
|
After Width: | Height: | Size: 670 B |
1
src/vs/workbench/parts/debug/browser/media/step-out.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{fill:#F6F6F6;} .icon-vs-bg{fill:#424242;} .icon-vs-action-blue{fill:#00539C;}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><g id="outline"><path class="icon-vs-out" d="M10 7.414l2 2V4.586l-4-4-4 4v4.828l2-2V10h4z"/><circle class="icon-vs-out" cx="8" cy="13" r="3"/></g><path class="icon-vs-bg" d="M8 11c1.104 0 2 .896 2 2s-.896 2-2 2-2-.896-2-2 .896-2 2-2z" id="iconBg"/><path class="icon-vs-action-blue" d="M11 5v2L9 5v4H7V5L5 7V5l3-3 3 3z" id="colorAction"/></svg>
|
||||
|
After Width: | Height: | Size: 670 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#2D2D30;} .icon-vs-out{fill:#2D2D30;} .icon-vs-bg{fill:#C5C5C5;} .icon-vs-action-blue{fill:#75BEFF;}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M8 16c-1.654 0-3-1.346-3-3s1.346-3 3-3 3 1.346 3 3-1.346 3-3 3zm7-6V4.586l-4-4V3.03C9.967 2.367 8.755 2 7.5 2 4.158 2 1.305 4.596 1.004 7.91L.904 9H4.55l.113-.872c.104-.79.528-1.474 1.13-1.923L9.587 10H15zM6.106 6c.415-.232.892-.363 1.394-.363.51 0 1.02.133 1.466.363h-2.86z" id="outline"/><path class="icon-vs-bg" d="M8 11c1.104 0 2 .896 2 2s-.896 2-2 2-2-.896-2-2 .896-2 2-2z" id="iconBg"/><path class="icon-vs-action-blue" d="M3.67 8H2c.254-2.8 2.637-5 5.5-5 1.86 0 3.504.93 4.5 2.348V3l2 2v4h-4L8 7h3v-.002l.238.002C10.652 5.61 9.102 4.637 7.5 4.637 5.535 4.637 3.915 6.102 3.67 8z" id="colorAction"/></svg>
|
||||
|
After Width: | Height: | Size: 967 B |
1
src/vs/workbench/parts/debug/browser/media/step-over.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{fill:#F6F6F6;} .icon-vs-bg{fill:#424242;} .icon-vs-action-blue{fill:#00539C;}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M8 16c-1.654 0-3-1.346-3-3s1.346-3 3-3 3 1.346 3 3-1.346 3-3 3zm7-6V4.586l-4-4V3.03C9.967 2.367 8.755 2 7.5 2 4.158 2 1.305 4.596 1.004 7.91L.904 9H4.55l.113-.872c.104-.79.528-1.474 1.13-1.923L9.587 10H15zM6.106 6c.415-.232.892-.363 1.394-.363.51 0 1.02.133 1.466.363h-2.86z" id="outline"/><path class="icon-vs-bg" d="M8 11c1.104 0 2 .896 2 2s-.896 2-2 2-2-.896-2-2 .896-2 2-2z" id="iconBg"/><path class="icon-vs-action-blue" d="M3.67 8H2c.254-2.8 2.637-5 5.5-5 1.86 0 3.504.93 4.5 2.348V3l2 2v4h-4L8 7h3v-.002l.238.002C10.652 5.61 9.102 4.637 7.5 4.637 5.535 4.637 3.915 6.102 3.67 8z" id="colorAction"/></svg>
|
||||
|
After Width: | Height: | Size: 967 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><path fill="#2D2D30" d="M13 13h-10v-10h10v10z"/><path fill="#F48771" d="M12 12h-8v-8h8v8z"/></svg>
|
||||
|
After Width: | Height: | Size: 215 B |
1
src/vs/workbench/parts/debug/browser/media/stop.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><path fill="#F6F6F6" d="M13 13h-10v-10h10v10z"/><path fill="#A1260D" d="M12 12h-8v-8h8v8z"/></svg>
|
||||
|
After Width: | Height: | Size: 215 B |
642
src/vs/workbench/parts/debug/common/debug.ts
Normal file
@@ -0,0 +1,642 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import uri from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import Event from 'vs/base/common/event';
|
||||
import { IJSONSchemaSnippet } from 'vs/base/common/jsonSchema';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IModel as EditorIModel, IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { IEditor } from 'vs/platform/editor/common/editor';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { ISuggestion } from 'vs/editor/common/modes';
|
||||
import { Source } from 'vs/workbench/parts/debug/common/debugSource';
|
||||
import { Range, IRange } from 'vs/editor/common/core/range';
|
||||
import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
export const VIEWLET_ID = 'workbench.view.debug';
|
||||
export const REPL_ID = 'workbench.panel.repl';
|
||||
export const DEBUG_SERVICE_ID = 'debugService';
|
||||
export const CONTEXT_DEBUG_TYPE = new RawContextKey<string>('debugType', undefined);
|
||||
export const CONTEXT_DEBUG_STATE = new RawContextKey<string>('debugState', undefined);
|
||||
export const CONTEXT_IN_DEBUG_MODE = new RawContextKey<boolean>('inDebugMode', false);
|
||||
export const CONTEXT_NOT_IN_DEBUG_MODE: ContextKeyExpr = CONTEXT_IN_DEBUG_MODE.toNegated();
|
||||
export const CONTEXT_IN_DEBUG_REPL = new RawContextKey<boolean>('inDebugRepl', false);
|
||||
export const CONTEXT_NOT_IN_DEBUG_REPL: ContextKeyExpr = CONTEXT_IN_DEBUG_REPL.toNegated();
|
||||
export const CONTEXT_ON_FIRST_DEBUG_REPL_LINE = new RawContextKey<boolean>('onFirsteDebugReplLine', false);
|
||||
export const CONTEXT_ON_LAST_DEBUG_REPL_LINE = new RawContextKey<boolean>('onLastDebugReplLine', false);
|
||||
export const CONTEXT_BREAKPOINT_WIDGET_VISIBLE = new RawContextKey<boolean>('breakpointWidgetVisible', false);
|
||||
export const CONTEXT_BREAKPOINTS_FOCUSED = new RawContextKey<boolean>('breakpointsFocused', false);
|
||||
export const CONTEXT_WATCH_EXPRESSIONS_FOCUSED = new RawContextKey<boolean>('watchExpressionsFocused', false);
|
||||
export const CONTEXT_VARIABLES_FOCUSED = new RawContextKey<boolean>('variablesFocused', false);
|
||||
|
||||
export const EDITOR_CONTRIBUTION_ID = 'editor.contrib.debug';
|
||||
export const DEBUG_SCHEME = 'debug';
|
||||
export const INTERNAL_CONSOLE_OPTIONS_SCHEMA = {
|
||||
enum: ['neverOpen', 'openOnSessionStart', 'openOnFirstSessionStart'],
|
||||
default: 'openOnFirstSessionStart',
|
||||
description: nls.localize('internalConsoleOptions', "Controls behavior of the internal debug console.")
|
||||
};
|
||||
|
||||
// raw
|
||||
|
||||
export interface IRawModelUpdate {
|
||||
threadId: number;
|
||||
sessionId: string;
|
||||
thread?: DebugProtocol.Thread;
|
||||
callStack?: DebugProtocol.StackFrame[];
|
||||
stoppedDetails?: IRawStoppedDetails;
|
||||
allThreadsStopped?: boolean;
|
||||
}
|
||||
|
||||
export interface IRawStoppedDetails {
|
||||
reason: string;
|
||||
description?: string;
|
||||
threadId?: number;
|
||||
text?: string;
|
||||
totalFrames?: number;
|
||||
framesErrorMessage?: string;
|
||||
}
|
||||
|
||||
// model
|
||||
|
||||
export interface ITreeElement {
|
||||
getId(): string;
|
||||
}
|
||||
|
||||
export interface IReplElement extends ITreeElement {
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
export interface IExpressionContainer extends ITreeElement {
|
||||
hasChildren: boolean;
|
||||
getChildren(): TPromise<IExpression[]>;
|
||||
}
|
||||
|
||||
export interface IExpression extends IReplElement, IExpressionContainer {
|
||||
name: string;
|
||||
value: string;
|
||||
valueChanged?: boolean;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export interface ISession {
|
||||
root: uri;
|
||||
stackTrace(args: DebugProtocol.StackTraceArguments): TPromise<DebugProtocol.StackTraceResponse>;
|
||||
exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): TPromise<DebugProtocol.ExceptionInfoResponse>;
|
||||
scopes(args: DebugProtocol.ScopesArguments): TPromise<DebugProtocol.ScopesResponse>;
|
||||
variables(args: DebugProtocol.VariablesArguments): TPromise<DebugProtocol.VariablesResponse>;
|
||||
evaluate(args: DebugProtocol.EvaluateArguments): TPromise<DebugProtocol.EvaluateResponse>;
|
||||
|
||||
capabilities: DebugProtocol.Capabilities;
|
||||
disconnect(restart?: boolean, force?: boolean): TPromise<DebugProtocol.DisconnectResponse>;
|
||||
custom(request: string, args: any): TPromise<DebugProtocol.Response>;
|
||||
onDidEvent: Event<DebugProtocol.Event>;
|
||||
onDidInitialize: Event<DebugProtocol.InitializedEvent>;
|
||||
restartFrame(args: DebugProtocol.RestartFrameArguments, threadId: number): TPromise<DebugProtocol.RestartFrameResponse>;
|
||||
|
||||
next(args: DebugProtocol.NextArguments): TPromise<DebugProtocol.NextResponse>;
|
||||
stepIn(args: DebugProtocol.StepInArguments): TPromise<DebugProtocol.StepInResponse>;
|
||||
stepOut(args: DebugProtocol.StepOutArguments): TPromise<DebugProtocol.StepOutResponse>;
|
||||
continue(args: DebugProtocol.ContinueArguments): TPromise<DebugProtocol.ContinueResponse>;
|
||||
pause(args: DebugProtocol.PauseArguments): TPromise<DebugProtocol.PauseResponse>;
|
||||
stepBack(args: DebugProtocol.StepBackArguments): TPromise<DebugProtocol.StepBackResponse>;
|
||||
reverseContinue(args: DebugProtocol.ReverseContinueArguments): TPromise<DebugProtocol.ReverseContinueResponse>;
|
||||
|
||||
completions(args: DebugProtocol.CompletionsArguments): TPromise<DebugProtocol.CompletionsResponse>;
|
||||
setVariable(args: DebugProtocol.SetVariableArguments): TPromise<DebugProtocol.SetVariableResponse>;
|
||||
source(args: DebugProtocol.SourceArguments): TPromise<DebugProtocol.SourceResponse>;
|
||||
}
|
||||
|
||||
export enum ProcessState {
|
||||
INACTIVE,
|
||||
ATTACH,
|
||||
LAUNCH
|
||||
}
|
||||
|
||||
export interface IProcess extends ITreeElement {
|
||||
getName(includeRoot: boolean): string;
|
||||
configuration: IConfig;
|
||||
session: ISession;
|
||||
sources: Map<string, Source>;
|
||||
state: ProcessState;
|
||||
getThread(threadId: number): IThread;
|
||||
getAllThreads(): IThread[];
|
||||
completions(frameId: number, text: string, position: Position, overwriteBefore: number): TPromise<ISuggestion[]>;
|
||||
}
|
||||
|
||||
export interface IThread extends ITreeElement {
|
||||
|
||||
/**
|
||||
* Process the thread belongs to
|
||||
*/
|
||||
process: IProcess;
|
||||
|
||||
/**
|
||||
* Id of the thread generated by the debug adapter backend.
|
||||
*/
|
||||
threadId: number;
|
||||
|
||||
/**
|
||||
* Name of the thread.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Information about the current thread stop event. Null if thread is not stopped.
|
||||
*/
|
||||
stoppedDetails: IRawStoppedDetails;
|
||||
|
||||
/**
|
||||
* Information about the exception if an 'exception' stopped event raised and DA supports the 'exceptionInfo' request, otherwise null.
|
||||
*/
|
||||
exceptionInfo: TPromise<IExceptionInfo>;
|
||||
|
||||
/**
|
||||
* Gets the callstack if it has already been received from the debug
|
||||
* adapter, otherwise it returns null.
|
||||
*/
|
||||
getCallStack(): IStackFrame[];
|
||||
|
||||
/**
|
||||
* Invalidates the callstack cache
|
||||
*/
|
||||
clearCallStack(): void;
|
||||
|
||||
/**
|
||||
* Indicates whether this thread is stopped. The callstack for stopped
|
||||
* threads can be retrieved from the debug adapter.
|
||||
*/
|
||||
stopped: boolean;
|
||||
|
||||
next(): TPromise<any>;
|
||||
stepIn(): TPromise<any>;
|
||||
stepOut(): TPromise<any>;
|
||||
stepBack(): TPromise<any>;
|
||||
continue(): TPromise<any>;
|
||||
pause(): TPromise<any>;
|
||||
reverseContinue(): TPromise<any>;
|
||||
}
|
||||
|
||||
export interface IScope extends IExpressionContainer {
|
||||
name: string;
|
||||
expensive: boolean;
|
||||
range?: IRange;
|
||||
}
|
||||
|
||||
export interface IStackFrame extends ITreeElement {
|
||||
thread: IThread;
|
||||
name: string;
|
||||
presentationHint: string;
|
||||
frameId: number;
|
||||
range: IRange;
|
||||
source: Source;
|
||||
getScopes(): TPromise<IScope[]>;
|
||||
getMostSpecificScopes(range: IRange): TPromise<IScope[]>;
|
||||
restart(): TPromise<any>;
|
||||
toString(): string;
|
||||
openInEditor(editorService: IWorkbenchEditorService, preserveFocus?: boolean, sideBySide?: boolean): TPromise<any>;
|
||||
}
|
||||
|
||||
export interface IEnablement extends ITreeElement {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface IRawBreakpoint {
|
||||
lineNumber: number;
|
||||
column?: number;
|
||||
enabled?: boolean;
|
||||
condition?: string;
|
||||
hitCondition?: string;
|
||||
}
|
||||
|
||||
export interface IBreakpoint extends IEnablement {
|
||||
uri: uri;
|
||||
lineNumber: number;
|
||||
endLineNumber?: number;
|
||||
column: number;
|
||||
endColumn?: number;
|
||||
condition: string;
|
||||
hitCondition: string;
|
||||
verified: boolean;
|
||||
idFromAdapter: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface IFunctionBreakpoint extends IEnablement {
|
||||
name: string;
|
||||
verified: boolean;
|
||||
idFromAdapter: number;
|
||||
hitCondition: string;
|
||||
}
|
||||
|
||||
export interface IExceptionBreakpoint extends IEnablement {
|
||||
filter: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export interface IExceptionInfo {
|
||||
id?: string;
|
||||
description?: string;
|
||||
breakMode: string;
|
||||
details?: DebugProtocol.ExceptionDetails;
|
||||
}
|
||||
|
||||
// model interfaces
|
||||
|
||||
export interface IViewModel extends ITreeElement {
|
||||
/**
|
||||
* Returns the focused debug process or null if no process is stopped.
|
||||
*/
|
||||
focusedProcess: IProcess;
|
||||
|
||||
/**
|
||||
* Returns the focused thread or null if no thread is stopped.
|
||||
*/
|
||||
focusedThread: IThread;
|
||||
|
||||
/**
|
||||
* Returns the focused stack frame or null if there are no stack frames.
|
||||
*/
|
||||
focusedStackFrame: IStackFrame;
|
||||
getSelectedExpression(): IExpression;
|
||||
getSelectedFunctionBreakpoint(): IFunctionBreakpoint;
|
||||
setSelectedExpression(expression: IExpression);
|
||||
setSelectedFunctionBreakpoint(functionBreakpoint: IFunctionBreakpoint): void;
|
||||
|
||||
isMultiProcessView(): boolean;
|
||||
|
||||
onDidFocusProcess: Event<IProcess | undefined>;
|
||||
onDidFocusStackFrame: Event<{ stackFrame: IStackFrame, explicit: boolean }>;
|
||||
onDidSelectExpression: Event<IExpression>;
|
||||
onDidSelectFunctionBreakpoint: Event<IFunctionBreakpoint>;
|
||||
}
|
||||
|
||||
export interface IModel extends ITreeElement {
|
||||
getProcesses(): IProcess[];
|
||||
getBreakpoints(): IBreakpoint[];
|
||||
areBreakpointsActivated(): boolean;
|
||||
getFunctionBreakpoints(): IFunctionBreakpoint[];
|
||||
getExceptionBreakpoints(): IExceptionBreakpoint[];
|
||||
getWatchExpressions(): IExpression[];
|
||||
getReplElements(): IReplElement[];
|
||||
|
||||
onDidChangeBreakpoints: Event<void>;
|
||||
onDidChangeCallStack: Event<void>;
|
||||
onDidChangeWatchExpressions: Event<IExpression>;
|
||||
onDidChangeReplElements: Event<void>;
|
||||
};
|
||||
|
||||
// Debug enums
|
||||
|
||||
export enum State {
|
||||
Inactive,
|
||||
Initializing,
|
||||
Stopped,
|
||||
Running
|
||||
}
|
||||
|
||||
// Debug configuration interfaces
|
||||
|
||||
export interface IDebugConfiguration {
|
||||
allowBreakpointsEverywhere: boolean;
|
||||
openExplorerOnEnd: boolean;
|
||||
inlineValues: boolean;
|
||||
hideActionBar: boolean;
|
||||
internalConsoleOptions: string;
|
||||
}
|
||||
|
||||
export interface IGlobalConfig {
|
||||
version: string;
|
||||
compounds: ICompound[];
|
||||
configurations: IConfig[];
|
||||
}
|
||||
|
||||
export interface IEnvConfig {
|
||||
name?: string;
|
||||
type: string;
|
||||
request: string;
|
||||
internalConsoleOptions?: string;
|
||||
preLaunchTask?: string;
|
||||
__restart?: any;
|
||||
__sessionId?: string;
|
||||
debugServer?: number;
|
||||
noDebug?: boolean;
|
||||
port?: number;
|
||||
}
|
||||
|
||||
export interface IConfig extends IEnvConfig {
|
||||
windows?: IEnvConfig;
|
||||
osx?: IEnvConfig;
|
||||
linux?: IEnvConfig;
|
||||
}
|
||||
|
||||
export interface ICompound {
|
||||
name: string;
|
||||
configurations: string[];
|
||||
}
|
||||
|
||||
export interface IAdapterExecutable {
|
||||
command?: string;
|
||||
args?: string[];
|
||||
}
|
||||
|
||||
export interface IRawEnvAdapter {
|
||||
type?: string;
|
||||
label?: string;
|
||||
program?: string;
|
||||
args?: string[];
|
||||
runtime?: string;
|
||||
runtimeArgs?: string[];
|
||||
}
|
||||
|
||||
export interface IRawAdapter extends IRawEnvAdapter {
|
||||
adapterExecutableCommand?: string;
|
||||
enableBreakpointsFor?: { languageIds: string[] };
|
||||
configurationAttributes?: any;
|
||||
configurationSnippets?: IJSONSchemaSnippet[];
|
||||
initialConfigurations?: any[] | string;
|
||||
startSessionCommand?: string;
|
||||
languages?: string[];
|
||||
variables?: { [key: string]: string };
|
||||
aiKey?: string;
|
||||
win?: IRawEnvAdapter;
|
||||
winx86?: IRawEnvAdapter;
|
||||
windows?: IRawEnvAdapter;
|
||||
osx?: IRawEnvAdapter;
|
||||
linux?: IRawEnvAdapter;
|
||||
}
|
||||
|
||||
export interface IDebugConfigurationProvider {
|
||||
type: string;
|
||||
resolveDebugConfiguration?(folderUri: uri | undefined, debugConfiguration: any): TPromise<any>;
|
||||
provideDebugConfigurations?(folderUri: uri | undefined): TPromise<any[]>;
|
||||
}
|
||||
|
||||
export interface IConfigurationManager {
|
||||
/**
|
||||
* Returns true if breakpoints can be set for a given editor model. Depends on mode.
|
||||
*/
|
||||
canSetBreakpointsIn(model: EditorIModel): boolean;
|
||||
|
||||
/**
|
||||
* Returns null for no folder workspace. Otherwise returns a launch object corresponding to the selected debug configuration.
|
||||
*/
|
||||
selectedLaunch: ILaunch;
|
||||
|
||||
selectedName: string;
|
||||
|
||||
selectConfiguration(launch: ILaunch, name?: string, debugStarted?: boolean): void;
|
||||
|
||||
getLaunches(): ILaunch[];
|
||||
|
||||
/**
|
||||
* Allows to register on change of selected debug configuration.
|
||||
*/
|
||||
onDidSelectConfiguration: Event<void>;
|
||||
|
||||
/**
|
||||
* Returns a "startSessionCommand" contribution for an adapter with the passed type.
|
||||
* If no type is specified will try to automatically pick an adapter by looking at
|
||||
* the active editor language and matching it against the "languages" contribution of an adapter.
|
||||
*/
|
||||
getStartSessionCommand(type?: string): TPromise<{ command: string, type: string }>;
|
||||
|
||||
registerDebugConfigurationProvider(handle: number, debugConfigurationProvider: IDebugConfigurationProvider): void;
|
||||
unregisterDebugConfigurationProvider(handle: number): void;
|
||||
resolveDebugConfiguration(folderUri: uri | undefined, debugConfiguration: any): TPromise<any>;
|
||||
}
|
||||
|
||||
export interface ILaunch {
|
||||
|
||||
/**
|
||||
* Resource pointing to the launch.json this object is wrapping.
|
||||
*/
|
||||
uri: uri;
|
||||
|
||||
workspaceUri: uri;
|
||||
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Returns a configuration with the specified name.
|
||||
* Returns null if there is no configuration with the specified name.
|
||||
*/
|
||||
getConfiguration(name: string): IConfig;
|
||||
|
||||
/**
|
||||
* Returns a compound with the specified name.
|
||||
* Returns null if there is no compound with the specified name.
|
||||
*/
|
||||
getCompound(name: string): ICompound;
|
||||
|
||||
/**
|
||||
* Returns the names of all configurations and compounds.
|
||||
* Ignores configurations which are invalid.
|
||||
*/
|
||||
getConfigurationNames(): string[];
|
||||
|
||||
/**
|
||||
* Returns the resolved configuration.
|
||||
* Replaces os specific values, system variables, interactive variables.
|
||||
*/
|
||||
resolveConfiguration(config: IConfig): TPromise<IConfig>;
|
||||
|
||||
/**
|
||||
* Opens the launch.json file. Creates if it does not exist.
|
||||
*/
|
||||
openConfigFile(sideBySide: boolean, type?: string): TPromise<IEditor>;
|
||||
}
|
||||
|
||||
// Debug service interfaces
|
||||
|
||||
export const IDebugService = createDecorator<IDebugService>(DEBUG_SERVICE_ID);
|
||||
|
||||
export interface DebugEvent extends DebugProtocol.Event {
|
||||
sessionId?: string;
|
||||
}
|
||||
|
||||
export interface IDebugService {
|
||||
_serviceBrand: any;
|
||||
|
||||
/**
|
||||
* Gets the current debug state.
|
||||
*/
|
||||
state: State;
|
||||
|
||||
/**
|
||||
* Allows to register on debug state changes.
|
||||
*/
|
||||
onDidChangeState: Event<State>;
|
||||
|
||||
/**
|
||||
* Allows to register on new process events.
|
||||
*/
|
||||
onDidNewProcess: Event<IProcess>;
|
||||
|
||||
/**
|
||||
* Allows to register on end process events.
|
||||
*/
|
||||
onDidEndProcess: Event<IProcess>;
|
||||
|
||||
/**
|
||||
* Allows to register on custom DAP events.
|
||||
*/
|
||||
onDidCustomEvent: Event<DebugEvent>;
|
||||
|
||||
/**
|
||||
* Gets the current configuration manager.
|
||||
*/
|
||||
getConfigurationManager(): IConfigurationManager;
|
||||
|
||||
/**
|
||||
* Sets the focused stack frame and evaluates all expressions against the newly focused stack frame,
|
||||
*/
|
||||
focusStackFrameAndEvaluate(focusedStackFrame: IStackFrame, process?: IProcess, explicit?: boolean): TPromise<void>;
|
||||
|
||||
/**
|
||||
* Adds new breakpoints to the model for the file specified with the uri. Notifies debug adapter of breakpoint changes.
|
||||
*/
|
||||
addBreakpoints(uri: uri, rawBreakpoints: IRawBreakpoint[]): TPromise<void>;
|
||||
|
||||
/**
|
||||
* Enables or disables all breakpoints. If breakpoint is passed only enables or disables the passed breakpoint.
|
||||
* Notifies debug adapter of breakpoint changes.
|
||||
*/
|
||||
enableOrDisableBreakpoints(enable: boolean, breakpoint?: IEnablement): TPromise<void>;
|
||||
|
||||
/**
|
||||
* Sets the global activated property for all breakpoints.
|
||||
* Notifies debug adapter of breakpoint changes.
|
||||
*/
|
||||
setBreakpointsActivated(activated: boolean): TPromise<void>;
|
||||
|
||||
/**
|
||||
* Removes all breakpoints. If id is passed only removes the breakpoint associated with that id.
|
||||
* Notifies debug adapter of breakpoint changes.
|
||||
*/
|
||||
removeBreakpoints(id?: string): TPromise<any>;
|
||||
|
||||
/**
|
||||
* Adds a new no name function breakpoint. The function breakpoint should be renamed once user enters the name.
|
||||
*/
|
||||
addFunctionBreakpoint(): void;
|
||||
|
||||
/**
|
||||
* Renames an already existing function breakpoint.
|
||||
* Notifies debug adapter of breakpoint changes.
|
||||
*/
|
||||
renameFunctionBreakpoint(id: string, newFunctionName: string): TPromise<void>;
|
||||
|
||||
/**
|
||||
* Removes all function breakpoints. If id is passed only removes the function breakpoint with the passed id.
|
||||
* Notifies debug adapter of breakpoint changes.
|
||||
*/
|
||||
removeFunctionBreakpoints(id?: string): TPromise<void>;
|
||||
|
||||
/**
|
||||
* Adds a new expression to the repl.
|
||||
*/
|
||||
addReplExpression(name: string): TPromise<void>;
|
||||
|
||||
/**
|
||||
* Removes all repl expressions.
|
||||
*/
|
||||
removeReplExpressions(): void;
|
||||
|
||||
/**
|
||||
* Appends the passed string to the debug repl.
|
||||
*/
|
||||
logToRepl(value: string, sev?: severity): void;
|
||||
|
||||
/**
|
||||
* Adds a new watch expression and evaluates it against the debug adapter.
|
||||
*/
|
||||
addWatchExpression(name?: string): TPromise<void>;
|
||||
|
||||
/**
|
||||
* Renames a watch expression and evaluates it against the debug adapter.
|
||||
*/
|
||||
renameWatchExpression(id: string, newName: string): TPromise<void>;
|
||||
|
||||
/**
|
||||
* Moves a watch expression to a new possition. Used for reordering watch expressions.
|
||||
*/
|
||||
moveWatchExpression(id: string, position: number): void;
|
||||
|
||||
/**
|
||||
* Removes all watch expressions. If id is passed only removes the watch expression with the passed id.
|
||||
*/
|
||||
removeWatchExpressions(id?: string): void;
|
||||
|
||||
/**
|
||||
* Starts debugging. If the configOrName is not passed uses the selected configuration in the debug dropdown.
|
||||
* Also saves all files, manages if compounds are present in the configuration
|
||||
* and calls the startSessionCommand if an adapter registered it.
|
||||
*/
|
||||
startDebugging(root: uri, configOrName?: IConfig | string, noDebug?: boolean): TPromise<any>;
|
||||
|
||||
/**
|
||||
* Creates a new debug process. Depending on the configuration will either 'launch' or 'attach'.
|
||||
*/
|
||||
createProcess(root: uri, config: IConfig): TPromise<IProcess>;
|
||||
|
||||
/**
|
||||
* Find process by ID.
|
||||
*/
|
||||
findProcessByUUID(uuid: string): IProcess | null;
|
||||
|
||||
/**
|
||||
* Restarts a process or creates a new one if there is no active session.
|
||||
*/
|
||||
restartProcess(process: IProcess): TPromise<any>;
|
||||
|
||||
/**
|
||||
* Stops the process. If the process does not exist then stops all processes.
|
||||
*/
|
||||
stopProcess(process: IProcess): TPromise<any>;
|
||||
|
||||
/**
|
||||
* Makes unavailable all sources with the passed uri. Source will appear as grayed out in callstack view.
|
||||
*/
|
||||
sourceIsNotAvailable(uri: uri): void;
|
||||
|
||||
/**
|
||||
* Gets the current debug model.
|
||||
*/
|
||||
getModel(): IModel;
|
||||
|
||||
/**
|
||||
* Gets the current view model.
|
||||
*/
|
||||
getViewModel(): IViewModel;
|
||||
}
|
||||
|
||||
// Editor interfaces
|
||||
export interface IDebugEditorContribution extends IEditorContribution {
|
||||
showHover(range: Range, focus: boolean): TPromise<void>;
|
||||
showBreakpointWidget(lineNumber: number, column: number): void;
|
||||
closeBreakpointWidget(): void;
|
||||
addLaunchConfiguration(): TPromise<any>;
|
||||
}
|
||||
|
||||
// utils
|
||||
|
||||
const _formatPIIRegexp = /{([^}]+)}/g;
|
||||
|
||||
export function formatPII(value: string, excludePII: boolean, args: { [key: string]: string }): string {
|
||||
return value.replace(_formatPIIRegexp, function (match, group) {
|
||||
if (excludePII && group.length > 0 && group[0] !== '_') {
|
||||
return match;
|
||||
}
|
||||
|
||||
return args && args.hasOwnProperty(group) ?
|
||||
args[group] :
|
||||
match;
|
||||
});
|
||||
}
|
||||
1063
src/vs/workbench/parts/debug/common/debugModel.ts
Normal file
1461
src/vs/workbench/parts/debug/common/debugProtocol.d.ts
vendored
Normal file
45
src/vs/workbench/parts/debug/common/debugSource.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import uri from 'vs/base/common/uri';
|
||||
import { DEBUG_SCHEME } from 'vs/workbench/parts/debug/common/debug';
|
||||
|
||||
const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source");
|
||||
|
||||
export class Source {
|
||||
|
||||
public uri: uri;
|
||||
public available: boolean;
|
||||
|
||||
constructor(public raw: DebugProtocol.Source) {
|
||||
if (!raw) {
|
||||
this.raw = { name: UNKNOWN_SOURCE_LABEL };
|
||||
}
|
||||
const path = this.raw.path || this.raw.name;
|
||||
this.available = this.raw.name !== UNKNOWN_SOURCE_LABEL;
|
||||
this.uri = this.raw.sourceReference > 0 ? uri.parse(`${DEBUG_SCHEME}:${path}`) : uri.file(path);
|
||||
}
|
||||
|
||||
public get name() {
|
||||
return this.raw.name;
|
||||
}
|
||||
|
||||
public get origin() {
|
||||
return this.raw.origin;
|
||||
}
|
||||
|
||||
public get presentationHint() {
|
||||
return this.raw.presentationHint;
|
||||
}
|
||||
|
||||
public get reference() {
|
||||
return this.raw.sourceReference;
|
||||
}
|
||||
|
||||
public get inMemory() {
|
||||
return this.uri.toString().indexOf(`${DEBUG_SCHEME}:`) === 0;
|
||||
}
|
||||
}
|
||||
97
src/vs/workbench/parts/debug/common/debugViewModel.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import * as debug from 'vs/workbench/parts/debug/common/debug';
|
||||
|
||||
export class ViewModel implements debug.IViewModel {
|
||||
|
||||
private _focusedStackFrame: debug.IStackFrame;
|
||||
private _focusedProcess: debug.IProcess;
|
||||
private selectedExpression: debug.IExpression;
|
||||
private selectedFunctionBreakpoint: debug.IFunctionBreakpoint;
|
||||
private _onDidFocusProcess: Emitter<debug.IProcess | undefined>;
|
||||
private _onDidFocusStackFrame: Emitter<{ stackFrame: debug.IStackFrame, explicit: boolean }>;
|
||||
private _onDidSelectExpression: Emitter<debug.IExpression>;
|
||||
private _onDidSelectFunctionBreakpoint: Emitter<debug.IFunctionBreakpoint>;
|
||||
private multiProcessView: boolean;
|
||||
public changedWorkbenchViewState: boolean;
|
||||
|
||||
constructor() {
|
||||
this._onDidFocusProcess = new Emitter<debug.IProcess | undefined>();
|
||||
this._onDidFocusStackFrame = new Emitter<{ stackFrame: debug.IStackFrame, explicit: boolean }>();
|
||||
this._onDidSelectExpression = new Emitter<debug.IExpression>();
|
||||
this._onDidSelectFunctionBreakpoint = new Emitter<debug.IFunctionBreakpoint>();
|
||||
this.changedWorkbenchViewState = false;
|
||||
this.multiProcessView = false;
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return 'root';
|
||||
}
|
||||
|
||||
public get focusedProcess(): debug.IProcess {
|
||||
return this._focusedProcess;
|
||||
}
|
||||
|
||||
public get focusedThread(): debug.IThread {
|
||||
return this._focusedStackFrame ? this._focusedStackFrame.thread : (this._focusedProcess ? this._focusedProcess.getAllThreads().pop() : null);
|
||||
}
|
||||
|
||||
public get focusedStackFrame(): debug.IStackFrame {
|
||||
return this._focusedStackFrame;
|
||||
}
|
||||
|
||||
public setFocusedStackFrame(stackFrame: debug.IStackFrame, process: debug.IProcess, explicit: boolean): void {
|
||||
this._focusedStackFrame = stackFrame;
|
||||
if (process !== this._focusedProcess) {
|
||||
this._focusedProcess = process;
|
||||
this._onDidFocusProcess.fire(process);
|
||||
}
|
||||
this._onDidFocusStackFrame.fire({ stackFrame, explicit });
|
||||
}
|
||||
|
||||
public get onDidFocusProcess(): Event<debug.IProcess> {
|
||||
return this._onDidFocusProcess.event;
|
||||
}
|
||||
|
||||
public get onDidFocusStackFrame(): Event<{ stackFrame: debug.IStackFrame, explicit: boolean }> {
|
||||
return this._onDidFocusStackFrame.event;
|
||||
}
|
||||
|
||||
public getSelectedExpression(): debug.IExpression {
|
||||
return this.selectedExpression;
|
||||
}
|
||||
|
||||
public setSelectedExpression(expression: debug.IExpression) {
|
||||
this.selectedExpression = expression;
|
||||
this._onDidSelectExpression.fire(expression);
|
||||
}
|
||||
|
||||
public get onDidSelectExpression(): Event<debug.IExpression> {
|
||||
return this._onDidSelectExpression.event;
|
||||
}
|
||||
|
||||
public getSelectedFunctionBreakpoint(): debug.IFunctionBreakpoint {
|
||||
return this.selectedFunctionBreakpoint;
|
||||
}
|
||||
|
||||
public setSelectedFunctionBreakpoint(functionBreakpoint: debug.IFunctionBreakpoint): void {
|
||||
this.selectedFunctionBreakpoint = functionBreakpoint;
|
||||
this._onDidSelectFunctionBreakpoint.fire(functionBreakpoint);
|
||||
}
|
||||
|
||||
public get onDidSelectFunctionBreakpoint(): Event<debug.IFunctionBreakpoint> {
|
||||
return this._onDidSelectFunctionBreakpoint.event;
|
||||
}
|
||||
|
||||
public isMultiProcessView(): boolean {
|
||||
return this.multiProcessView;
|
||||
}
|
||||
|
||||
public setMultiProcessView(isMultiProcessView: boolean): void {
|
||||
this.multiProcessView = isMultiProcessView;
|
||||
}
|
||||
}
|
||||
117
src/vs/workbench/parts/debug/common/replHistory.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
const MAX_HISTORY_ENTRIES = 50;
|
||||
|
||||
/**
|
||||
* The repl history has the following characteristics:
|
||||
* - the history is stored in local storage up to N items
|
||||
* - every time a expression is evaluated, it is being added to the history
|
||||
* - when starting to navigate in history, the current expression is remembered to be able to go back
|
||||
* - when navigating in history and making changes to any expression, these changes are remembered until a expression is evaluated
|
||||
* - the navigation state is not remembered so that the user always ends up at the end of the history stack when evaluating a expression
|
||||
*/
|
||||
export class ReplHistory {
|
||||
|
||||
private historyPointer: number;
|
||||
private currentExpressionStoredMarkers: boolean;
|
||||
private historyOverwrites: Map<string, string>;
|
||||
|
||||
constructor(private history: string[]) {
|
||||
this.historyPointer = this.history.length;
|
||||
this.currentExpressionStoredMarkers = false;
|
||||
this.historyOverwrites = new Map<string, string>();
|
||||
}
|
||||
|
||||
public next(): string {
|
||||
return this.navigate(false);
|
||||
}
|
||||
|
||||
public previous(): string {
|
||||
return this.navigate(true);
|
||||
}
|
||||
|
||||
private navigate(previous: boolean): string {
|
||||
// validate new pointer
|
||||
let newPointer = -1;
|
||||
if (previous && this.historyPointer > 0 && this.history.length > this.historyPointer - 1) {
|
||||
newPointer = this.historyPointer - 1;
|
||||
} else if (!previous && this.history.length > this.historyPointer + 1) {
|
||||
newPointer = this.historyPointer + 1;
|
||||
}
|
||||
|
||||
if (newPointer >= 0) {
|
||||
|
||||
// remember pointer for next navigation
|
||||
this.historyPointer = newPointer;
|
||||
|
||||
// check for overwrite
|
||||
if (this.historyOverwrites.has(newPointer.toString())) {
|
||||
return this.historyOverwrites.get(newPointer.toString());
|
||||
}
|
||||
|
||||
return this.history[newPointer];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public remember(expression: string, fromPrevious: boolean): void {
|
||||
let previousPointer: number;
|
||||
|
||||
// this method is called after the user has navigated in the history. Therefor we need to
|
||||
// restore the value of the pointer from the point when the user started the navigation.
|
||||
if (fromPrevious) {
|
||||
previousPointer = this.historyPointer + 1;
|
||||
} else {
|
||||
previousPointer = this.historyPointer - 1;
|
||||
}
|
||||
|
||||
// when the user starts to navigate in history, add the current expression to the history
|
||||
// once so that the user can always navigate back to it and does not loose its data.
|
||||
if (previousPointer === this.history.length && !this.currentExpressionStoredMarkers) {
|
||||
this.history.push(expression);
|
||||
this.currentExpressionStoredMarkers = true;
|
||||
}
|
||||
|
||||
// keep edits that are made to history items up until the user actually evaluates a expression
|
||||
else {
|
||||
this.historyOverwrites.set(previousPointer.toString(), expression);
|
||||
}
|
||||
}
|
||||
|
||||
public evaluated(expression: string): void {
|
||||
// clear current expression that was stored previously to support history navigation now on evaluate
|
||||
if (this.currentExpressionStoredMarkers) {
|
||||
this.history.pop();
|
||||
}
|
||||
|
||||
// keep in local history if expression provided and not equal to previous expression stored in history
|
||||
if (expression && (this.history.length === 0 || this.history[this.history.length - 1] !== expression)) {
|
||||
this.history.push(expression);
|
||||
}
|
||||
|
||||
// advance History Pointer to the end
|
||||
this.historyPointer = this.history.length;
|
||||
|
||||
// reset marker
|
||||
this.currentExpressionStoredMarkers = false;
|
||||
|
||||
// reset overwrites
|
||||
this.historyOverwrites.clear();
|
||||
}
|
||||
|
||||
public save(): string[] {
|
||||
// remove current expression from history since it was not evaluated
|
||||
if (this.currentExpressionStoredMarkers) {
|
||||
this.history.pop();
|
||||
}
|
||||
if (this.history.length > MAX_HISTORY_ENTRIES) {
|
||||
this.history = this.history.splice(this.history.length - MAX_HISTORY_ENTRIES, MAX_HISTORY_ENTRIES);
|
||||
}
|
||||
|
||||
return this.history;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!../browser/media/debug.contribution';
|
||||
import 'vs/css!../browser/media/debugHover';
|
||||
import * as nls from 'vs/nls';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { KeybindingsRegistry, IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionRegistryExtensions } from 'vs/workbench/common/actionRegistry';
|
||||
import { ToggleViewletAction, Extensions as ViewletExtensions, ViewletRegistry, ViewletDescriptor } from 'vs/workbench/browser/viewlet';
|
||||
import { TogglePanelAction, Extensions as PanelExtensions, PanelRegistry, PanelDescriptor } from 'vs/workbench/browser/panel';
|
||||
import { VariablesView, WatchExpressionsView, CallStackView, BreakpointsView } from 'vs/workbench/parts/debug/electron-browser/debugViews';
|
||||
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { IDebugService, VIEWLET_ID, REPL_ID, CONTEXT_NOT_IN_DEBUG_MODE, CONTEXT_IN_DEBUG_MODE, INTERNAL_CONSOLE_OPTIONS_SCHEMA } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { DebugEditorModelManager } from 'vs/workbench/parts/debug/browser/debugEditorModelManager';
|
||||
import {
|
||||
StepOverAction, ClearReplAction, FocusReplAction, StepIntoAction, StepOutAction, StartAction, RestartAction, ContinueAction, StopAction, DisconnectAction, PauseAction, AddFunctionBreakpointAction,
|
||||
ConfigureAction, DisableAllBreakpointsAction, EnableAllBreakpointsAction, RemoveAllBreakpointsAction, RunAction, ReapplyBreakpointsAction, SelectAndStartAction
|
||||
} from 'vs/workbench/parts/debug/browser/debugActions';
|
||||
import { DebugActionsWidget } from 'vs/workbench/parts/debug/browser/debugActionsWidget';
|
||||
import * as service from 'vs/workbench/parts/debug/electron-browser/debugService';
|
||||
import { DebugContentProvider } from 'vs/workbench/parts/debug/browser/debugContentProvider';
|
||||
import 'vs/workbench/parts/debug/electron-browser/debugEditorContribution';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import * as debugCommands from 'vs/workbench/parts/debug/electron-browser/debugCommands';
|
||||
import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen';
|
||||
import { StatusBarColorProvider } from 'vs/workbench/parts/debug/electron-browser/statusbarColorProvider';
|
||||
import { ViewLocation, ViewsRegistry } from 'vs/workbench/parts/views/browser/viewsRegistry';
|
||||
|
||||
class OpenDebugViewletAction extends ToggleViewletAction {
|
||||
public static ID = VIEWLET_ID;
|
||||
public static LABEL = nls.localize('toggleDebugViewlet', "Show Debug");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IViewletService viewletService: IViewletService,
|
||||
@IWorkbenchEditorService editorService: IWorkbenchEditorService
|
||||
) {
|
||||
super(id, label, VIEWLET_ID, viewletService, editorService);
|
||||
}
|
||||
}
|
||||
|
||||
class OpenDebugPanelAction extends TogglePanelAction {
|
||||
public static ID = 'workbench.debug.action.toggleRepl';
|
||||
public static LABEL = nls.localize('toggleDebugPanel', "Debug Console");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IPanelService panelService: IPanelService,
|
||||
@IPartService partService: IPartService
|
||||
) {
|
||||
super(id, label, REPL_ID, panelService, partService);
|
||||
}
|
||||
}
|
||||
|
||||
// register viewlet
|
||||
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor(
|
||||
'vs/workbench/parts/debug/browser/debugViewlet',
|
||||
'DebugViewlet',
|
||||
VIEWLET_ID,
|
||||
nls.localize('debug', "Debug"),
|
||||
'debug',
|
||||
40
|
||||
));
|
||||
|
||||
const openViewletKb: IKeybindings = {
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_D
|
||||
};
|
||||
const openPanelKb: IKeybindings = {
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Y
|
||||
};
|
||||
|
||||
// register repl panel
|
||||
Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(new PanelDescriptor(
|
||||
'vs/workbench/parts/debug/electron-browser/repl',
|
||||
'Repl',
|
||||
REPL_ID,
|
||||
nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugPanel' }, 'Debug Console'),
|
||||
'repl',
|
||||
30,
|
||||
OpenDebugPanelAction.ID
|
||||
));
|
||||
Registry.as<PanelRegistry>(PanelExtensions.Panels).setDefaultPanelId(REPL_ID);
|
||||
|
||||
// Register default debug views
|
||||
ViewsRegistry.registerViews([{ id: 'workbench.debug.variablesView', name: nls.localize('variables', "Variables"), ctor: VariablesView, order: 10, size: 40, location: ViewLocation.Debug, canToggleVisibility: true }]);
|
||||
ViewsRegistry.registerViews([{ id: 'workbench.debug.watchExpressionsView', name: nls.localize('watch', "Watch"), ctor: WatchExpressionsView, order: 20, size: 10, location: ViewLocation.Debug, canToggleVisibility: true }]);
|
||||
ViewsRegistry.registerViews([{ id: 'workbench.debug.callStackView', name: nls.localize('callStack', "Call Stack"), ctor: CallStackView, order: 30, size: 30, location: ViewLocation.Debug, canToggleVisibility: true }]);
|
||||
ViewsRegistry.registerViews([{ id: 'workbench.debug.breakPointsView', name: nls.localize('breakpoints', "Breakpoints"), ctor: BreakpointsView, order: 40, size: 20, location: ViewLocation.Debug, canToggleVisibility: true }]);
|
||||
|
||||
// register action to open viewlet
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionRegistryExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDebugPanelAction, OpenDebugPanelAction.ID, OpenDebugPanelAction.LABEL, openPanelKb), 'View: Debug Console', nls.localize('view', "View"));
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDebugViewletAction, OpenDebugViewletAction.ID, OpenDebugViewletAction.LABEL, openViewletKb), 'View: Show Debug', nls.localize('view', "View"));
|
||||
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugEditorModelManager);
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugActionsWidget);
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugContentProvider);
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(StatusBarColorProvider);
|
||||
|
||||
const debugCategory = nls.localize('debugCategory', "Debug");
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(
|
||||
StartAction, StartAction.ID, StartAction.LABEL, { primary: KeyCode.F5 }, CONTEXT_NOT_IN_DEBUG_MODE), 'Debug: Start Debugging', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(StepOverAction, StepOverAction.ID, StepOverAction.LABEL, { primary: KeyCode.F10 }, CONTEXT_IN_DEBUG_MODE), 'Debug: Step Over', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(StepIntoAction, StepIntoAction.ID, StepIntoAction.LABEL, { primary: KeyCode.F11 }, CONTEXT_IN_DEBUG_MODE, KeybindingsRegistry.WEIGHT.workbenchContrib(1)), 'Debug: Step Into', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(StepOutAction, StepOutAction.ID, StepOutAction.LABEL, { primary: KeyMod.Shift | KeyCode.F11 }, CONTEXT_IN_DEBUG_MODE), 'Debug: Step Out', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(RestartAction, RestartAction.ID, RestartAction.LABEL, { primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.F5 }, CONTEXT_IN_DEBUG_MODE), 'Debug: Restart', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(StopAction, StopAction.ID, StopAction.LABEL, { primary: KeyMod.Shift | KeyCode.F5 }, CONTEXT_IN_DEBUG_MODE), 'Debug: Stop', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(DisconnectAction, DisconnectAction.ID, DisconnectAction.LABEL), 'Debug: Disconnect', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ContinueAction, ContinueAction.ID, ContinueAction.LABEL, { primary: KeyCode.F5 }, CONTEXT_IN_DEBUG_MODE), 'Debug: Continue', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(PauseAction, PauseAction.ID, PauseAction.LABEL, { primary: KeyCode.F6 }, CONTEXT_IN_DEBUG_MODE), 'Debug: Pause', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureAction, ConfigureAction.ID, ConfigureAction.LABEL), 'Debug: Open launch.json', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(AddFunctionBreakpointAction, AddFunctionBreakpointAction.ID, AddFunctionBreakpointAction.LABEL), 'Debug: Add Function Breakpoint', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ReapplyBreakpointsAction, ReapplyBreakpointsAction.ID, ReapplyBreakpointsAction.LABEL), 'Debug: Reapply All Breakpoints', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(RunAction, RunAction.ID, RunAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.F5 }, CONTEXT_NOT_IN_DEBUG_MODE), 'Debug: Start Without Debugging', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(RemoveAllBreakpointsAction, RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL), 'Debug: Remove All Breakpoints', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(EnableAllBreakpointsAction, EnableAllBreakpointsAction.ID, EnableAllBreakpointsAction.LABEL), 'Debug: Enable All Breakpoints', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(DisableAllBreakpointsAction, DisableAllBreakpointsAction.ID, DisableAllBreakpointsAction.LABEL), 'Debug: Disable All Breakpoints', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL), 'Debug: Clear Console', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(FocusReplAction, FocusReplAction.ID, FocusReplAction.LABEL), 'Debug: Focus Debug Console', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(SelectAndStartAction, SelectAndStartAction.ID, SelectAndStartAction.LABEL), 'Debug: Select and Start Debugging', debugCategory);
|
||||
|
||||
// Register Quick Open
|
||||
(<IQuickOpenRegistry>Registry.as(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler(
|
||||
new QuickOpenHandlerDescriptor(
|
||||
'vs/workbench/parts/debug/browser/debugQuickOpen',
|
||||
'DebugQuickOpenHandler',
|
||||
'debug ',
|
||||
'inLaunchConfigurationsPicker',
|
||||
nls.localize('debugCommands', "Debug Configuration")
|
||||
)
|
||||
);
|
||||
|
||||
// register service
|
||||
registerSingleton(IDebugService, service.DebugService);
|
||||
|
||||
// Register configuration
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
||||
configurationRegistry.registerConfiguration({
|
||||
id: 'debug',
|
||||
order: 20,
|
||||
title: nls.localize('debugConfigurationTitle', "Debug"),
|
||||
type: 'object',
|
||||
properties: {
|
||||
'debug.allowBreakpointsEverywhere': {
|
||||
type: 'boolean',
|
||||
description: nls.localize({ comment: ['This is the description for a setting'], key: 'allowBreakpointsEverywhere' }, "Allows setting breakpoint in any file"),
|
||||
default: false
|
||||
},
|
||||
'debug.openExplorerOnEnd': {
|
||||
type: 'boolean',
|
||||
description: nls.localize({ comment: ['This is the description for a setting'], key: 'openExplorerOnEnd' }, "Automatically open explorer view on the end of a debug session"),
|
||||
default: false
|
||||
},
|
||||
'debug.inlineValues': {
|
||||
type: 'boolean',
|
||||
description: nls.localize({ comment: ['This is the description for a setting'], key: 'inlineValues' }, "Show variable values inline in editor while debugging"),
|
||||
default: false
|
||||
},
|
||||
'debug.hideActionBar': {
|
||||
type: 'boolean',
|
||||
description: nls.localize({ comment: ['This is the description for a setting'], key: 'hideActionBar' }, "Controls if the floating debug action bar should be hidden"),
|
||||
default: false
|
||||
},
|
||||
'debug.internalConsoleOptions': INTERNAL_CONSOLE_OPTIONS_SCHEMA,
|
||||
'launch': {
|
||||
type: 'object',
|
||||
description: nls.localize({ comment: ['This is the description for a setting'], key: 'launch' }, "Global debug launch configuration. Should be used as an alternative to 'launch.json' that is shared across workspaces"),
|
||||
default: {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
debugCommands.registerCommands();
|
||||
225
src/vs/workbench/parts/debug/electron-browser/debugCommands.ts
Normal file
@@ -0,0 +1,225 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import uri from 'vs/base/common/uri';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { List } from 'vs/base/browser/ui/list/listWidget';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { ICommonCodeEditor } from 'vs/editor/common/editorCommon';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IListService } from 'vs/platform/list/browser/listService';
|
||||
import { IMessageService } from 'vs/platform/message/common/message';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IDebugService, IConfig, IEnablement, CONTEXT_NOT_IN_DEBUG_MODE, CONTEXT_IN_DEBUG_MODE, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_VARIABLES_FOCUSED, EDITOR_CONTRIBUTION_ID, IDebugEditorContribution } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { Expression, Variable, Breakpoint, FunctionBreakpoint } from 'vs/workbench/parts/debug/common/debugModel';
|
||||
import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/parts/extensions/common/extensions';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
|
||||
export function registerCommands(): void {
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: '_workbench.startDebug',
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
handler(accessor: ServicesAccessor, configurationOrName: IConfig | string, folderUri?: uri) {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
if (!configurationOrName) {
|
||||
configurationOrName = debugService.getConfigurationManager().selectedName;
|
||||
}
|
||||
|
||||
if (!folderUri) {
|
||||
const selectedLaunch = debugService.getConfigurationManager().selectedLaunch;
|
||||
folderUri = selectedLaunch ? selectedLaunch.workspaceUri : undefined;
|
||||
}
|
||||
|
||||
if (typeof configurationOrName === 'string') {
|
||||
debugService.startDebugging(folderUri, configurationOrName);
|
||||
} else {
|
||||
debugService.createProcess(folderUri, configurationOrName);
|
||||
}
|
||||
},
|
||||
when: CONTEXT_NOT_IN_DEBUG_MODE,
|
||||
primary: undefined
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'workbench.customDebugRequest',
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
handler(accessor: ServicesAccessor, request: string, requestArgs: any) {
|
||||
const process = accessor.get(IDebugService).getViewModel().focusedProcess;
|
||||
if (process) {
|
||||
return process.session.custom(request, requestArgs);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
when: CONTEXT_IN_DEBUG_MODE,
|
||||
primary: undefined
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'debug.logToDebugConsole',
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
handler(accessor: ServicesAccessor, value: string) {
|
||||
if (typeof value === 'string') {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
// Use warning as severity to get the orange color for messages coming from the debug extension
|
||||
debugService.logToRepl(value, severity.Warning);
|
||||
}
|
||||
},
|
||||
when: undefined,
|
||||
primary: undefined
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'debug.toggleBreakpoint',
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(5),
|
||||
when: CONTEXT_BREAKPOINTS_FOCUSED,
|
||||
primary: KeyCode.Space,
|
||||
handler: (accessor) => {
|
||||
const listService = accessor.get(IListService);
|
||||
const debugService = accessor.get(IDebugService);
|
||||
const focused = listService.getFocused();
|
||||
|
||||
// Tree only
|
||||
if (!(focused instanceof List)) {
|
||||
const tree = focused;
|
||||
const element = <IEnablement>tree.getFocus();
|
||||
debugService.enableOrDisableBreakpoints(!element.enabled, element).done(null, errors.onUnexpectedError);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'debug.renameWatchExpression',
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(5),
|
||||
when: CONTEXT_WATCH_EXPRESSIONS_FOCUSED,
|
||||
primary: KeyCode.F2,
|
||||
mac: { primary: KeyCode.Enter },
|
||||
handler: (accessor) => {
|
||||
const listService = accessor.get(IListService);
|
||||
const debugService = accessor.get(IDebugService);
|
||||
const focused = listService.getFocused();
|
||||
|
||||
// Tree only
|
||||
if (!(focused instanceof List)) {
|
||||
const element = focused.getFocus();
|
||||
if (element instanceof Expression) {
|
||||
debugService.getViewModel().setSelectedExpression(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'debug.setVariable',
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(5),
|
||||
when: CONTEXT_VARIABLES_FOCUSED,
|
||||
primary: KeyCode.F2,
|
||||
mac: { primary: KeyCode.Enter },
|
||||
handler: (accessor) => {
|
||||
const listService = accessor.get(IListService);
|
||||
const debugService = accessor.get(IDebugService);
|
||||
const focused = listService.getFocused();
|
||||
|
||||
// Tree only
|
||||
if (!(focused instanceof List)) {
|
||||
const element = focused.getFocus();
|
||||
if (element instanceof Variable) {
|
||||
debugService.getViewModel().setSelectedExpression(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'debug.removeWatchExpression',
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
when: CONTEXT_WATCH_EXPRESSIONS_FOCUSED,
|
||||
primary: KeyCode.Delete,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace },
|
||||
handler: (accessor) => {
|
||||
const listService = accessor.get(IListService);
|
||||
const debugService = accessor.get(IDebugService);
|
||||
const focused = listService.getFocused();
|
||||
|
||||
// Tree only
|
||||
if (!(focused instanceof List)) {
|
||||
const element = focused.getFocus();
|
||||
if (element instanceof Expression) {
|
||||
debugService.removeWatchExpressions(element.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'debug.removeBreakpoint',
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
when: CONTEXT_BREAKPOINTS_FOCUSED,
|
||||
primary: KeyCode.Delete,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace },
|
||||
handler: (accessor) => {
|
||||
const listService = accessor.get(IListService);
|
||||
const debugService = accessor.get(IDebugService);
|
||||
const focused = listService.getFocused();
|
||||
|
||||
// Tree only
|
||||
if (!(focused instanceof List)) {
|
||||
const element = focused.getFocus();
|
||||
if (element instanceof Breakpoint) {
|
||||
debugService.removeBreakpoints(element.getId()).done(null, errors.onUnexpectedError);
|
||||
} else if (element instanceof FunctionBreakpoint) {
|
||||
debugService.removeFunctionBreakpoints(element.getId()).done(null, errors.onUnexpectedError);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'debug.installAdditionalDebuggers',
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
when: undefined,
|
||||
primary: undefined,
|
||||
handler: (accessor) => {
|
||||
const viewletService = accessor.get(IViewletService);
|
||||
return viewletService.openViewlet(EXTENSIONS_VIEWLET_ID, true)
|
||||
.then(viewlet => viewlet as IExtensionsViewlet)
|
||||
.then(viewlet => {
|
||||
viewlet.search('tag:debuggers @sort:installs');
|
||||
viewlet.focus();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'debug.addConfiguration',
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
when: undefined,
|
||||
primary: undefined,
|
||||
handler: (accessor, workspaceUri: string) => {
|
||||
const manager = accessor.get(IDebugService).getConfigurationManager();
|
||||
if (!accessor.get(IWorkspaceContextService).hasWorkspace()) {
|
||||
accessor.get(IMessageService).show(severity.Info, nls.localize('noFolderDebugConfig', "Please first open a folder in order to do advanced debug configuration."));
|
||||
return TPromise.as(null);
|
||||
}
|
||||
const launch = manager.getLaunches().filter(l => l.workspaceUri.toString() === workspaceUri).pop() || manager.selectedLaunch;
|
||||
|
||||
return launch.openConfigFile(false).done(editor => {
|
||||
if (editor) {
|
||||
const codeEditor = <ICommonCodeEditor>editor.getControl();
|
||||
if (codeEditor) {
|
||||
return codeEditor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).addLaunchConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,593 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { first } from 'vs/base/common/arrays';
|
||||
import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import uri from 'vs/base/common/uri';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import * as paths from 'vs/base/common/paths';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import { IModel, isCommonCodeEditor } from 'vs/editor/common/editorCommon';
|
||||
import { IEditor } from 'vs/platform/editor/common/editor';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import * as extensionsRegistry from 'vs/platform/extensions/common/extensionsRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IDebugConfigurationProvider, IRawAdapter, ICompound, IDebugConfiguration, DEBUG_SCHEME, IConfig, IEnvConfig, IGlobalConfig, IConfigurationManager, ILaunch } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { Adapter } from 'vs/workbench/parts/debug/node/debugAdapter';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
|
||||
// debuggers extension point
|
||||
export const debuggersExtPoint = extensionsRegistry.ExtensionsRegistry.registerExtensionPoint<IRawAdapter[]>('debuggers', [], {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers', 'Contributes debug adapters.'),
|
||||
type: 'array',
|
||||
defaultSnippets: [{ body: [{ type: '', extensions: [] }] }],
|
||||
items: {
|
||||
type: 'object',
|
||||
defaultSnippets: [{ body: { type: '', program: '', runtime: '', enableBreakpointsFor: { languageIds: [''] } } }],
|
||||
properties: {
|
||||
type: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.type', "Unique identifier for this debug adapter."),
|
||||
type: 'string'
|
||||
},
|
||||
label: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.label', "Display name for this debug adapter."),
|
||||
type: 'string'
|
||||
},
|
||||
program: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.program', "Path to the debug adapter program. Path is either absolute or relative to the extension folder."),
|
||||
type: 'string'
|
||||
},
|
||||
args: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.args', "Optional arguments to pass to the adapter."),
|
||||
type: 'array'
|
||||
},
|
||||
runtime: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.runtime', "Optional runtime in case the program attribute is not an executable but requires a runtime."),
|
||||
type: 'string'
|
||||
},
|
||||
runtimeArgs: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.runtimeArgs', "Optional runtime arguments."),
|
||||
type: 'array'
|
||||
},
|
||||
variables: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.variables', "Mapping from interactive variables (e.g ${action.pickProcess}) in `launch.json` to a command."),
|
||||
type: 'object'
|
||||
},
|
||||
initialConfigurations: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.initialConfigurations', "Configurations for generating the initial \'launch.json\'."),
|
||||
type: ['array', 'string'],
|
||||
},
|
||||
languages: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.languages', "List of languages for which the debug extension could be considered the \"default debugger\"."),
|
||||
type: 'array'
|
||||
},
|
||||
adapterExecutableCommand: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.adapterExecutableCommand', "If specified VS Code will call this command to determine the executable path of the debug adapter and the arguments to pass."),
|
||||
type: 'string'
|
||||
},
|
||||
startSessionCommand: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.startSessionCommand', "If specified VS Code will call this command for the \"debug\" or \"run\" actions targeted for this extension."),
|
||||
type: 'string'
|
||||
},
|
||||
configurationSnippets: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.configurationSnippets', "Snippets for adding new configurations in \'launch.json\'."),
|
||||
type: 'array'
|
||||
},
|
||||
configurationAttributes: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.configurationAttributes', "JSON schema configurations for validating \'launch.json\'."),
|
||||
type: 'object'
|
||||
},
|
||||
windows: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.windows', "Windows specific settings."),
|
||||
type: 'object',
|
||||
properties: {
|
||||
runtime: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.windows.runtime', "Runtime used for Windows."),
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
osx: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.osx', "OS X specific settings."),
|
||||
type: 'object',
|
||||
properties: {
|
||||
runtime: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.osx.runtime', "Runtime used for OSX."),
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
linux: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.linux', "Linux specific settings."),
|
||||
type: 'object',
|
||||
properties: {
|
||||
runtime: {
|
||||
description: nls.localize('vscode.extension.contributes.debuggers.linux.runtime', "Runtime used for Linux."),
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
interface IRawBreakpointContribution {
|
||||
language: string;
|
||||
}
|
||||
|
||||
// breakpoints extension point #9037
|
||||
const breakpointsExtPoint = extensionsRegistry.ExtensionsRegistry.registerExtensionPoint<IRawBreakpointContribution[]>('breakpoints', [], {
|
||||
description: nls.localize('vscode.extension.contributes.breakpoints', 'Contributes breakpoints.'),
|
||||
type: 'array',
|
||||
defaultSnippets: [{ body: [{ language: '' }] }],
|
||||
items: {
|
||||
type: 'object',
|
||||
defaultSnippets: [{ body: { language: '' } }],
|
||||
properties: {
|
||||
language: {
|
||||
description: nls.localize('vscode.extension.contributes.breakpoints.language', "Allow breakpoints for this language."),
|
||||
type: 'string'
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// debug general schema
|
||||
|
||||
export const schemaId = 'vscode://schemas/launch';
|
||||
const defaultCompound: ICompound = { name: 'Compound', configurations: [] };
|
||||
const schema: IJSONSchema = {
|
||||
id: schemaId,
|
||||
type: 'object',
|
||||
title: nls.localize('app.launch.json.title', "Launch"),
|
||||
required: ['version', 'configurations'],
|
||||
default: { version: '0.2.0', configurations: [], compounds: [] },
|
||||
properties: {
|
||||
version: {
|
||||
type: 'string',
|
||||
description: nls.localize('app.launch.json.version', "Version of this file format."),
|
||||
default: '0.2.0'
|
||||
},
|
||||
configurations: {
|
||||
type: 'array',
|
||||
description: nls.localize('app.launch.json.configurations', "List of configurations. Add new configurations or edit existing ones by using IntelliSense."),
|
||||
items: {
|
||||
defaultSnippets: [],
|
||||
'type': 'object',
|
||||
oneOf: []
|
||||
}
|
||||
},
|
||||
compounds: {
|
||||
type: 'array',
|
||||
description: nls.localize('app.launch.json.compounds', "List of compounds. Each compound references multiple configurations which will get launched together."),
|
||||
items: {
|
||||
type: 'object',
|
||||
required: ['name', 'configurations'],
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
description: nls.localize('app.launch.json.compound.name', "Name of compound. Appears in the launch configuration drop down menu.")
|
||||
},
|
||||
configurations: {
|
||||
type: 'array',
|
||||
default: [],
|
||||
items: {
|
||||
type: 'string'
|
||||
},
|
||||
description: nls.localize('app.launch.json.compounds.configurations', "Names of configurations that will be started as part of this compound.")
|
||||
}
|
||||
},
|
||||
default: defaultCompound
|
||||
},
|
||||
default: [
|
||||
defaultCompound
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const jsonRegistry = <IJSONContributionRegistry>Registry.as(JSONExtensions.JSONContribution);
|
||||
jsonRegistry.registerSchema(schemaId, schema);
|
||||
const DEBUG_SELECTED_CONFIG_NAME_KEY = 'debug.selectedconfigname';
|
||||
const DEBUG_SELECTED_ROOT = 'debug.selectedroot';
|
||||
|
||||
export class ConfigurationManager implements IConfigurationManager {
|
||||
private adapters: Adapter[];
|
||||
private breakpointModeIdsSet = new Set<string>();
|
||||
private launches: ILaunch[];
|
||||
private _selectedName: string;
|
||||
private _selectedLaunch: ILaunch;
|
||||
private toDispose: IDisposable[];
|
||||
private _onDidSelectConfigurationName = new Emitter<void>();
|
||||
private _providers: Map<number, IDebugConfigurationProvider>;
|
||||
|
||||
constructor(
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService,
|
||||
@IFileService private fileService: IFileService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService,
|
||||
@IConfigurationResolverService private configurationResolverService: IConfigurationResolverService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@ICommandService private commandService: ICommandService,
|
||||
@IStorageService private storageService: IStorageService,
|
||||
@ILifecycleService lifecycleService: ILifecycleService,
|
||||
) {
|
||||
this._providers = new Map<number, IDebugConfigurationProvider>();
|
||||
this.adapters = [];
|
||||
this.toDispose = [];
|
||||
this.registerListeners(lifecycleService);
|
||||
this.initLaunches();
|
||||
const previousSelectedRoot = this.storageService.get(DEBUG_SELECTED_ROOT, StorageScope.WORKSPACE);
|
||||
const filtered = this.launches.filter(l => l.workspaceUri.toString() === previousSelectedRoot);
|
||||
const launchToSelect = filtered.length ? filtered[0] : this.launches.length ? this.launches[0] : undefined;
|
||||
this.selectConfiguration(launchToSelect, this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE));
|
||||
}
|
||||
|
||||
public registerDebugConfigurationProvider(handle: number, debugConfigurationProvider: IDebugConfigurationProvider): void {
|
||||
if (!debugConfigurationProvider) {
|
||||
return;
|
||||
}
|
||||
this._providers.set(handle, debugConfigurationProvider);
|
||||
const adapter = this.getAdapter(debugConfigurationProvider.type);
|
||||
if (adapter) {
|
||||
adapter.hasConfigurationProvider = true;
|
||||
}
|
||||
}
|
||||
|
||||
public unregisterDebugConfigurationProvider(handle: number): boolean {
|
||||
return this._providers.delete(handle);
|
||||
}
|
||||
|
||||
public resolveDebugConfiguration(folderUri: uri | undefined, debugConfiguration: any): TPromise<any> {
|
||||
|
||||
// collect all candidates
|
||||
const providers: IDebugConfigurationProvider[] = [];
|
||||
this._providers.forEach(provider => {
|
||||
if (provider.type === debugConfiguration.type && provider.resolveDebugConfiguration) {
|
||||
providers.push(provider);
|
||||
}
|
||||
});
|
||||
|
||||
// pipe the config through the promises sequentially
|
||||
return providers.reduce((promise, provider) => {
|
||||
return promise.then(config => {
|
||||
return provider.resolveDebugConfiguration(folderUri, config);
|
||||
});
|
||||
}, TPromise.as(debugConfiguration));
|
||||
}
|
||||
|
||||
public provideDebugConfigurations(folderUri: uri | undefined, type: string): TPromise<any[]> {
|
||||
|
||||
// collect all candidates
|
||||
const configs: TPromise<any[]>[] = [];
|
||||
this._providers.forEach(provider => {
|
||||
if (provider.type === type && provider.provideDebugConfigurations) {
|
||||
configs.push(provider.provideDebugConfigurations(folderUri));
|
||||
}
|
||||
});
|
||||
|
||||
// combine all configs into one array
|
||||
return TPromise.join(configs).then(results => {
|
||||
return [].concat.apply([], results);
|
||||
});
|
||||
}
|
||||
|
||||
private registerListeners(lifecycleService: ILifecycleService): void {
|
||||
debuggersExtPoint.setHandler((extensions) => {
|
||||
extensions.forEach(extension => {
|
||||
extension.value.forEach(rawAdapter => {
|
||||
if (!rawAdapter.type || (typeof rawAdapter.type !== 'string')) {
|
||||
extension.collector.error(nls.localize('debugNoType', "Debug adapter 'type' can not be omitted and must be of type 'string'."));
|
||||
}
|
||||
if (rawAdapter.enableBreakpointsFor) {
|
||||
rawAdapter.enableBreakpointsFor.languageIds.forEach(modeId => {
|
||||
this.breakpointModeIdsSet.add(modeId);
|
||||
});
|
||||
}
|
||||
|
||||
const duplicate = this.adapters.filter(a => a.type === rawAdapter.type).pop();
|
||||
if (duplicate) {
|
||||
duplicate.merge(rawAdapter, extension.description);
|
||||
} else {
|
||||
this.adapters.push(this.instantiationService.createInstance(Adapter, rawAdapter, extension.description));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// update the schema to include all attributes, snippets and types from extensions.
|
||||
this.adapters.forEach(adapter => {
|
||||
const items = (<IJSONSchema>schema.properties['configurations'].items);
|
||||
const schemaAttributes = adapter.getSchemaAttributes();
|
||||
if (schemaAttributes) {
|
||||
items.oneOf.push(...schemaAttributes);
|
||||
}
|
||||
const configurationSnippets = adapter.configurationSnippets;
|
||||
if (configurationSnippets) {
|
||||
items.defaultSnippets.push(...configurationSnippets);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
breakpointsExtPoint.setHandler(extensions => {
|
||||
extensions.forEach(ext => {
|
||||
ext.value.forEach(breakpoints => {
|
||||
this.breakpointModeIdsSet.add(breakpoints.language);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this.toDispose.push(this.contextService.onDidChangeWorkspaceRoots(() => {
|
||||
this.initLaunches();
|
||||
const toSelect = this.selectedLaunch && this.selectedLaunch.getConfigurationNames().length ? this.selectedLaunch : first(this.launches, l => !!l.getConfigurationNames().length, this.launches.length ? this.launches[0] : undefined);
|
||||
this.selectConfiguration(toSelect);
|
||||
}));
|
||||
|
||||
this.toDispose.push(lifecycleService.onShutdown(this.store, this));
|
||||
}
|
||||
|
||||
private initLaunches(): void {
|
||||
const workspace = this.contextService.getWorkspace();
|
||||
this.launches = workspace ? workspace.roots.map(root => this.instantiationService.createInstance(Launch, this, root)) : [];
|
||||
if (this.launches.indexOf(this._selectedLaunch) === -1) {
|
||||
this._selectedLaunch = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
public getLaunches(): ILaunch[] {
|
||||
return this.launches;
|
||||
}
|
||||
|
||||
public get selectedLaunch(): ILaunch {
|
||||
return this._selectedLaunch;
|
||||
}
|
||||
|
||||
public get selectedName(): string {
|
||||
return this._selectedName;
|
||||
}
|
||||
|
||||
public get onDidSelectConfiguration(): Event<void> {
|
||||
return this._onDidSelectConfigurationName.event;
|
||||
}
|
||||
|
||||
public selectConfiguration(launch: ILaunch, name?: string, debugStarted?: boolean): void {
|
||||
const previousLaunch = this._selectedLaunch;
|
||||
const previousName = this._selectedName;
|
||||
|
||||
this._selectedLaunch = launch;
|
||||
const names = launch ? launch.getConfigurationNames() : [];
|
||||
if (name && names.indexOf(name) >= 0) {
|
||||
this._selectedName = name;
|
||||
}
|
||||
if (names.indexOf(this.selectedName) === -1) {
|
||||
this._selectedName = names.length ? names[0] : undefined;
|
||||
}
|
||||
|
||||
if (this.selectedLaunch !== previousLaunch || this.selectedName !== previousName) {
|
||||
this._onDidSelectConfigurationName.fire();
|
||||
}
|
||||
}
|
||||
|
||||
public canSetBreakpointsIn(model: IModel): boolean {
|
||||
if (model.uri.scheme !== Schemas.file && model.uri.scheme !== DEBUG_SCHEME) {
|
||||
return false;
|
||||
}
|
||||
if (this.configurationService.getConfiguration<IDebugConfiguration>('debug').allowBreakpointsEverywhere) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const modeId = model ? model.getLanguageIdentifier().language : null;
|
||||
|
||||
return this.breakpointModeIdsSet.has(modeId);
|
||||
}
|
||||
|
||||
public getAdapter(type: string): Adapter {
|
||||
return this.adapters.filter(adapter => strings.equalsIgnoreCase(adapter.type, type)).pop();
|
||||
}
|
||||
|
||||
public guessAdapter(type?: string): TPromise<Adapter> {
|
||||
if (type) {
|
||||
const adapter = this.getAdapter(type);
|
||||
return TPromise.as(adapter);
|
||||
}
|
||||
|
||||
const editor = this.editorService.getActiveEditor();
|
||||
if (editor) {
|
||||
const codeEditor = editor.getControl();
|
||||
if (isCommonCodeEditor(codeEditor)) {
|
||||
const model = codeEditor.getModel();
|
||||
const language = model ? model.getLanguageIdentifier().language : undefined;
|
||||
const adapters = this.adapters.filter(a => a.languages && a.languages.indexOf(language) >= 0);
|
||||
if (adapters.length === 1) {
|
||||
return TPromise.as(adapters[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.quickOpenService.pick([...this.adapters.filter(a => a.hasInitialConfiguration() || a.hasConfigurationProvider), { label: 'More...', separator: { border: true } }], { placeHolder: nls.localize('selectDebug', "Select Environment") })
|
||||
.then(picked => {
|
||||
if (picked instanceof Adapter) {
|
||||
return picked;
|
||||
}
|
||||
if (picked) {
|
||||
this.commandService.executeCommand('debug.installAdditionalDebuggers');
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
public getStartSessionCommand(type?: string): TPromise<{ command: string, type: string }> {
|
||||
return this.guessAdapter(type).then(adapter => {
|
||||
if (adapter) {
|
||||
return {
|
||||
command: adapter.startSessionCommand,
|
||||
type: adapter.type
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
private store(): void {
|
||||
this.storageService.store(DEBUG_SELECTED_CONFIG_NAME_KEY, this.selectedName, StorageScope.WORKSPACE);
|
||||
if (this._selectedLaunch) {
|
||||
this.storageService.store(DEBUG_SELECTED_ROOT, this._selectedLaunch.workspaceUri.toString(), StorageScope.WORKSPACE);
|
||||
}
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.toDispose = dispose(this.toDispose);
|
||||
}
|
||||
}
|
||||
|
||||
class Launch implements ILaunch {
|
||||
|
||||
public name: string;
|
||||
|
||||
constructor(
|
||||
private configurationManager: ConfigurationManager,
|
||||
public workspaceUri: uri,
|
||||
@IFileService private fileService: IFileService,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IConfigurationResolverService private configurationResolverService: IConfigurationResolverService,
|
||||
) {
|
||||
this.name = paths.basename(this.workspaceUri.fsPath);
|
||||
}
|
||||
|
||||
public getCompound(name: string): ICompound {
|
||||
const config = this.configurationService.getConfiguration<IGlobalConfig>('launch', { resource: this.workspaceUri });
|
||||
if (!config || !config.compounds) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return config.compounds.filter(compound => compound.name === name).pop();
|
||||
}
|
||||
|
||||
public getConfigurationNames(): string[] {
|
||||
const config = this.configurationService.getConfiguration<IGlobalConfig>('launch', { resource: this.workspaceUri });
|
||||
if (!config || !config.configurations) {
|
||||
return [];
|
||||
} else {
|
||||
const names = config.configurations.filter(cfg => cfg && typeof cfg.name === 'string').map(cfg => cfg.name);
|
||||
if (names.length > 0 && config.compounds) {
|
||||
if (config.compounds) {
|
||||
names.push(...config.compounds.filter(compound => typeof compound.name === 'string' && compound.configurations && compound.configurations.length)
|
||||
.map(compound => compound.name));
|
||||
}
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
}
|
||||
|
||||
public getConfiguration(name: string): IConfig {
|
||||
const config = this.configurationService.getConfiguration<IGlobalConfig>('launch', { resource: this.workspaceUri });
|
||||
if (!config || !config.configurations) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return config.configurations.filter(config => config && config.name === name).shift();
|
||||
}
|
||||
|
||||
public resolveConfiguration(config: IConfig): TPromise<IConfig> {
|
||||
const result = objects.deepClone(config) as IConfig;
|
||||
// Set operating system specific properties #1873
|
||||
const setOSProperties = (flag: boolean, osConfig: IEnvConfig) => {
|
||||
if (flag && osConfig) {
|
||||
Object.keys(osConfig).forEach(key => {
|
||||
result[key] = osConfig[key];
|
||||
});
|
||||
}
|
||||
};
|
||||
setOSProperties(isWindows, result.windows);
|
||||
setOSProperties(isMacintosh, result.osx);
|
||||
setOSProperties(isLinux, result.linux);
|
||||
|
||||
// massage configuration attributes - append workspace path to relatvie paths, substitute variables in paths.
|
||||
Object.keys(result).forEach(key => {
|
||||
result[key] = this.configurationResolverService.resolveAny(this.workspaceUri, result[key]);
|
||||
});
|
||||
|
||||
const adapter = this.configurationManager.getAdapter(result.type);
|
||||
return this.configurationResolverService.resolveInteractiveVariables(result, adapter ? adapter.variables : null);
|
||||
}
|
||||
|
||||
public get uri(): uri {
|
||||
return uri.file(paths.join(this.workspaceUri.fsPath, '/.vscode/launch.json'));
|
||||
}
|
||||
|
||||
public openConfigFile(sideBySide: boolean, type?: string): TPromise<IEditor> {
|
||||
const resource = this.uri;
|
||||
let configFileCreated = false;
|
||||
|
||||
return this.fileService.resolveContent(resource).then(content => content, err => {
|
||||
|
||||
// launch.json not found: create one by collecting launch configs from debugConfigProviders
|
||||
|
||||
return this.configurationManager.guessAdapter(type).then(adapter => {
|
||||
if (adapter) {
|
||||
return this.configurationManager.provideDebugConfigurations(this.workspaceUri, adapter.type).then(initialConfigs => {
|
||||
return adapter.getInitialConfigurationContent(this.workspaceUri, initialConfigs);
|
||||
});
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}).then(content => {
|
||||
|
||||
if (!content) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
configFileCreated = true;
|
||||
return this.fileService.updateContent(resource, content).then(() => {
|
||||
// convert string into IContent; see #32135
|
||||
return { value: content };
|
||||
});
|
||||
});
|
||||
}).then(content => {
|
||||
if (!content) {
|
||||
return undefined;
|
||||
}
|
||||
const index = content.value.indexOf(`"${this.configurationManager.selectedName}"`);
|
||||
let startLineNumber = 1;
|
||||
for (let i = 0; i < index; i++) {
|
||||
if (content.value.charAt(i) === '\n') {
|
||||
startLineNumber++;
|
||||
}
|
||||
}
|
||||
const selection = startLineNumber > 1 ? { startLineNumber, startColumn: 4 } : undefined;
|
||||
|
||||
return this.editorService.openEditor({
|
||||
resource: resource,
|
||||
options: {
|
||||
forceOpen: true,
|
||||
selection,
|
||||
pinned: configFileCreated, // pin only if config file is created #8727
|
||||
revealIfVisible: true
|
||||
},
|
||||
}, sideBySide);
|
||||
}, (error) => {
|
||||
throw new Error(nls.localize('DebugConfig.failed', "Unable to create 'launch.json' file inside the '.vscode' folder ({0}).", error));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,620 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import * as env from 'vs/base/common/platform';
|
||||
import uri from 'vs/base/common/uri';
|
||||
import { visit } from 'vs/base/common/json';
|
||||
import { Constants } from 'vs/editor/common/core/uint';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { StandardTokenType } from 'vs/editor/common/modes';
|
||||
import { DEFAULT_WORD_REGEXP } from 'vs/editor/common/model/wordHelper';
|
||||
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import { IDecorationOptions, IModelDecorationOptions, IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/editorCommon';
|
||||
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextMenuService, ContextSubMenu } from 'vs/platform/contextview/browser/contextView';
|
||||
import { DebugHoverWidget } from 'vs/workbench/parts/debug/electron-browser/debugHover';
|
||||
import { RemoveBreakpointAction, EditConditionalBreakpointAction, EnableBreakpointAction, DisableBreakpointAction, AddConditionalBreakpointAction } from 'vs/workbench/parts/debug/browser/debugActions';
|
||||
import { IDebugEditorContribution, IDebugService, State, IBreakpoint, EDITOR_CONTRIBUTION_ID, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, IStackFrame, IDebugConfiguration, IExpression, IExceptionInfo } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { BreakpointWidget } from 'vs/workbench/parts/debug/browser/breakpointWidget';
|
||||
import { ExceptionWidget } from 'vs/workbench/parts/debug/browser/exceptionWidget';
|
||||
import { FloatingClickWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets';
|
||||
import { IListService } from 'vs/platform/list/browser/listService';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { CoreEditingCommands } from 'vs/editor/common/controller/coreCommands';
|
||||
import { first } from 'vs/base/common/arrays';
|
||||
|
||||
const HOVER_DELAY = 300;
|
||||
const LAUNCH_JSON_REGEX = /launch\.json$/;
|
||||
const REMOVE_INLINE_VALUES_DELAY = 100;
|
||||
const INLINE_VALUE_DECORATION_KEY = 'inlinevaluedecoration';
|
||||
const MAX_NUM_INLINE_VALUES = 100; // JS Global scope can have 700+ entries. We want to limit ourselves for perf reasons
|
||||
const MAX_INLINE_DECORATOR_LENGTH = 150; // Max string length of each inline decorator when debugging. If exceeded ... is added
|
||||
const MAX_TOKENIZATION_LINE_LEN = 500; // If line is too long, then inline values for the line are skipped
|
||||
|
||||
@editorContribution
|
||||
export class DebugEditorContribution implements IDebugEditorContribution {
|
||||
|
||||
private toDispose: lifecycle.IDisposable[];
|
||||
private hoverWidget: DebugHoverWidget;
|
||||
private showHoverScheduler: RunOnceScheduler;
|
||||
private hideHoverScheduler: RunOnceScheduler;
|
||||
private removeInlineValuesScheduler: RunOnceScheduler;
|
||||
private hoverRange: Range;
|
||||
|
||||
private breakpointHintDecoration: string[];
|
||||
private breakpointWidget: BreakpointWidget;
|
||||
private breakpointWidgetVisible: IContextKey<boolean>;
|
||||
private wordToLineNumbersMap: Map<string, Position[]>;
|
||||
|
||||
private exceptionWidget: ExceptionWidget;
|
||||
|
||||
private configurationWidget: FloatingClickWidget;
|
||||
|
||||
constructor(
|
||||
private editor: ICodeEditor,
|
||||
@IDebugService private debugService: IDebugService,
|
||||
@IContextMenuService private contextMenuService: IContextMenuService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@ICommandService private commandService: ICommandService,
|
||||
@ICodeEditorService private codeEditorService: ICodeEditorService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService,
|
||||
@IListService listService: IListService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IThemeService themeService: IThemeService
|
||||
) {
|
||||
this.breakpointHintDecoration = [];
|
||||
this.hoverWidget = new DebugHoverWidget(this.editor, this.debugService, listService, this.instantiationService, themeService);
|
||||
this.toDispose = [];
|
||||
this.showHoverScheduler = new RunOnceScheduler(() => this.showHover(this.hoverRange, false), HOVER_DELAY);
|
||||
this.hideHoverScheduler = new RunOnceScheduler(() => this.hoverWidget.hide(), HOVER_DELAY);
|
||||
this.removeInlineValuesScheduler = new RunOnceScheduler(() => this.editor.removeDecorations(INLINE_VALUE_DECORATION_KEY), REMOVE_INLINE_VALUES_DELAY);
|
||||
this.registerListeners();
|
||||
this.breakpointWidgetVisible = CONTEXT_BREAKPOINT_WIDGET_VISIBLE.bindTo(contextKeyService);
|
||||
this.updateConfigurationWidgetVisibility();
|
||||
this.codeEditorService.registerDecorationType(INLINE_VALUE_DECORATION_KEY, {});
|
||||
this.toggleExceptionWidget();
|
||||
}
|
||||
|
||||
private getContextMenuActions(breakpoints: IBreakpoint[], uri: uri, lineNumber: number): TPromise<(IAction | ContextSubMenu)[]> {
|
||||
const actions: (IAction | ContextSubMenu)[] = [];
|
||||
if (breakpoints.length === 1) {
|
||||
actions.push(this.instantiationService.createInstance(RemoveBreakpointAction, RemoveBreakpointAction.ID, RemoveBreakpointAction.LABEL));
|
||||
actions.push(this.instantiationService.createInstance(EditConditionalBreakpointAction, EditConditionalBreakpointAction.ID, EditConditionalBreakpointAction.LABEL, this.editor));
|
||||
if (breakpoints[0].enabled) {
|
||||
actions.push(this.instantiationService.createInstance(DisableBreakpointAction, DisableBreakpointAction.ID, DisableBreakpointAction.LABEL));
|
||||
} else {
|
||||
actions.push(this.instantiationService.createInstance(EnableBreakpointAction, EnableBreakpointAction.ID, EnableBreakpointAction.LABEL));
|
||||
}
|
||||
} else if (breakpoints.length > 1) {
|
||||
const sorted = breakpoints.sort((first, second) => first.column - second.column);
|
||||
actions.push(new ContextSubMenu(nls.localize('removeBreakpoints', "Remove Breakpoints"), sorted.map(bp => new Action(
|
||||
'removeColumnBreakpoint',
|
||||
bp.column ? nls.localize('removeBreakpointOnColumn', "Remove Breakpoint on Column {0}", bp.column) : nls.localize('removeLineBreakpoint', "Remove Line Breakpoint"),
|
||||
null,
|
||||
true,
|
||||
() => this.debugService.removeBreakpoints(bp.getId())
|
||||
))));
|
||||
|
||||
actions.push(new ContextSubMenu(nls.localize('editBreakpoints', "Edit Breakpoints"), sorted.map(bp =>
|
||||
new Action('editBreakpoint',
|
||||
bp.column ? nls.localize('editBreakpointOnColumn', "Edit Breakpoint on Column {0}", bp.column) : nls.localize('editLineBrekapoint', "Edit Line Breakpoint"),
|
||||
null,
|
||||
true,
|
||||
() => TPromise.as(this.editor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(bp.lineNumber, bp.column))
|
||||
)
|
||||
)));
|
||||
|
||||
actions.push(new ContextSubMenu(nls.localize('enableDisableBreakpoints', "Enable/Disable Breakpoints"), sorted.map(bp => new Action(
|
||||
bp.enabled ? 'disableColumnBreakpoint' : 'enableColumnBreakpoint',
|
||||
bp.enabled ? (bp.column ? nls.localize('disableColumnBreakpoint', "Disable Breakpoint on Column {0}", bp.column) : nls.localize('disableBreakpointOnLine', "Disable Line Breakpoint"))
|
||||
: (bp.column ? nls.localize('enableBreakpoints', "Enable Breakpoint on Column {0}", bp.column) : nls.localize('enableBreakpointOnLine', "Enable Line Breakpoint")),
|
||||
null,
|
||||
true,
|
||||
() => this.debugService.enableOrDisableBreakpoints(!bp.enabled, bp)
|
||||
))));
|
||||
} else {
|
||||
actions.push(new Action(
|
||||
'addBreakpoint',
|
||||
nls.localize('addBreakpoint', "Add Breakpoint"),
|
||||
null,
|
||||
true,
|
||||
() => this.debugService.addBreakpoints(uri, [{ lineNumber }])
|
||||
));
|
||||
actions.push(this.instantiationService.createInstance(AddConditionalBreakpointAction, AddConditionalBreakpointAction.ID, AddConditionalBreakpointAction.LABEL, this.editor, lineNumber));
|
||||
}
|
||||
|
||||
return TPromise.as(actions);
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this.toDispose.push(this.editor.onMouseDown((e: IEditorMouseEvent) => {
|
||||
if (e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN || /* after last line */ e.target.detail || !this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
|
||||
return;
|
||||
}
|
||||
const canSetBreakpoints = this.debugService.getConfigurationManager().canSetBreakpointsIn(this.editor.getModel());
|
||||
const lineNumber = e.target.position.lineNumber;
|
||||
const uri = this.editor.getModel().uri;
|
||||
|
||||
if (e.event.rightButton || (env.isMacintosh && e.event.leftButton && e.event.ctrlKey)) {
|
||||
if (!canSetBreakpoints) {
|
||||
return;
|
||||
}
|
||||
|
||||
const anchor = { x: e.event.posx + 1, y: e.event.posy };
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints().filter(bp => bp.lineNumber === lineNumber && bp.uri.toString() === uri.toString());
|
||||
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => this.getContextMenuActions(breakpoints, uri, lineNumber),
|
||||
getActionsContext: () => breakpoints.length ? breakpoints[0] : undefined
|
||||
});
|
||||
} else {
|
||||
const breakpoints = this.debugService.getModel().getBreakpoints()
|
||||
.filter(bp => bp.uri.toString() === uri.toString() && bp.lineNumber === lineNumber);
|
||||
|
||||
if (breakpoints.length) {
|
||||
breakpoints.forEach(bp => this.debugService.removeBreakpoints(bp.getId()));
|
||||
} else if (canSetBreakpoints) {
|
||||
this.debugService.addBreakpoints(uri, [{ lineNumber }]);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
this.toDispose.push(this.editor.onMouseMove((e: IEditorMouseEvent) => {
|
||||
let showBreakpointHintAtLineNumber = -1;
|
||||
if (e.target.type === MouseTargetType.GUTTER_GLYPH_MARGIN && this.debugService.getConfigurationManager().canSetBreakpointsIn(this.editor.getModel()) &&
|
||||
this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
|
||||
if (!e.target.detail) {
|
||||
// is not after last line
|
||||
showBreakpointHintAtLineNumber = e.target.position.lineNumber;
|
||||
}
|
||||
}
|
||||
this.ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber);
|
||||
}));
|
||||
this.toDispose.push(this.editor.onMouseLeave((e: IEditorMouseEvent) => {
|
||||
this.ensureBreakpointHintDecoration(-1);
|
||||
}));
|
||||
this.toDispose.push(this.debugService.getViewModel().onDidFocusStackFrame(e => this.onFocusStackFrame(e.stackFrame)));
|
||||
|
||||
// hover listeners & hover widget
|
||||
this.toDispose.push(this.editor.onMouseDown((e: IEditorMouseEvent) => this.onEditorMouseDown(e)));
|
||||
this.toDispose.push(this.editor.onMouseMove((e: IEditorMouseEvent) => this.onEditorMouseMove(e)));
|
||||
this.toDispose.push(this.editor.onMouseLeave((e: IEditorMouseEvent) => {
|
||||
const rect = this.hoverWidget.getDomNode().getBoundingClientRect();
|
||||
// Only hide the hover widget if the editor mouse leave event is outside the hover widget #3528
|
||||
if (e.event.posx < rect.left || e.event.posx > rect.right || e.event.posy < rect.top || e.event.posy > rect.bottom) {
|
||||
this.hideHoverWidget();
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(this.editor.onKeyDown((e: IKeyboardEvent) => this.onKeyDown(e)));
|
||||
this.toDispose.push(this.editor.onDidChangeModelContent(() => {
|
||||
this.wordToLineNumbersMap = null;
|
||||
}));
|
||||
this.toDispose.push(this.editor.onDidChangeModel(() => {
|
||||
const sf = this.debugService.getViewModel().focusedStackFrame;
|
||||
const model = this.editor.getModel();
|
||||
this.editor.updateOptions({ hover: !sf || !model || model.uri.toString() !== sf.source.uri.toString() });
|
||||
this.closeBreakpointWidget();
|
||||
this.toggleExceptionWidget();
|
||||
this.hideHoverWidget();
|
||||
this.updateConfigurationWidgetVisibility();
|
||||
this.wordToLineNumbersMap = null;
|
||||
this.updateInlineDecorations(sf);
|
||||
}));
|
||||
this.toDispose.push(this.editor.onDidScrollChange(() => this.hideHoverWidget));
|
||||
this.toDispose.push(this.debugService.onDidChangeState((state: State) => {
|
||||
if (state !== State.Stopped) {
|
||||
this.toggleExceptionWidget();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return EDITOR_CONTRIBUTION_ID;
|
||||
}
|
||||
|
||||
public showHover(range: Range, focus: boolean): TPromise<void> {
|
||||
const sf = this.debugService.getViewModel().focusedStackFrame;
|
||||
const model = this.editor.getModel();
|
||||
if (sf && model && sf.source.uri.toString() === model.uri.toString()) {
|
||||
return this.hoverWidget.showAt(range, focus);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private marginFreeFromNonDebugDecorations(line: number): boolean {
|
||||
const decorations = this.editor.getLineDecorations(line);
|
||||
if (decorations) {
|
||||
for (const { options } of decorations) {
|
||||
if (options.glyphMarginClassName && options.glyphMarginClassName.indexOf('debug') === -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber: number): void {
|
||||
const newDecoration: IModelDeltaDecoration[] = [];
|
||||
if (showBreakpointHintAtLineNumber !== -1) {
|
||||
newDecoration.push({
|
||||
options: DebugEditorContribution.BREAKPOINT_HELPER_DECORATION,
|
||||
range: {
|
||||
startLineNumber: showBreakpointHintAtLineNumber,
|
||||
startColumn: 1,
|
||||
endLineNumber: showBreakpointHintAtLineNumber,
|
||||
endColumn: 1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.breakpointHintDecoration = this.editor.deltaDecorations(this.breakpointHintDecoration, newDecoration);
|
||||
}
|
||||
|
||||
private onFocusStackFrame(sf: IStackFrame): void {
|
||||
const model = this.editor.getModel();
|
||||
if (model && sf && sf.source.uri.toString() === model.uri.toString()) {
|
||||
this.editor.updateOptions({ hover: false });
|
||||
this.toggleExceptionWidget();
|
||||
} else {
|
||||
this.editor.updateOptions({ hover: true });
|
||||
this.hideHoverWidget();
|
||||
}
|
||||
|
||||
this.updateInlineDecorations(sf);
|
||||
}
|
||||
|
||||
private hideHoverWidget(): void {
|
||||
if (!this.hideHoverScheduler.isScheduled() && this.hoverWidget.isVisible()) {
|
||||
this.hideHoverScheduler.schedule();
|
||||
}
|
||||
this.showHoverScheduler.cancel();
|
||||
}
|
||||
|
||||
// hover business
|
||||
|
||||
private onEditorMouseDown(mouseEvent: IEditorMouseEvent): void {
|
||||
if (mouseEvent.target.type === MouseTargetType.CONTENT_WIDGET && mouseEvent.target.detail === DebugHoverWidget.ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.hideHoverWidget();
|
||||
}
|
||||
|
||||
private onEditorMouseMove(mouseEvent: IEditorMouseEvent): void {
|
||||
if (this.debugService.state !== State.Stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetType = mouseEvent.target.type;
|
||||
const stopKey = env.isMacintosh ? 'metaKey' : 'ctrlKey';
|
||||
|
||||
if (targetType === MouseTargetType.CONTENT_WIDGET && mouseEvent.target.detail === DebugHoverWidget.ID && !(<any>mouseEvent.event)[stopKey]) {
|
||||
// mouse moved on top of debug hover widget
|
||||
return;
|
||||
}
|
||||
if (targetType === MouseTargetType.CONTENT_TEXT) {
|
||||
if (!mouseEvent.target.range.equalsRange(this.hoverRange)) {
|
||||
this.hoverRange = mouseEvent.target.range;
|
||||
this.showHoverScheduler.schedule();
|
||||
}
|
||||
} else {
|
||||
this.hideHoverWidget();
|
||||
}
|
||||
}
|
||||
|
||||
private onKeyDown(e: IKeyboardEvent): void {
|
||||
const stopKey = env.isMacintosh ? KeyCode.Meta : KeyCode.Ctrl;
|
||||
if (e.keyCode !== stopKey) {
|
||||
// do not hide hover when Ctrl/Meta is pressed
|
||||
this.hideHoverWidget();
|
||||
}
|
||||
}
|
||||
|
||||
// end hover business
|
||||
|
||||
// breakpoint widget
|
||||
public showBreakpointWidget(lineNumber: number, column: number): void {
|
||||
if (this.breakpointWidget) {
|
||||
this.breakpointWidget.dispose();
|
||||
}
|
||||
|
||||
this.breakpointWidget = this.instantiationService.createInstance(BreakpointWidget, this.editor, lineNumber, column);
|
||||
this.breakpointWidget.show({ lineNumber, column: 1 }, 2);
|
||||
this.breakpointWidgetVisible.set(true);
|
||||
}
|
||||
|
||||
public closeBreakpointWidget(): void {
|
||||
if (this.breakpointWidget) {
|
||||
this.breakpointWidget.dispose();
|
||||
this.breakpointWidget = null;
|
||||
this.breakpointWidgetVisible.reset();
|
||||
this.editor.focus();
|
||||
}
|
||||
}
|
||||
|
||||
// exception widget
|
||||
private toggleExceptionWidget(): void {
|
||||
// Toggles exception widget based on the state of the current editor model and debug stack frame
|
||||
const model = this.editor.getModel();
|
||||
const focusedSf = this.debugService.getViewModel().focusedStackFrame;
|
||||
const callStack = focusedSf ? focusedSf.thread.getCallStack() : null;
|
||||
if (!model || !focusedSf || !callStack || callStack.length === 0) {
|
||||
this.closeExceptionWidget();
|
||||
return;
|
||||
}
|
||||
|
||||
// First call stack frame that is available is the frame where exception has been thrown
|
||||
const exceptionSf = first(callStack, sf => sf.source && sf.source.available, undefined);
|
||||
if (!exceptionSf) {
|
||||
this.closeExceptionWidget();
|
||||
return;
|
||||
}
|
||||
|
||||
const sameUri = exceptionSf.source.uri.toString() === model.uri.toString();
|
||||
if (this.exceptionWidget && !sameUri) {
|
||||
this.closeExceptionWidget();
|
||||
} else if (sameUri) {
|
||||
focusedSf.thread.exceptionInfo.then(exceptionInfo => {
|
||||
if (exceptionInfo && exceptionSf.range.startLineNumber && exceptionSf.range.startColumn) {
|
||||
this.showExceptionWidget(exceptionInfo, exceptionSf.range.startLineNumber, exceptionSf.range.startColumn);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private showExceptionWidget(exceptionInfo: IExceptionInfo, lineNumber: number, column: number): void {
|
||||
if (this.exceptionWidget) {
|
||||
this.exceptionWidget.dispose();
|
||||
}
|
||||
|
||||
this.exceptionWidget = this.instantiationService.createInstance(ExceptionWidget, this.editor, exceptionInfo, lineNumber);
|
||||
this.exceptionWidget.show({ lineNumber, column }, 0);
|
||||
}
|
||||
|
||||
private closeExceptionWidget(): void {
|
||||
if (this.exceptionWidget) {
|
||||
this.exceptionWidget.dispose();
|
||||
this.exceptionWidget = null;
|
||||
}
|
||||
}
|
||||
|
||||
// configuration widget
|
||||
private updateConfigurationWidgetVisibility(): void {
|
||||
const model = this.editor.getModel();
|
||||
if (model && LAUNCH_JSON_REGEX.test(model.uri.toString())) {
|
||||
this.configurationWidget = this.instantiationService.createInstance(FloatingClickWidget, this.editor, nls.localize('addConfiguration', "Add Configuration..."), null);
|
||||
this.configurationWidget.render();
|
||||
this.toDispose.push(this.configurationWidget.onClick(() => this.addLaunchConfiguration().done(undefined, errors.onUnexpectedError)));
|
||||
} else if (this.configurationWidget) {
|
||||
this.configurationWidget.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public addLaunchConfiguration(): TPromise<any> {
|
||||
this.telemetryService.publicLog('debug/addLaunchConfiguration');
|
||||
let configurationsArrayPosition: Position;
|
||||
const model = this.editor.getModel();
|
||||
let depthInArray = 0;
|
||||
let lastProperty: string;
|
||||
|
||||
visit(model.getValue(), {
|
||||
onObjectProperty: (property, offset, length) => {
|
||||
lastProperty = property;
|
||||
},
|
||||
onArrayBegin: (offset: number, length: number) => {
|
||||
if (lastProperty === 'configurations' && depthInArray === 0) {
|
||||
configurationsArrayPosition = model.getPositionAt(offset + 1);
|
||||
}
|
||||
depthInArray++;
|
||||
},
|
||||
onArrayEnd: () => {
|
||||
depthInArray--;
|
||||
}
|
||||
});
|
||||
|
||||
this.editor.focus();
|
||||
if (!configurationsArrayPosition) {
|
||||
return this.commandService.executeCommand('editor.action.triggerSuggest');
|
||||
}
|
||||
|
||||
const insertLine = (position: Position): TPromise<any> => {
|
||||
// Check if there are more characters on a line after a "configurations": [, if yes enter a newline
|
||||
if (this.editor.getModel().getLineLastNonWhitespaceColumn(position.lineNumber) > position.column) {
|
||||
this.editor.setPosition(position);
|
||||
CoreEditingCommands.LineBreakInsert.runEditorCommand(null, this.editor, null);
|
||||
}
|
||||
// Check if there is already an empty line to insert suggest, if yes just place the cursor
|
||||
if (this.editor.getModel().getLineLastNonWhitespaceColumn(position.lineNumber + 1) === 0) {
|
||||
this.editor.setPosition({ lineNumber: position.lineNumber + 1, column: Constants.MAX_SAFE_SMALL_INTEGER });
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
this.editor.setPosition(position);
|
||||
return this.commandService.executeCommand('editor.action.insertLineAfter');
|
||||
};
|
||||
|
||||
return insertLine(configurationsArrayPosition).then(() => this.commandService.executeCommand('editor.action.triggerSuggest'));
|
||||
}
|
||||
|
||||
private static BREAKPOINT_HELPER_DECORATION: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-breakpoint-hint-glyph',
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
|
||||
};
|
||||
|
||||
// Inline Decorations
|
||||
private updateInlineDecorations(stackFrame: IStackFrame): void {
|
||||
const model = this.editor.getModel();
|
||||
if (!this.configurationService.getConfiguration<IDebugConfiguration>('debug').inlineValues ||
|
||||
!model || !stackFrame || model.uri.toString() !== stackFrame.source.uri.toString()) {
|
||||
if (!this.removeInlineValuesScheduler.isScheduled()) {
|
||||
this.removeInlineValuesScheduler.schedule();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.removeInlineValuesScheduler.cancel();
|
||||
|
||||
stackFrame.getMostSpecificScopes(stackFrame.range)
|
||||
// Get all top level children in the scope chain
|
||||
.then(scopes => TPromise.join(scopes.map(scope => scope.getChildren()
|
||||
.then(children => {
|
||||
let range = new Range(0, 0, stackFrame.range.startLineNumber, stackFrame.range.startColumn);
|
||||
if (scope.range) {
|
||||
range = range.setStartPosition(scope.range.startLineNumber, scope.range.startColumn);
|
||||
}
|
||||
|
||||
return this.createInlineValueDecorationsInsideRange(children, range);
|
||||
}))).then(decorationsPerScope => {
|
||||
const allDecorations = decorationsPerScope.reduce((previous, current) => previous.concat(current), []);
|
||||
this.editor.setDecorations(INLINE_VALUE_DECORATION_KEY, allDecorations);
|
||||
}));
|
||||
}
|
||||
|
||||
private createInlineValueDecorationsInsideRange(expressions: IExpression[], range: Range): IDecorationOptions[] {
|
||||
const nameValueMap = new Map<string, string>();
|
||||
for (let expr of expressions) {
|
||||
nameValueMap.set(expr.name, expr.value);
|
||||
// Limit the size of map. Too large can have a perf impact
|
||||
if (nameValueMap.size >= MAX_NUM_INLINE_VALUES) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const lineToNamesMap: Map<number, string[]> = new Map<number, string[]>();
|
||||
const wordToPositionsMap = this.getWordToPositionsMap();
|
||||
|
||||
// Compute unique set of names on each line
|
||||
nameValueMap.forEach((value, name) => {
|
||||
if (wordToPositionsMap.has(name)) {
|
||||
for (let position of wordToPositionsMap.get(name)) {
|
||||
if (range.containsPosition(position)) {
|
||||
if (!lineToNamesMap.has(position.lineNumber)) {
|
||||
lineToNamesMap.set(position.lineNumber, []);
|
||||
}
|
||||
|
||||
if (lineToNamesMap.get(position.lineNumber).indexOf(name) === -1) {
|
||||
lineToNamesMap.get(position.lineNumber).push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const decorations: IDecorationOptions[] = [];
|
||||
// Compute decorators for each line
|
||||
lineToNamesMap.forEach((names, line) => {
|
||||
const contentText = names.sort((first, second) => {
|
||||
const content = this.editor.getModel().getLineContent(line);
|
||||
return content.indexOf(first) - content.indexOf(second);
|
||||
}).map(name => `${name} = ${nameValueMap.get(name)}`).join(', ');
|
||||
decorations.push(this.createInlineValueDecoration(line, contentText));
|
||||
});
|
||||
|
||||
return decorations;
|
||||
}
|
||||
|
||||
private createInlineValueDecoration(lineNumber: number, contentText: string): IDecorationOptions {
|
||||
// If decoratorText is too long, trim and add ellipses. This could happen for minified files with everything on a single line
|
||||
if (contentText.length > MAX_INLINE_DECORATOR_LENGTH) {
|
||||
contentText = contentText.substr(0, MAX_INLINE_DECORATOR_LENGTH) + '...';
|
||||
}
|
||||
|
||||
return {
|
||||
range: {
|
||||
startLineNumber: lineNumber,
|
||||
endLineNumber: lineNumber,
|
||||
startColumn: Constants.MAX_SAFE_SMALL_INTEGER,
|
||||
endColumn: Constants.MAX_SAFE_SMALL_INTEGER
|
||||
},
|
||||
renderOptions: {
|
||||
after: {
|
||||
contentText,
|
||||
backgroundColor: 'rgba(255, 200, 0, 0.2)',
|
||||
margin: '10px'
|
||||
},
|
||||
dark: {
|
||||
after: {
|
||||
color: 'rgba(255, 255, 255, 0.5)',
|
||||
}
|
||||
},
|
||||
light: {
|
||||
after: {
|
||||
color: 'rgba(0, 0, 0, 0.5)',
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private getWordToPositionsMap(): Map<string, Position[]> {
|
||||
if (!this.wordToLineNumbersMap) {
|
||||
this.wordToLineNumbersMap = new Map<string, Position[]>();
|
||||
const model = this.editor.getModel();
|
||||
// For every word in every line, map its ranges for fast lookup
|
||||
for (let lineNumber = 1, len = model.getLineCount(); lineNumber <= len; ++lineNumber) {
|
||||
const lineContent = model.getLineContent(lineNumber);
|
||||
|
||||
// If line is too long then skip the line
|
||||
if (lineContent.length > MAX_TOKENIZATION_LINE_LEN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
model.forceTokenization(lineNumber);
|
||||
const lineTokens = model.getLineTokens(lineNumber);
|
||||
for (let token = lineTokens.firstToken(); !!token; token = token.next()) {
|
||||
const tokenStr = lineContent.substring(token.startOffset, token.endOffset);
|
||||
|
||||
// Token is a word and not a comment
|
||||
if (token.tokenType === StandardTokenType.Other) {
|
||||
DEFAULT_WORD_REGEXP.lastIndex = 0; // We assume tokens will usually map 1:1 to words if they match
|
||||
const wordMatch = DEFAULT_WORD_REGEXP.exec(tokenStr);
|
||||
|
||||
if (wordMatch) {
|
||||
const word = wordMatch[0];
|
||||
if (!this.wordToLineNumbersMap.has(word)) {
|
||||
this.wordToLineNumbersMap.set(word, []);
|
||||
}
|
||||
|
||||
this.wordToLineNumbersMap.get(word).push(new Position(lineNumber, token.startOffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.wordToLineNumbersMap;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this.breakpointWidget) {
|
||||
this.breakpointWidget.dispose();
|
||||
}
|
||||
if (this.hoverWidget) {
|
||||
this.hoverWidget.dispose();
|
||||
}
|
||||
if (this.configurationWidget) {
|
||||
this.configurationWidget.dispose();
|
||||
}
|
||||
this.toDispose = lifecycle.dispose(this.toDispose);
|
||||
}
|
||||
}
|
||||