Merge from vscode a5cf1da01d5db3d2557132be8d30f89c38019f6c (#8525)
* Merge from vscode a5cf1da01d5db3d2557132be8d30f89c38019f6c * remove files we don't want * fix hygiene * update distro * update distro * fix hygiene * fix strict nulls * distro * distro * fix tests * fix tests * add another edit * fix viewlet icon * fix azure dialog * fix some padding * fix more padding issues
@@ -7,10 +7,10 @@ import { URI as Uri } from 'vs/base/common/uri';
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
import { Disposable } 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 { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||
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';
|
||||
import { CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files';
|
||||
import { IFilesConfigurationService, IAutoSaveConfiguration } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
|
||||
|
||||
const AUTO_SAVE_AFTER_DELAY_DISABLED_TIME = CONTENT_CHANGE_EVENT_BUFFER_DELAY + 500;
|
||||
|
||||
@@ -21,8 +21,8 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu
|
||||
constructor(
|
||||
@IBackupFileService private readonly backupFileService: IBackupFileService,
|
||||
@ITextFileService private readonly textFileService: ITextFileService,
|
||||
@IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
@IUntitledTextEditorService private readonly untitledTextEditorService: IUntitledTextEditorService,
|
||||
@IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -32,26 +32,20 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu
|
||||
private registerListeners() {
|
||||
|
||||
// Listen for text file model changes
|
||||
this._register(this.textFileService.models.onModelContentChanged((e) => this.onTextFileModelChanged(e)));
|
||||
this._register(this.textFileService.models.onModelSaved((e) => this.discardBackup(e.resource)));
|
||||
this._register(this.textFileService.models.onModelDisposed((e) => this.discardBackup(e)));
|
||||
this._register(this.textFileService.models.onModelContentChanged(e => this.onTextFileModelChanged(e)));
|
||||
this._register(this.textFileService.models.onModelSaved(e => this.discardBackup(e.resource)));
|
||||
this._register(this.textFileService.models.onModelDisposed(e => this.discardBackup(e)));
|
||||
|
||||
// Listen for untitled model changes
|
||||
this._register(this.untitledEditorService.onDidChangeContent((e) => this.onUntitledModelChanged(e)));
|
||||
this._register(this.untitledEditorService.onDidDisposeModel((e) => this.discardBackup(e)));
|
||||
this._register(this.untitledTextEditorService.onDidChangeContent(e => this.onUntitledModelChanged(e)));
|
||||
this._register(this.untitledTextEditorService.onDidDisposeModel(e => this.discardBackup(e)));
|
||||
|
||||
// Listen to config changes
|
||||
this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(this.configurationService.getValue<IFilesConfiguration>())));
|
||||
// Listen to auto save config changes
|
||||
this._register(this.filesConfigurationService.onAutoSaveConfigurationChange(c => this.onAutoSaveConfigurationChange(c)));
|
||||
}
|
||||
|
||||
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 onAutoSaveConfigurationChange(configuration: IAutoSaveConfiguration): void {
|
||||
this.configuredAutoSaveAfterDelay = typeof configuration.autoSaveDelay === 'number' && configuration.autoSaveDelay < AUTO_SAVE_AFTER_DELAY_DISABLED_TIME;
|
||||
}
|
||||
|
||||
private onTextFileModelChanged(event: TextFileModelChangeEvent): void {
|
||||
@@ -71,8 +65,8 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu
|
||||
}
|
||||
|
||||
private onUntitledModelChanged(resource: Uri): void {
|
||||
if (this.untitledEditorService.isDirty(resource)) {
|
||||
this.untitledEditorService.loadOrCreate({ resource }).then(model => model.backup());
|
||||
if (this.untitledTextEditorService.isDirty(resource)) {
|
||||
this.untitledTextEditorService.loadOrCreate({ resource }).then(model => model.backup());
|
||||
} else {
|
||||
this.discardBackup(resource);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
||||
import { IResourceInput } from 'vs/platform/editor/common/editor';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IUntitledResourceInput } from 'vs/workbench/common/editor';
|
||||
import { IUntitledTextResourceInput } from 'vs/workbench/common/editor';
|
||||
import { toLocalResource } from 'vs/base/common/resources';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
@@ -76,7 +76,7 @@ export class BackupRestorer implements IWorkbenchContribution {
|
||||
await this.editorService.openEditors(inputs);
|
||||
}
|
||||
|
||||
private resolveInput(resource: URI, index: number, hasOpenedEditors: boolean): IResourceInput | IUntitledResourceInput {
|
||||
private resolveInput(resource: URI, index: number, hasOpenedEditors: boolean): IResourceInput | IUntitledTextResourceInput {
|
||||
const options = { pinned: true, preserveFocus: true, inactive: index > 0 || hasOpenedEditors };
|
||||
|
||||
// this is a (weak) strategy to find out if the untitled input had
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { CallHierarchyProviderRegistry, CallHierarchyDirection } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy';
|
||||
import { CallHierarchyProviderRegistry, CallHierarchyDirection, CallHierarchyModel } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { CallHierarchyTreePeekWidget } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek';
|
||||
@@ -17,9 +17,12 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { PeekContext } from 'vs/editor/contrib/referenceSearch/peekViewWidget';
|
||||
import { CallHierarchyRoot } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyTree';
|
||||
import { PeekContext } from 'vs/editor/contrib/peekView/peekView';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
|
||||
const _ctxHasCompletionItemProvider = new RawContextKey<boolean>('editorHasCallHierarchyProvider', false);
|
||||
const _ctxCallHierarchyVisible = new RawContextKey<boolean>('callHierarchyVisible', false);
|
||||
@@ -39,10 +42,13 @@ class CallHierarchyController implements IEditorContribution {
|
||||
private readonly _dispoables = new DisposableStore();
|
||||
private readonly _sessionDisposables = new DisposableStore();
|
||||
|
||||
private _widget?: CallHierarchyTreePeekWidget;
|
||||
|
||||
constructor(
|
||||
private readonly _editor: ICodeEditor,
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||
@IStorageService private readonly _storageService: IStorageService,
|
||||
@ICodeEditorService private readonly _editorService: ICodeEditorService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
) {
|
||||
this._ctxIsVisible = _ctxCallHierarchyVisible.bindTo(this._contextKeyService);
|
||||
@@ -59,48 +65,83 @@ class CallHierarchyController implements IEditorContribution {
|
||||
this._dispoables.dispose();
|
||||
}
|
||||
|
||||
async startCallHierarchy(): Promise<void> {
|
||||
async startCallHierarchyFromEditor(): Promise<void> {
|
||||
this._sessionDisposables.clear();
|
||||
|
||||
if (!this._editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const model = this._editor.getModel();
|
||||
const document = this._editor.getModel();
|
||||
const position = this._editor.getPosition();
|
||||
const [provider] = CallHierarchyProviderRegistry.ordered(model);
|
||||
if (!provider) {
|
||||
if (!CallHierarchyProviderRegistry.has(document)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cts = new CancellationTokenSource();
|
||||
const model = CallHierarchyModel.create(document, position, cts.token);
|
||||
const direction = this._storageService.getNumber(CallHierarchyController._StorageDirection, StorageScope.GLOBAL, <number>CallHierarchyDirection.CallsFrom);
|
||||
|
||||
Event.any<any>(this._editor.onDidChangeModel, this._editor.onDidChangeModelLanguage)(this.endCallHierarchy, this, this._sessionDisposables);
|
||||
const widget = this._instantiationService.createInstance(
|
||||
CallHierarchyTreePeekWidget,
|
||||
this._editor,
|
||||
position,
|
||||
provider,
|
||||
direction
|
||||
this._showCallHierarchyWidget(position, direction, model, cts);
|
||||
}
|
||||
|
||||
async startCallHierarchyFromCallHierarchy(): Promise<void> {
|
||||
if (!this._widget) {
|
||||
return;
|
||||
}
|
||||
const model = this._widget.getModel();
|
||||
const call = this._widget.getFocused();
|
||||
if (!call || !model) {
|
||||
return;
|
||||
}
|
||||
const newEditor = await this._editorService.openCodeEditor({ resource: call.item.uri }, this._editor);
|
||||
if (!newEditor) {
|
||||
return;
|
||||
}
|
||||
const newModel = model.fork(call.item);
|
||||
this._sessionDisposables.clear();
|
||||
|
||||
CallHierarchyController.get(newEditor)._showCallHierarchyWidget(
|
||||
Range.lift(newModel.root.selectionRange).getStartPosition(),
|
||||
this._widget.direction,
|
||||
Promise.resolve(newModel),
|
||||
new CancellationTokenSource()
|
||||
);
|
||||
}
|
||||
|
||||
widget.showLoading();
|
||||
private _showCallHierarchyWidget(position: IPosition, direction: number, model: Promise<CallHierarchyModel | undefined>, cts: CancellationTokenSource) {
|
||||
|
||||
Event.any<any>(this._editor.onDidChangeModel, this._editor.onDidChangeModelLanguage)(this.endCallHierarchy, this, this._sessionDisposables);
|
||||
this._widget = this._instantiationService.createInstance(CallHierarchyTreePeekWidget, this._editor, position, direction);
|
||||
this._widget.showLoading();
|
||||
this._ctxIsVisible.set(true);
|
||||
|
||||
const cancel = new CancellationTokenSource();
|
||||
|
||||
this._sessionDisposables.add(widget.onDidClose(() => {
|
||||
this._sessionDisposables.add(this._widget.onDidClose(() => {
|
||||
this.endCallHierarchy();
|
||||
this._storageService.store(CallHierarchyController._StorageDirection, widget.direction, StorageScope.GLOBAL);
|
||||
this._storageService.store(CallHierarchyController._StorageDirection, this._widget!.direction, StorageScope.GLOBAL);
|
||||
}));
|
||||
this._sessionDisposables.add({ dispose() { cancel.cancel(); } });
|
||||
this._sessionDisposables.add(widget);
|
||||
this._sessionDisposables.add({ dispose() { cts.dispose(true); } });
|
||||
this._sessionDisposables.add(this._widget);
|
||||
|
||||
const root = CallHierarchyRoot.fromEditor(this._editor);
|
||||
if (root) {
|
||||
widget.showItem(root);
|
||||
} else {
|
||||
widget.showMessage(localize('no.item', "No results"));
|
||||
model.then(model => {
|
||||
if (cts.token.isCancellationRequested) {
|
||||
return; // nothing
|
||||
}
|
||||
if (model) {
|
||||
this._sessionDisposables.add(model);
|
||||
this._widget!.showModel(model);
|
||||
}
|
||||
else {
|
||||
this._widget!.showMessage(localize('no.item', "No results"));
|
||||
}
|
||||
}).catch(e => {
|
||||
this._widget!.showMessage(localize('error', "Failed to show call hierarchy"));
|
||||
console.error(e);
|
||||
});
|
||||
}
|
||||
|
||||
toggleCallHierarchyDirection(): void {
|
||||
if (this._widget) {
|
||||
this._widget.toggleDirection();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,9 +161,10 @@ registerEditorAction(class extends EditorAction {
|
||||
id: 'editor.showCallHierarchy',
|
||||
label: localize('title', "Peek Call Hierarchy"),
|
||||
alias: 'Peek Call Hierarchy',
|
||||
menuOpts: {
|
||||
contextMenuOpts: {
|
||||
menuId: MenuId.EditorContextPeek,
|
||||
group: 'navigation',
|
||||
order: 1.48
|
||||
order: 1000
|
||||
},
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.editorTextFocus,
|
||||
@@ -130,14 +172,55 @@ registerEditorAction(class extends EditorAction {
|
||||
primary: KeyMod.Shift + KeyMod.Alt + KeyCode.KEY_H
|
||||
},
|
||||
precondition: ContextKeyExpr.and(
|
||||
_ctxCallHierarchyVisible.negate(),
|
||||
_ctxHasCompletionItemProvider,
|
||||
PeekContext.notInPeekEditor
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
async run(_accessor: ServicesAccessor, editor: ICodeEditor, args: any): Promise<void> {
|
||||
return CallHierarchyController.get(editor).startCallHierarchy();
|
||||
async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
|
||||
return CallHierarchyController.get(editor).startCallHierarchyFromEditor();
|
||||
}
|
||||
});
|
||||
|
||||
registerEditorAction(class extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.toggleCallHierarchy',
|
||||
label: localize('title.toggle', "Toggle Call Hierarchy"),
|
||||
alias: 'Toggle Call Hierarchy',
|
||||
kbOpts: {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.Shift + KeyMod.Alt + KeyCode.KEY_H
|
||||
},
|
||||
precondition: _ctxCallHierarchyVisible
|
||||
});
|
||||
}
|
||||
|
||||
async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
|
||||
return CallHierarchyController.get(editor).toggleCallHierarchyDirection();
|
||||
}
|
||||
});
|
||||
|
||||
registerEditorAction(class extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.refocusCallHierarchy',
|
||||
label: localize('title.refocus', "Refocus Call Hierarchy"),
|
||||
alias: 'Refocus Call Hierarchy',
|
||||
kbOpts: {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.Shift + KeyCode.Enter
|
||||
},
|
||||
precondition: _ctxCallHierarchyVisible
|
||||
});
|
||||
}
|
||||
|
||||
async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
|
||||
return CallHierarchyController.get(editor).startCallHierarchyFromCallHierarchy();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -9,10 +9,14 @@ import { ITextModel } from 'vs/editor/common/model';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { registerDefaultLanguageCommand } from 'vs/editor/browser/editorExtensions';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { assertType } from 'vs/base/common/types';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
|
||||
export const enum CallHierarchyDirection {
|
||||
CallsTo = 1,
|
||||
@@ -20,6 +24,8 @@ export const enum CallHierarchyDirection {
|
||||
}
|
||||
|
||||
export interface CallHierarchyItem {
|
||||
_sessionId: string;
|
||||
_itemId: string;
|
||||
kind: SymbolKind;
|
||||
name: string;
|
||||
detail?: string;
|
||||
@@ -38,47 +44,167 @@ export interface OutgoingCall {
|
||||
to: CallHierarchyItem;
|
||||
}
|
||||
|
||||
export interface CallHierarchySession {
|
||||
root: CallHierarchyItem;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export interface CallHierarchyProvider {
|
||||
|
||||
provideIncomingCalls(document: ITextModel, postion: IPosition, token: CancellationToken): ProviderResult<IncomingCall[]>;
|
||||
prepareCallHierarchy(document: ITextModel, position: IPosition, token: CancellationToken): ProviderResult<CallHierarchySession>;
|
||||
|
||||
provideOutgoingCalls(document: ITextModel, postion: IPosition, token: CancellationToken): ProviderResult<OutgoingCall[]>;
|
||||
provideIncomingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult<IncomingCall[]>;
|
||||
|
||||
provideOutgoingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult<OutgoingCall[]>;
|
||||
}
|
||||
|
||||
export const CallHierarchyProviderRegistry = new LanguageFeatureRegistry<CallHierarchyProvider>();
|
||||
|
||||
|
||||
export async function provideIncomingCalls(model: ITextModel, position: IPosition, token: CancellationToken): Promise<IncomingCall[]> {
|
||||
const [provider] = CallHierarchyProviderRegistry.ordered(model);
|
||||
if (!provider) {
|
||||
return [];
|
||||
class RefCountedDisposabled {
|
||||
|
||||
constructor(
|
||||
private readonly _disposable: IDisposable,
|
||||
private _counter = 1
|
||||
) { }
|
||||
|
||||
acquire() {
|
||||
this._counter++;
|
||||
return this;
|
||||
}
|
||||
try {
|
||||
const result = await provider.provideIncomingCalls(model, position, token);
|
||||
if (isNonEmptyArray(result)) {
|
||||
return result;
|
||||
|
||||
release() {
|
||||
if (--this._counter === 0) {
|
||||
this._disposable.dispose();
|
||||
}
|
||||
} catch (e) {
|
||||
onUnexpectedExternalError(e);
|
||||
return this;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export async function provideOutgoingCalls(model: ITextModel, position: IPosition, token: CancellationToken): Promise<OutgoingCall[]> {
|
||||
const [provider] = CallHierarchyProviderRegistry.ordered(model);
|
||||
if (!provider) {
|
||||
export class CallHierarchyModel {
|
||||
|
||||
static async create(model: ITextModel, position: IPosition, token: CancellationToken): Promise<CallHierarchyModel | undefined> {
|
||||
const [provider] = CallHierarchyProviderRegistry.ordered(model);
|
||||
if (!provider) {
|
||||
return undefined;
|
||||
}
|
||||
const session = await provider.prepareCallHierarchy(model, position, token);
|
||||
if (!session) {
|
||||
return undefined;
|
||||
}
|
||||
return new CallHierarchyModel(session.root._sessionId, provider, session.root, new RefCountedDisposabled(session));
|
||||
}
|
||||
|
||||
private constructor(
|
||||
readonly id: string,
|
||||
readonly provider: CallHierarchyProvider,
|
||||
readonly root: CallHierarchyItem,
|
||||
readonly ref: RefCountedDisposabled,
|
||||
) { }
|
||||
|
||||
dispose(): void {
|
||||
this.ref.release();
|
||||
}
|
||||
|
||||
fork(item: CallHierarchyItem): CallHierarchyModel {
|
||||
const that = this;
|
||||
return new class extends CallHierarchyModel {
|
||||
constructor() {
|
||||
super(that.id, that.provider, item, that.ref.acquire());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async resolveIncomingCalls(item: CallHierarchyItem, token: CancellationToken): Promise<IncomingCall[]> {
|
||||
try {
|
||||
const result = await this.provider.provideIncomingCalls(item, token);
|
||||
if (isNonEmptyArray(result)) {
|
||||
return result;
|
||||
}
|
||||
} catch (e) {
|
||||
onUnexpectedExternalError(e);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
const result = await provider.provideOutgoingCalls(model, position, token);
|
||||
if (isNonEmptyArray(result)) {
|
||||
return result;
|
||||
|
||||
async resolveOutgoingCalls(item: CallHierarchyItem, token: CancellationToken): Promise<OutgoingCall[]> {
|
||||
try {
|
||||
const result = await this.provider.provideOutgoingCalls(item, token);
|
||||
if (isNonEmptyArray(result)) {
|
||||
return result;
|
||||
}
|
||||
} catch (e) {
|
||||
onUnexpectedExternalError(e);
|
||||
}
|
||||
} catch (e) {
|
||||
onUnexpectedExternalError(e);
|
||||
return [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
registerDefaultLanguageCommand('_executeCallHierarchyIncomingCalls', async (model, position) => provideIncomingCalls(model, position, CancellationToken.None));
|
||||
registerDefaultLanguageCommand('_executeCallHierarchyOutgoingCalls', async (model, position) => provideOutgoingCalls(model, position, CancellationToken.None));
|
||||
// --- API command support
|
||||
|
||||
const _models = new Map<string, CallHierarchyModel>();
|
||||
|
||||
CommandsRegistry.registerCommand('_executePrepareCallHierarchy', async (accessor, ...args) => {
|
||||
const [resource, position] = args;
|
||||
assertType(URI.isUri(resource));
|
||||
assertType(Position.isIPosition(position));
|
||||
|
||||
const modelService = accessor.get(IModelService);
|
||||
let textModel = modelService.getModel(resource);
|
||||
let textModelReference: IDisposable | undefined;
|
||||
if (!textModel) {
|
||||
const textModelService = accessor.get(ITextModelService);
|
||||
const result = await textModelService.createModelReference(resource);
|
||||
textModel = result.object.textEditorModel;
|
||||
textModelReference = result;
|
||||
}
|
||||
|
||||
try {
|
||||
const model = await CallHierarchyModel.create(textModel, position, CancellationToken.None);
|
||||
if (!model) {
|
||||
return [];
|
||||
}
|
||||
//
|
||||
_models.set(model.id, model);
|
||||
_models.forEach((value, key, map) => {
|
||||
if (map.size > 10) {
|
||||
value.dispose();
|
||||
_models.delete(key);
|
||||
}
|
||||
});
|
||||
return [model.root];
|
||||
|
||||
} finally {
|
||||
dispose(textModelReference);
|
||||
}
|
||||
});
|
||||
|
||||
function isCallHierarchyItemDto(obj: any): obj is CallHierarchyItem {
|
||||
return true;
|
||||
}
|
||||
|
||||
CommandsRegistry.registerCommand('_executeProvideIncomingCalls', async (_accessor, ...args) => {
|
||||
const [item] = args;
|
||||
assertType(isCallHierarchyItemDto(item));
|
||||
|
||||
// find model
|
||||
const model = _models.get(item._sessionId);
|
||||
if (!model) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return model.resolveIncomingCalls(item, CancellationToken.None);
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand('_executeProvideOutgoingCalls', async (_accessor, ...args) => {
|
||||
const [item] = args;
|
||||
assertType(isCallHierarchyItemDto(item));
|
||||
|
||||
// find model
|
||||
const model = _models.get(item._sessionId);
|
||||
if (!model) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return model.resolveOutgoingCalls(item, CancellationToken.None);
|
||||
});
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/callHierarchy';
|
||||
import { PeekViewWidget, IPeekViewService } from 'vs/editor/contrib/referenceSearch/peekViewWidget';
|
||||
import * as peekView from 'vs/editor/contrib/peekView/peekView';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { CallHierarchyProvider, CallHierarchyDirection } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy';
|
||||
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
|
||||
import { CallHierarchyDirection, CallHierarchyModel } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy';
|
||||
import { WorkbenchAsyncDataTree, IWorkbenchAsyncDataTreeOptions } from 'vs/platform/list/browser/listService';
|
||||
import { FuzzyScore } from 'vs/base/common/filters';
|
||||
import * as callHTree from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyTree';
|
||||
import { IAsyncDataTreeOptions, IAsyncDataTreeViewState } from 'vs/base/browser/ui/tree/asyncDataTree';
|
||||
import { IAsyncDataTreeViewState } from 'vs/base/browser/ui/tree/asyncDataTree';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
@@ -25,13 +25,12 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { TrackedRangeStickiness, IModelDeltaDecoration, IModelDecorationOptions, OverviewRulerLane } from 'vs/editor/common/model';
|
||||
import { registerThemingParticipant, themeColorFromId, IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
||||
import * as referencesWidget from 'vs/editor/contrib/referenceSearch/referencesWidget';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { TreeMouseEventTarget } from 'vs/base/browser/ui/tree/tree';
|
||||
import { TreeMouseEventTarget, ITreeNode } from 'vs/base/browser/ui/tree/tree';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
const enum State {
|
||||
@@ -42,19 +41,14 @@ const enum State {
|
||||
|
||||
class ChangeHierarchyDirectionAction extends Action {
|
||||
|
||||
constructor(direction: CallHierarchyDirection, updateDirection: (direction: CallHierarchyDirection) => void) {
|
||||
constructor(getDirection: () => CallHierarchyDirection, toggleDirection: () => void) {
|
||||
super('', undefined, '', true, () => {
|
||||
if (direction === CallHierarchyDirection.CallsTo) {
|
||||
direction = CallHierarchyDirection.CallsFrom;
|
||||
} else {
|
||||
direction = CallHierarchyDirection.CallsTo;
|
||||
}
|
||||
updateDirection(direction);
|
||||
toggleDirection();
|
||||
update();
|
||||
return Promise.resolve();
|
||||
});
|
||||
const update = () => {
|
||||
if (direction === CallHierarchyDirection.CallsFrom) {
|
||||
if (getDirection() === CallHierarchyDirection.CallsFrom) {
|
||||
this.label = localize('toggle.from', "Showing Calls");
|
||||
this.class = 'calls-from';
|
||||
} else {
|
||||
@@ -88,25 +82,26 @@ class LayoutInfo {
|
||||
) { }
|
||||
}
|
||||
|
||||
export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
export class CallHierarchyTreePeekWidget extends peekView.PeekViewWidget {
|
||||
|
||||
private _changeDirectionAction?: ChangeHierarchyDirectionAction;
|
||||
private _parent!: HTMLElement;
|
||||
private _message!: HTMLElement;
|
||||
private _splitView!: SplitView;
|
||||
private _tree!: WorkbenchAsyncDataTree<callHTree.CallHierarchyRoot, callHTree.Call, FuzzyScore>;
|
||||
private _tree!: WorkbenchAsyncDataTree<CallHierarchyModel, callHTree.Call, FuzzyScore>;
|
||||
private _treeViewStates = new Map<CallHierarchyDirection, IAsyncDataTreeViewState>();
|
||||
private _editor!: EmbeddedCodeEditorWidget;
|
||||
private _dim!: Dimension;
|
||||
private _layoutInfo!: LayoutInfo;
|
||||
|
||||
private readonly _previewDisposable = new DisposableStore();
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
private readonly _where: IPosition,
|
||||
private readonly _provider: CallHierarchyProvider,
|
||||
private _direction: CallHierarchyDirection,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IPeekViewService private readonly _peekViewService: IPeekViewService,
|
||||
@peekView.IPeekViewService private readonly _peekViewService: peekView.IPeekViewService,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@ITextModelService private readonly _textModelService: ITextModelService,
|
||||
@IStorageService private readonly _storageService: IStorageService,
|
||||
@@ -117,6 +112,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
this._peekViewService.addExclusiveWidget(editor, this);
|
||||
this._applyTheme(themeService.getTheme());
|
||||
this._disposables.add(themeService.onThemeChange(this._applyTheme, this));
|
||||
this._disposables.add(this._previewDisposable);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -132,13 +128,13 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
}
|
||||
|
||||
private _applyTheme(theme: ITheme) {
|
||||
const borderColor = theme.getColor(referencesWidget.peekViewBorder) || Color.transparent;
|
||||
const borderColor = theme.getColor(peekView.peekViewBorder) || Color.transparent;
|
||||
this.style({
|
||||
arrowColor: borderColor,
|
||||
frameColor: borderColor,
|
||||
headerBackgroundColor: theme.getColor(referencesWidget.peekViewTitleBackground) || Color.transparent,
|
||||
primaryHeadingColor: theme.getColor(referencesWidget.peekViewTitleForeground),
|
||||
secondaryHeadingColor: theme.getColor(referencesWidget.peekViewTitleInfoForeground)
|
||||
headerBackgroundColor: theme.getColor(peekView.peekViewTitleBackground) || Color.transparent,
|
||||
primaryHeadingColor: theme.getColor(peekView.peekViewTitleForeground),
|
||||
secondaryHeadingColor: theme.getColor(peekView.peekViewTitleInfoForeground)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -198,18 +194,22 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
const treeContainer = document.createElement('div');
|
||||
addClass(treeContainer, 'tree');
|
||||
container.appendChild(treeContainer);
|
||||
const options: IAsyncDataTreeOptions<callHTree.Call, FuzzyScore> = {
|
||||
const options: IWorkbenchAsyncDataTreeOptions<callHTree.Call, FuzzyScore> = {
|
||||
sorter: new callHTree.Sorter(),
|
||||
identityProvider: new callHTree.IdentityProvider(() => this._direction),
|
||||
ariaLabel: localize('tree.aria', "Call Hierarchy"),
|
||||
expandOnlyOnTwistieClick: true,
|
||||
overrideStyles: {
|
||||
listBackground: peekView.peekViewResultsBackground
|
||||
}
|
||||
};
|
||||
this._tree = <any>this._instantiationService.createInstance(
|
||||
this._tree = this._instantiationService.createInstance<typeof WorkbenchAsyncDataTree, WorkbenchAsyncDataTree<CallHierarchyModel, callHTree.Call, FuzzyScore>>(
|
||||
WorkbenchAsyncDataTree,
|
||||
'CallHierarchyPeek',
|
||||
treeContainer,
|
||||
new callHTree.VirtualDelegate(),
|
||||
[this._instantiationService.createInstance(callHTree.CallRenderer)],
|
||||
this._instantiationService.createInstance(callHTree.DataSource, this._provider, () => this._direction),
|
||||
this._instantiationService.createInstance(callHTree.DataSource, () => this._direction),
|
||||
options
|
||||
);
|
||||
|
||||
@@ -244,63 +244,8 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
}
|
||||
}));
|
||||
|
||||
// session state
|
||||
const localDispose = new DisposableStore();
|
||||
this._disposables.add(localDispose);
|
||||
|
||||
// update editor
|
||||
this._disposables.add(this._tree.onDidChangeFocus(async e => {
|
||||
const [element] = e.elements;
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
localDispose.clear();
|
||||
|
||||
// update: editor and editor highlights
|
||||
const options: IModelDecorationOptions = {
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
className: 'call-decoration',
|
||||
overviewRuler: {
|
||||
color: themeColorFromId(referencesWidget.peekViewEditorMatchHighlight),
|
||||
position: OverviewRulerLane.Center
|
||||
},
|
||||
};
|
||||
|
||||
let previewUri: URI;
|
||||
if (this._direction === CallHierarchyDirection.CallsFrom) {
|
||||
// outgoing calls: show caller and highlight focused calls
|
||||
previewUri = element.parent ? element.parent.item.uri : this._tree.getInput()!.model.uri;
|
||||
} else {
|
||||
// incoming calls: show caller and highlight focused calls
|
||||
previewUri = element.item.uri;
|
||||
}
|
||||
|
||||
const value = await this._textModelService.createModelReference(previewUri);
|
||||
this._editor.setModel(value.object.textEditorModel);
|
||||
|
||||
// set decorations for caller ranges (if in the same file)
|
||||
let decorations: IModelDeltaDecoration[] = [];
|
||||
let fullRange: IRange | undefined;
|
||||
for (const loc of element.locations) {
|
||||
if (loc.uri.toString() === previewUri.toString()) {
|
||||
decorations.push({ range: loc.range, options });
|
||||
fullRange = !fullRange ? loc.range : Range.plusRange(loc.range, fullRange);
|
||||
}
|
||||
}
|
||||
if (fullRange) {
|
||||
this._editor.revealRangeInCenter(fullRange, ScrollType.Immediate);
|
||||
const ids = this._editor.deltaDecorations([], decorations);
|
||||
localDispose.add(toDisposable(() => this._editor.deltaDecorations(ids, [])));
|
||||
}
|
||||
localDispose.add(value);
|
||||
|
||||
// update: title
|
||||
const title = this._direction === CallHierarchyDirection.CallsFrom
|
||||
? localize('callFrom', "Calls from '{0}'", this._tree.getInput()!.word)
|
||||
: localize('callsTo', "Callers of '{0}'", this._tree.getInput()!.word);
|
||||
this.setTitle(title);
|
||||
}));
|
||||
this._disposables.add(this._tree.onDidChangeFocus(this._updatePreview, this));
|
||||
|
||||
this._disposables.add(this._editor.onMouseDown(e => {
|
||||
const { event, target } = e;
|
||||
@@ -346,6 +291,60 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
}));
|
||||
}
|
||||
|
||||
private async _updatePreview() {
|
||||
const [element] = this._tree.getFocus();
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._previewDisposable.clear();
|
||||
|
||||
// update: editor and editor highlights
|
||||
const options: IModelDecorationOptions = {
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
className: 'call-decoration',
|
||||
overviewRuler: {
|
||||
color: themeColorFromId(peekView.peekViewEditorMatchHighlight),
|
||||
position: OverviewRulerLane.Center
|
||||
},
|
||||
};
|
||||
|
||||
let previewUri: URI;
|
||||
if (this._direction === CallHierarchyDirection.CallsFrom) {
|
||||
// outgoing calls: show caller and highlight focused calls
|
||||
previewUri = element.parent ? element.parent.item.uri : element.model.root.uri;
|
||||
|
||||
} else {
|
||||
// incoming calls: show caller and highlight focused calls
|
||||
previewUri = element.item.uri;
|
||||
}
|
||||
|
||||
const value = await this._textModelService.createModelReference(previewUri);
|
||||
this._editor.setModel(value.object.textEditorModel);
|
||||
|
||||
// set decorations for caller ranges (if in the same file)
|
||||
let decorations: IModelDeltaDecoration[] = [];
|
||||
let fullRange: IRange | undefined;
|
||||
for (const loc of element.locations) {
|
||||
if (loc.uri.toString() === previewUri.toString()) {
|
||||
decorations.push({ range: loc.range, options });
|
||||
fullRange = !fullRange ? loc.range : Range.plusRange(loc.range, fullRange);
|
||||
}
|
||||
}
|
||||
if (fullRange) {
|
||||
this._editor.revealRangeInCenter(fullRange, ScrollType.Immediate);
|
||||
const ids = this._editor.deltaDecorations([], decorations);
|
||||
this._previewDisposable.add(toDisposable(() => this._editor.deltaDecorations(ids, [])));
|
||||
}
|
||||
this._previewDisposable.add(value);
|
||||
|
||||
// update: title
|
||||
const title = this._direction === CallHierarchyDirection.CallsFrom
|
||||
? localize('callFrom', "Calls from '{0}'", element.model.root.name)
|
||||
: localize('callsTo', "Callers of '{0}'", element.model.root.name);
|
||||
this.setTitle(title);
|
||||
}
|
||||
|
||||
showLoading(): void {
|
||||
this._parent.dataset['state'] = State.Loading;
|
||||
this.setTitle(localize('title.loading', "Loading..."));
|
||||
@@ -361,41 +360,56 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
this._message.focus();
|
||||
}
|
||||
|
||||
async showItem(item: callHTree.CallHierarchyRoot): Promise<void> {
|
||||
async showModel(model: CallHierarchyModel): Promise<void> {
|
||||
|
||||
this._show();
|
||||
const viewState = this._treeViewStates.get(this._direction);
|
||||
await this._tree.setInput(item, viewState);
|
||||
|
||||
if (this._tree.getNode(item).children.length === 0) {
|
||||
await this._tree.setInput(model, viewState);
|
||||
|
||||
const root = <ITreeNode<callHTree.Call, FuzzyScore>>this._tree.getNode(model).children[0]; // {{SQL CARBON EDIT}} strict-null-checks
|
||||
await this._tree.expand(root.element);
|
||||
|
||||
if (root.children.length === 0) {
|
||||
//
|
||||
this.showMessage(this._direction === CallHierarchyDirection.CallsFrom
|
||||
? localize('empt.callsFrom', "No calls from '{0}'", item.word)
|
||||
: localize('empt.callsTo', "No callers of '{0}'", item.word));
|
||||
? localize('empt.callsFrom', "No calls from '{0}'", model.root.name)
|
||||
: localize('empt.callsTo', "No callers of '{0}'", model.root.name));
|
||||
|
||||
} else {
|
||||
this._parent.dataset['state'] = State.Data;
|
||||
this._tree.domFocus();
|
||||
if (!viewState) {
|
||||
this._tree.focusFirst();
|
||||
this._tree.setFocus([root.children[0].element]);
|
||||
}
|
||||
this._tree.domFocus();
|
||||
this._updatePreview();
|
||||
}
|
||||
|
||||
if (!this._changeDirectionAction) {
|
||||
const changeDirection = (newDirection: CallHierarchyDirection) => {
|
||||
if (this._direction !== newDirection) {
|
||||
this._treeViewStates.set(this._direction, this._tree.getViewState());
|
||||
this._direction = newDirection;
|
||||
this._tree.setFocus([]);
|
||||
this.showItem(this._tree.getInput()!);
|
||||
}
|
||||
};
|
||||
this._changeDirectionAction = new ChangeHierarchyDirectionAction(this._direction, changeDirection);
|
||||
this._changeDirectionAction = new ChangeHierarchyDirectionAction(() => this._direction, () => this.toggleDirection());
|
||||
this._disposables.add(this._changeDirectionAction);
|
||||
this._actionbarWidget!.push(this._changeDirectionAction, { icon: true, label: false });
|
||||
}
|
||||
}
|
||||
|
||||
getModel(): CallHierarchyModel | undefined {
|
||||
return this._tree.getInput();
|
||||
}
|
||||
|
||||
getFocused(): callHTree.Call | undefined {
|
||||
return this._tree.getFocus()[0];
|
||||
}
|
||||
|
||||
async toggleDirection(): Promise<void> {
|
||||
const model = this._tree.getInput();
|
||||
if (model) {
|
||||
const newDirection = this._direction === CallHierarchyDirection.CallsTo ? CallHierarchyDirection.CallsFrom : CallHierarchyDirection.CallsTo;
|
||||
this._treeViewStates.set(this._direction, this._tree.getViewState());
|
||||
this._direction = newDirection;
|
||||
await this.showModel(model);
|
||||
}
|
||||
}
|
||||
|
||||
private _show() {
|
||||
if (!this._isShowing) {
|
||||
this.editor.revealLineInCenterIfOutsideViewport(this._where.lineNumber, ScrollType.Smooth);
|
||||
@@ -421,31 +435,31 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const referenceHighlightColor = theme.getColor(referencesWidget.peekViewEditorMatchHighlight);
|
||||
const referenceHighlightColor = theme.getColor(peekView.peekViewEditorMatchHighlight);
|
||||
if (referenceHighlightColor) {
|
||||
collector.addRule(`.monaco-editor .call-hierarchy .call-decoration { background-color: ${referenceHighlightColor}; }`);
|
||||
}
|
||||
const referenceHighlightBorder = theme.getColor(referencesWidget.peekViewEditorMatchHighlightBorder);
|
||||
const referenceHighlightBorder = theme.getColor(peekView.peekViewEditorMatchHighlightBorder);
|
||||
if (referenceHighlightBorder) {
|
||||
collector.addRule(`.monaco-editor .call-hierarchy .call-decoration { border: 2px solid ${referenceHighlightBorder}; box-sizing: border-box; }`);
|
||||
}
|
||||
const resultsBackground = theme.getColor(referencesWidget.peekViewResultsBackground);
|
||||
const resultsBackground = theme.getColor(peekView.peekViewResultsBackground);
|
||||
if (resultsBackground) {
|
||||
collector.addRule(`.monaco-editor .call-hierarchy .tree { background-color: ${resultsBackground}; }`);
|
||||
}
|
||||
const resultsMatchForeground = theme.getColor(referencesWidget.peekViewResultsFileForeground);
|
||||
const resultsMatchForeground = theme.getColor(peekView.peekViewResultsFileForeground);
|
||||
if (resultsMatchForeground) {
|
||||
collector.addRule(`.monaco-editor .call-hierarchy .tree { color: ${resultsMatchForeground}; }`);
|
||||
}
|
||||
const resultsSelectedBackground = theme.getColor(referencesWidget.peekViewResultsSelectionBackground);
|
||||
const resultsSelectedBackground = theme.getColor(peekView.peekViewResultsSelectionBackground);
|
||||
if (resultsSelectedBackground) {
|
||||
collector.addRule(`.monaco-editor .call-hierarchy .tree .monaco-list:focus .monaco-list-rows > .monaco-list-row.selected:not(.highlighted) { background-color: ${resultsSelectedBackground}; }`);
|
||||
}
|
||||
const resultsSelectedForeground = theme.getColor(referencesWidget.peekViewResultsSelectionForeground);
|
||||
const resultsSelectedForeground = theme.getColor(peekView.peekViewResultsSelectionForeground);
|
||||
if (resultsSelectedForeground) {
|
||||
collector.addRule(`.monaco-editor .call-hierarchy .tree .monaco-list:focus .monaco-list-rows > .monaco-list-row.selected:not(.highlighted) { color: ${resultsSelectedForeground} !important; }`);
|
||||
}
|
||||
const editorBackground = theme.getColor(referencesWidget.peekViewEditorBackground);
|
||||
const editorBackground = theme.getColor(peekView.peekViewEditorBackground);
|
||||
if (editorBackground) {
|
||||
collector.addRule(
|
||||
`.monaco-editor .call-hierarchy .editor .monaco-editor .monaco-editor-background,` +
|
||||
@@ -454,7 +468,7 @@ registerThemingParticipant((theme, collector) => {
|
||||
`}`
|
||||
);
|
||||
}
|
||||
const editorGutterBackground = theme.getColor(referencesWidget.peekViewEditorGutterBackground);
|
||||
const editorGutterBackground = theme.getColor(peekView.peekViewEditorGutterBackground);
|
||||
if (editorGutterBackground) {
|
||||
collector.addRule(
|
||||
`.monaco-editor .call-hierarchy .editor .monaco-editor .margin {` +
|
||||
|
||||
@@ -3,104 +3,79 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IAsyncDataSource, ITreeRenderer, ITreeNode } from 'vs/base/browser/ui/tree/tree';
|
||||
import { CallHierarchyItem, CallHierarchyProvider, CallHierarchyDirection, provideOutgoingCalls, provideIncomingCalls } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy';
|
||||
import { IAsyncDataSource, ITreeRenderer, ITreeNode, ITreeSorter } from 'vs/base/browser/ui/tree/tree';
|
||||
import { CallHierarchyItem, CallHierarchyDirection, CallHierarchyModel, } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IIdentityProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||
import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { SymbolKinds, Location } from 'vs/editor/common/modes';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { compare } from 'vs/base/common/strings';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
|
||||
export class Call {
|
||||
constructor(
|
||||
readonly item: CallHierarchyItem,
|
||||
readonly locations: Location[],
|
||||
readonly model: CallHierarchyModel,
|
||||
readonly parent: Call | undefined
|
||||
) { }
|
||||
}
|
||||
|
||||
export class CallHierarchyRoot {
|
||||
|
||||
static fromEditor(editor: IActiveCodeEditor): CallHierarchyRoot | undefined {
|
||||
const model = editor.getModel();
|
||||
const position = editor.getPosition();
|
||||
const wordInfo = model.getWordAtPosition(position);
|
||||
return wordInfo
|
||||
? new CallHierarchyRoot(model, position, wordInfo.word)
|
||||
: undefined;
|
||||
static compare(a: Call, b: Call): number {
|
||||
let res = compare(a.item.uri.toString(), b.item.uri.toString());
|
||||
if (res === 0) {
|
||||
res = Range.compareRangesUsingStarts(a.item.range, b.item.range);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
constructor(
|
||||
readonly model: ITextModel,
|
||||
readonly position: IPosition,
|
||||
readonly word: string
|
||||
) { }
|
||||
}
|
||||
|
||||
export class DataSource implements IAsyncDataSource<CallHierarchyRoot, Call> {
|
||||
export class DataSource implements IAsyncDataSource<CallHierarchyModel, Call> {
|
||||
|
||||
constructor(
|
||||
public provider: CallHierarchyProvider,
|
||||
public getDirection: () => CallHierarchyDirection,
|
||||
@ITextModelService private readonly _modelService: ITextModelService,
|
||||
) { }
|
||||
|
||||
hasChildren(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
async getChildren(element: CallHierarchyRoot | Call): Promise<Call[]> {
|
||||
async getChildren(element: CallHierarchyModel | Call): Promise<Call[]> {
|
||||
if (element instanceof CallHierarchyModel) {
|
||||
return [new Call(element.root, [], element, undefined)];
|
||||
}
|
||||
|
||||
const results: Call[] = [];
|
||||
const { model, item } = element;
|
||||
|
||||
if (this.getDirection() === CallHierarchyDirection.CallsFrom) {
|
||||
return (await model.resolveOutgoingCalls(item, CancellationToken.None)).map(call => {
|
||||
return new Call(
|
||||
call.to,
|
||||
call.fromRanges.map(range => ({ range, uri: item.uri })),
|
||||
model,
|
||||
element
|
||||
);
|
||||
});
|
||||
|
||||
if (element instanceof CallHierarchyRoot) {
|
||||
if (this.getDirection() === CallHierarchyDirection.CallsFrom) {
|
||||
await this._getOutgoingCalls(element.model, element.position, results);
|
||||
} else {
|
||||
await this._getIncomingCalls(element.model, element.position, results);
|
||||
}
|
||||
} else {
|
||||
const reference = await this._modelService.createModelReference(element.item.uri);
|
||||
const position = Range.lift(element.item.selectionRange).getStartPosition();
|
||||
if (this.getDirection() === CallHierarchyDirection.CallsFrom) {
|
||||
await this._getOutgoingCalls(reference.object.textEditorModel, position, results, element);
|
||||
} else {
|
||||
await this._getIncomingCalls(reference.object.textEditorModel, position, results, element);
|
||||
}
|
||||
reference.dispose();
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private async _getOutgoingCalls(model: ITextModel, position: IPosition, bucket: Call[], parent?: Call): Promise<void> {
|
||||
const outgoingCalls = await provideOutgoingCalls(model, position, CancellationToken.None);
|
||||
for (const call of outgoingCalls) {
|
||||
bucket.push(new Call(
|
||||
call.to,
|
||||
call.fromRanges.map(range => ({ range, uri: model.uri })),
|
||||
parent
|
||||
));
|
||||
return (await model.resolveIncomingCalls(item, CancellationToken.None)).map(call => {
|
||||
return new Call(
|
||||
call.from,
|
||||
call.fromRanges.map(range => ({ range, uri: call.from.uri })),
|
||||
model,
|
||||
element
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async _getIncomingCalls(model: ITextModel, position: IPosition, bucket: Call[], parent?: Call): Promise<void> {
|
||||
const incomingCalls = await provideIncomingCalls(model, position, CancellationToken.None);
|
||||
for (const call of incomingCalls) {
|
||||
bucket.push(new Call(
|
||||
call.from,
|
||||
call.fromRanges.map(range => ({ range, uri: call.from.uri })),
|
||||
parent
|
||||
));
|
||||
}
|
||||
export class Sorter implements ITreeSorter<Call> {
|
||||
|
||||
compare(element: Call, otherElement: Call): number {
|
||||
return Call.compare(element, otherElement);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class IdentityProvider implements IIdentityProvider<Call> {
|
||||
@@ -110,13 +85,18 @@ export class IdentityProvider implements IIdentityProvider<Call> {
|
||||
) { }
|
||||
|
||||
getId(element: Call): { toString(): string; } {
|
||||
return this.getDirection() + hash(element.item.uri.toString(), hash(JSON.stringify(element.item.range))).toString() + (element.parent ? this.getId(element.parent) : '');
|
||||
let res = this.getDirection() + JSON.stringify(element.item.uri) + JSON.stringify(element.item.range);
|
||||
if (element.parent) {
|
||||
res += this.getId(element.parent);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
class CallRenderingTemplate {
|
||||
constructor(
|
||||
readonly iconLabel: IconLabel
|
||||
readonly icon: HTMLDivElement,
|
||||
readonly label: IconLabel
|
||||
) { }
|
||||
}
|
||||
|
||||
@@ -127,24 +107,23 @@ export class CallRenderer implements ITreeRenderer<Call, FuzzyScore, CallRenderi
|
||||
templateId: string = CallRenderer.id;
|
||||
|
||||
renderTemplate(container: HTMLElement): CallRenderingTemplate {
|
||||
const iconLabel = new IconLabel(container, { supportHighlights: true });
|
||||
return new CallRenderingTemplate(iconLabel);
|
||||
dom.addClass(container, 'callhierarchy-element');
|
||||
let icon = document.createElement('div');
|
||||
container.appendChild(icon);
|
||||
const label = new IconLabel(container, { supportHighlights: true });
|
||||
return new CallRenderingTemplate(icon, label);
|
||||
}
|
||||
renderElement(node: ITreeNode<Call, FuzzyScore>, _index: number, template: CallRenderingTemplate): void {
|
||||
const { element, filterData } = node;
|
||||
|
||||
template.iconLabel.setLabel(
|
||||
template.icon.className = SymbolKinds.toCssClassName(element.item.kind, true);
|
||||
template.label.setLabel(
|
||||
element.item.name,
|
||||
element.item.detail,
|
||||
{
|
||||
labelEscapeNewLines: true,
|
||||
matches: createMatches(filterData),
|
||||
extraClasses: [SymbolKinds.toCssClassName(element.item.kind, true)]
|
||||
}
|
||||
{ labelEscapeNewLines: true, matches: createMatches(filterData) }
|
||||
);
|
||||
}
|
||||
disposeTemplate(template: CallRenderingTemplate): void {
|
||||
template.iconLabel.dispose();
|
||||
template.label.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,3 +38,14 @@
|
||||
.monaco-workbench .call-hierarchy .tree {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-workbench .call-hierarchy .tree .callhierarchy-element {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-workbench .call-hierarchy .tree .callhierarchy-element .monaco-icon-label {
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ class InstallAction extends Action {
|
||||
|
||||
promisify(cp.exec)(command, {})
|
||||
.then(undefined, _ => Promise.reject(new Error(nls.localize('cantCreateBinFolder', "Unable to create '/usr/local/bin'."))))
|
||||
.then(resolve, reject);
|
||||
.then(() => resolve(), reject);
|
||||
break;
|
||||
case 1 /* Cancel */:
|
||||
reject(new Error(nls.localize('aborted', "Aborted")));
|
||||
@@ -175,7 +175,7 @@ class UninstallAction extends Action {
|
||||
|
||||
promisify(cp.exec)(command, {})
|
||||
.then(undefined, _ => Promise.reject(new Error(nls.localize('cantUninstall', "Unable to uninstall the shell command '{0}'.", this.target))))
|
||||
.then(resolve, reject);
|
||||
.then(() => resolve(), reject);
|
||||
break;
|
||||
case 1 /* Cancel */:
|
||||
reject(new Error(nls.localize('aborted', "Aborted")));
|
||||
@@ -189,6 +189,6 @@ if (platform.isMacintosh) {
|
||||
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 \'${product.applicationName}\' command in PATH`, category);
|
||||
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(UninstallAction, UninstallAction.ID, UninstallAction.LABEL), `Shell Command: Uninstall \'${product.applicationName}\' command from PATH`, category);
|
||||
workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.create(InstallAction, InstallAction.ID, InstallAction.LABEL), `Shell Command: Install \'${product.applicationName}\' command in PATH`, category);
|
||||
workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.create(UninstallAction, UninstallAction.ID, UninstallAction.LABEL), `Shell Command: Uninstall \'${product.applicationName}\' command from PATH`, category);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { CodeActionWorkbenchContribution, editorConfiguration } from 'vs/workbench/contrib/codeActions/common/configuration';
|
||||
import { CodeActionsExtensionPoint, codeActionsExtensionPointDescriptor } from 'vs/workbench/contrib/codeActions/common/extensionPoint';
|
||||
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
|
||||
const codeActionsExtensionPoint = ExtensionsRegistry.registerExtensionPoint<CodeActionsExtensionPoint[]>(codeActionsExtensionPointDescriptor);
|
||||
|
||||
Registry.as<IConfigurationRegistry>(Extensions.Configuration)
|
||||
.registerConfiguration(editorConfiguration);
|
||||
|
||||
class WorkbenchContribution {
|
||||
constructor(
|
||||
@IKeybindingService keybindingsService: IKeybindingService,
|
||||
) {
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
new CodeActionWorkbenchContribution(codeActionsExtensionPoint, keybindingsService);
|
||||
}
|
||||
}
|
||||
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
|
||||
.registerWorkbenchContribution(WorkbenchContribution, LifecyclePhase.Eventually);
|
||||
155
src/vs/workbench/contrib/codeActions/common/configuration.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { flatten } from 'vs/base/common/arrays';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { codeActionCommandId, refactorCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
import { CodeActionKind } from 'vs/editor/contrib/codeAction/types';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Extensions, IConfigurationNode, IConfigurationRegistry, ConfigurationScope, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { CodeActionsExtensionPoint, ContributedCodeAction } from 'vs/workbench/contrib/codeActions/common/extensionPoint';
|
||||
import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { editorConfigurationBaseNode } from 'vs/editor/common/config/commonEditorConfig';
|
||||
|
||||
const codeActionsOnSaveDefaultProperties = Object.freeze<IJSONSchemaMap>({
|
||||
'source.fixAll': {
|
||||
type: 'boolean',
|
||||
description: nls.localize('codeActionsOnSave.fixAll', "Controls whether auto fix action should be run on file save.")
|
||||
}
|
||||
});
|
||||
|
||||
const codeActionsOnSaveSchema: IConfigurationPropertySchema = {
|
||||
type: 'object',
|
||||
properties: codeActionsOnSaveDefaultProperties,
|
||||
'additionalProperties': {
|
||||
type: 'boolean'
|
||||
},
|
||||
default: {},
|
||||
description: nls.localize('codeActionsOnSave', "Code action kinds to be run on save."),
|
||||
scope: ConfigurationScope.RESOURCE
|
||||
};
|
||||
|
||||
export const editorConfiguration = Object.freeze<IConfigurationNode>({
|
||||
...editorConfigurationBaseNode,
|
||||
properties: {
|
||||
'editor.codeActionsOnSave': codeActionsOnSaveSchema,
|
||||
'editor.codeActionsOnSaveTimeout': {
|
||||
type: 'number',
|
||||
default: 750,
|
||||
description: nls.localize('codeActionsOnSaveTimeout', "Timeout in milliseconds after which the code actions that are run on save are cancelled."),
|
||||
scope: ConfigurationScope.RESOURCE
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
export class CodeActionWorkbenchContribution extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private _contributedCodeActions: CodeActionsExtensionPoint[] = [];
|
||||
|
||||
private readonly _onDidChangeContributions = this._register(new Emitter<void>());
|
||||
|
||||
constructor(
|
||||
codeActionsExtensionPoint: IExtensionPoint<CodeActionsExtensionPoint[]>,
|
||||
keybindingService: IKeybindingService,
|
||||
) {
|
||||
super();
|
||||
|
||||
codeActionsExtensionPoint.setHandler(extensionPoints => {
|
||||
this._contributedCodeActions = flatten(extensionPoints.map(x => x.value));
|
||||
this.updateConfigurationSchema(this._contributedCodeActions);
|
||||
this._onDidChangeContributions.fire();
|
||||
});
|
||||
|
||||
keybindingService.registerSchemaContribution({
|
||||
getSchemaAdditions: () => this.getSchemaAdditions(),
|
||||
onDidChange: this._onDidChangeContributions.event,
|
||||
});
|
||||
}
|
||||
|
||||
private updateConfigurationSchema(codeActionContributions: readonly CodeActionsExtensionPoint[]) {
|
||||
const newProperties: IJSONSchemaMap = { ...codeActionsOnSaveDefaultProperties };
|
||||
for (const [sourceAction, props] of this.getSourceActions(codeActionContributions)) {
|
||||
newProperties[sourceAction] = {
|
||||
type: 'boolean',
|
||||
description: nls.localize('codeActionsOnSave.generic', "Controls whether '{0}' actions should be run on file save.", props.title)
|
||||
};
|
||||
}
|
||||
codeActionsOnSaveSchema.properties = newProperties;
|
||||
Registry.as<IConfigurationRegistry>(Extensions.Configuration)
|
||||
.notifyConfigurationSchemaUpdated(editorConfiguration);
|
||||
}
|
||||
|
||||
private getSourceActions(contributions: readonly CodeActionsExtensionPoint[]) {
|
||||
const defaultKinds = Object.keys(codeActionsOnSaveDefaultProperties).map(value => new CodeActionKind(value));
|
||||
const sourceActions = new Map<string, { readonly title: string }>();
|
||||
for (const contribution of contributions) {
|
||||
for (const action of contribution.actions) {
|
||||
const kind = new CodeActionKind(action.kind);
|
||||
if (CodeActionKind.Source.contains(kind)
|
||||
// Exclude any we already included by default
|
||||
&& !defaultKinds.some(defaultKind => defaultKind.contains(kind))
|
||||
) {
|
||||
sourceActions.set(kind.value, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sourceActions;
|
||||
}
|
||||
|
||||
private getSchemaAdditions(): IJSONSchema[] {
|
||||
const conditionalSchema = (command: string, actions: readonly ContributedCodeAction[]): IJSONSchema => {
|
||||
return {
|
||||
if: {
|
||||
properties: {
|
||||
'command': { const: command }
|
||||
}
|
||||
},
|
||||
then: {
|
||||
required: ['args'],
|
||||
properties: {
|
||||
'args': {
|
||||
required: ['kind'],
|
||||
properties: {
|
||||
'kind': {
|
||||
anyOf: [
|
||||
{
|
||||
enum: actions.map(action => action.kind),
|
||||
enumDescriptions: actions.map(action => action.description ?? action.title),
|
||||
},
|
||||
{ type: 'string' },
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const getActions = (ofKind: CodeActionKind): ContributedCodeAction[] => {
|
||||
const allActions = flatten(this._contributedCodeActions.map(desc => desc.actions.slice()));
|
||||
|
||||
const out = new Map<string, ContributedCodeAction>();
|
||||
for (const action of allActions) {
|
||||
if (!out.has(action.kind) && ofKind.contains(new CodeActionKind(action.kind))) {
|
||||
out.set(action.kind, action);
|
||||
}
|
||||
}
|
||||
return values(out);
|
||||
};
|
||||
|
||||
return [
|
||||
conditionalSchema(codeActionCommandId, getActions(CodeActionKind.Empty)),
|
||||
conditionalSchema(refactorCommandId, getActions(CodeActionKind.Refactor)),
|
||||
conditionalSchema(sourceActionCommandId, getActions(CodeActionKind.Source)),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { languagesExtPoint } from 'vs/workbench/services/mode/common/workbenchModeService';
|
||||
|
||||
export enum CodeActionExtensionPointFields {
|
||||
languages = 'languages',
|
||||
actions = 'actions',
|
||||
kind = 'kind',
|
||||
title = 'title',
|
||||
description = 'description'
|
||||
}
|
||||
|
||||
export interface ContributedCodeAction {
|
||||
readonly [CodeActionExtensionPointFields.kind]: string;
|
||||
readonly [CodeActionExtensionPointFields.title]: string;
|
||||
readonly [CodeActionExtensionPointFields.description]?: string;
|
||||
}
|
||||
|
||||
export interface CodeActionsExtensionPoint {
|
||||
readonly [CodeActionExtensionPointFields.languages]: readonly string[];
|
||||
readonly [CodeActionExtensionPointFields.actions]: readonly ContributedCodeAction[];
|
||||
}
|
||||
|
||||
const codeActionsExtensionPointSchema = Object.freeze<IConfigurationPropertySchema>({
|
||||
type: 'array',
|
||||
markdownDescription: nls.localize('contributes.codeActions', "Configure which editor to use for a resource."),
|
||||
items: {
|
||||
type: 'object',
|
||||
required: [CodeActionExtensionPointFields.languages, CodeActionExtensionPointFields.actions],
|
||||
properties: {
|
||||
[CodeActionExtensionPointFields.languages]: {
|
||||
type: 'array',
|
||||
description: nls.localize('contributes.codeActions.languages', "Language modes that the code actions are enabled for."),
|
||||
items: { type: 'string' }
|
||||
},
|
||||
[CodeActionExtensionPointFields.actions]: {
|
||||
type: 'object',
|
||||
required: [CodeActionExtensionPointFields.kind, CodeActionExtensionPointFields.title],
|
||||
properties: {
|
||||
[CodeActionExtensionPointFields.kind]: {
|
||||
type: 'string',
|
||||
markdownDescription: nls.localize('contributes.codeActions.kind', "`CodeActionKind` of the contributed code action."),
|
||||
},
|
||||
[CodeActionExtensionPointFields.title]: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.codeActions.title', "Label for the code action used in the UI."),
|
||||
},
|
||||
[CodeActionExtensionPointFields.description]: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.codeActions.description', "Description of what the code action does."),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const codeActionsExtensionPointDescriptor = {
|
||||
extensionPoint: 'codeActions',
|
||||
deps: [languagesExtPoint],
|
||||
jsonSchema: codeActionsExtensionPointSchema
|
||||
};
|
||||
@@ -6,4 +6,5 @@
|
||||
.monaco-editor .accessibilityHelpWidget {
|
||||
padding: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@@ -263,11 +263,13 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget {
|
||||
private _layout(): void {
|
||||
let editorLayout = this._editor.getLayoutInfo();
|
||||
|
||||
let top = Math.round((editorLayout.height - AccessibilityHelpWidget.HEIGHT) / 2);
|
||||
this._domNode.setTop(top);
|
||||
const width = Math.min(editorLayout.width - 40, AccessibilityHelpWidget.WIDTH);
|
||||
const height = Math.min(editorLayout.height - 40, AccessibilityHelpWidget.HEIGHT);
|
||||
|
||||
let left = Math.round((editorLayout.width - AccessibilityHelpWidget.WIDTH) / 2);
|
||||
this._domNode.setLeft(left);
|
||||
this._domNode.setTop(Math.round((editorLayout.height - height) / 2));
|
||||
this._domNode.setLeft(Math.round((editorLayout.width - width) / 2));
|
||||
this._domNode.setWidth(width);
|
||||
this._domNode.setHeight(height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import { IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBo
|
||||
import { SimpleButton } from 'vs/editor/contrib/find/findWidget';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { editorWidgetBackground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { editorWidgetBackground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { ContextScopedFindInput } from 'vs/platform/browser/contextScopedHistoryWidget';
|
||||
|
||||
@@ -280,6 +280,11 @@ registerThemingParticipant((theme, collector) => {
|
||||
collector.addRule(`.monaco-workbench .simple-find-part { background-color: ${findWidgetBGColor} !important; }`);
|
||||
}
|
||||
|
||||
const widgetForeground = theme.getColor(editorWidgetForeground);
|
||||
if (widgetForeground) {
|
||||
collector.addRule(`.monaco-workbench .simple-find-part { color: ${widgetForeground}; }`);
|
||||
}
|
||||
|
||||
const widgetShadowColor = theme.getColor(widgetShadow);
|
||||
if (widgetShadowColor) {
|
||||
collector.addRule(`.monaco-workbench .simple-find-part { box-shadow: 0 2px 8px ${widgetShadowColor}; }`);
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IUntitledResourceInput } from 'vs/workbench/common/editor';
|
||||
import { IUntitledTextResourceInput } from 'vs/workbench/common/editor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
|
||||
@@ -29,7 +29,7 @@ class InspectKeyMap extends EditorAction {
|
||||
const keybindingService = accessor.get(IKeybindingService);
|
||||
const editorService = accessor.get(IEditorService);
|
||||
|
||||
editorService.openEditor({ contents: keybindingService._dumpDebugInfo(), options: { pinned: true } } as IUntitledResourceInput);
|
||||
editorService.openEditor({ contents: keybindingService._dumpDebugInfo(), options: { pinned: true } } as IUntitledTextResourceInput);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,9 +49,9 @@ class InspectKeyMapJSON extends Action {
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this._editorService.openEditor({ contents: this._keybindingService._dumpDebugInfoJSON(), options: { pinned: true } } as IUntitledResourceInput);
|
||||
return this._editorService.openEditor({ contents: this._keybindingService._dumpDebugInfoJSON(), options: { pinned: true } } as IUntitledTextResourceInput);
|
||||
}
|
||||
}
|
||||
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(InspectKeyMapJSON, InspectKeyMapJSON.ID, InspectKeyMapJSON.LABEL), 'Developer: Inspect Key Mappings (JSON)', nls.localize('developer', "Developer"));
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(InspectKeyMapJSON, InspectKeyMapJSON.ID, InspectKeyMapJSON.LABEL), 'Developer: Inspect Key Mappings (JSON)', nls.localize('developer', "Developer"));
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
.tm-inspect-widget {
|
||||
z-index: 50;
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ class InspectTMScopesWidget extends Disposable implements IContentWidget {
|
||||
private readonly _notificationService: INotificationService;
|
||||
private readonly _model: ITextModel;
|
||||
private readonly _domNode: HTMLElement;
|
||||
private readonly _grammar: Promise<IGrammar>;
|
||||
private readonly _grammar: Promise<IGrammar | null>;
|
||||
|
||||
constructor(
|
||||
editor: IActiveCodeEditor,
|
||||
@@ -212,7 +212,12 @@ class InspectTMScopesWidget extends Disposable implements IContentWidget {
|
||||
dom.clearNode(this._domNode);
|
||||
this._domNode.appendChild(document.createTextNode(nls.localize('inspectTMScopesWidget.loading', "Loading...")));
|
||||
this._grammar.then(
|
||||
(grammar) => this._compute(grammar, position),
|
||||
(grammar) => {
|
||||
if (!grammar) {
|
||||
throw new Error(`Could not find grammar for language!`);
|
||||
}
|
||||
this._compute(grammar, position);
|
||||
},
|
||||
(err) => {
|
||||
this._notificationService.warn(err);
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { ParseError, parse } from 'vs/base/common/json';
|
||||
import { ParseError, parse, getNodeType } from 'vs/base/common/json';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -12,12 +12,12 @@ import { LanguageIdentifier } from 'vs/editor/common/modes';
|
||||
import { CharacterPair, CommentRule, FoldingRules, IAutoClosingPair, IAutoClosingPairConditional, IndentationRule, LanguageConfiguration } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService';
|
||||
import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages';
|
||||
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
|
||||
|
||||
interface IRegExp {
|
||||
pattern: string;
|
||||
@@ -43,7 +43,16 @@ interface ILanguageConfiguration {
|
||||
}
|
||||
|
||||
function isStringArr(something: string[] | null): something is string[] {
|
||||
return Array.isArray(something) && something.every(value => typeof value === 'string');
|
||||
if (!Array.isArray(something)) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0, len = something.length; i < len; i++) {
|
||||
if (typeof something[i] !== 'string') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
function isCharacterPair(something: CharacterPair | null): boolean {
|
||||
@@ -60,7 +69,7 @@ export class LanguageConfigurationFileHandler {
|
||||
constructor(
|
||||
@ITextMateService textMateService: ITextMateService,
|
||||
@IModeService private readonly _modeService: IModeService,
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@IExtensionResourceLoaderService private readonly _extensionResourceLoaderService: IExtensionResourceLoaderService,
|
||||
@IExtensionService private readonly _extensionService: IExtensionService
|
||||
) {
|
||||
this._done = [];
|
||||
@@ -89,12 +98,16 @@ export class LanguageConfigurationFileHandler {
|
||||
}
|
||||
|
||||
private _handleConfigFile(languageIdentifier: LanguageIdentifier, configFileLocation: URI): void {
|
||||
this._fileService.readFile(configFileLocation).then((contents) => {
|
||||
this._extensionResourceLoaderService.readExtensionResource(configFileLocation).then((contents) => {
|
||||
const errors: ParseError[] = [];
|
||||
const configuration = <ILanguageConfiguration>parse(contents.value.toString(), errors);
|
||||
let configuration = <ILanguageConfiguration>parse(contents, errors);
|
||||
if (errors.length) {
|
||||
console.error(nls.localize('parseErrors', "Errors parsing {0}: {1}", configFileLocation.toString(), errors.map(e => (`[${e.offset}, ${e.length}] ${getParseErrorMessage(e.error)}`)).join('\n')));
|
||||
}
|
||||
if (getNodeType(configuration) !== 'object') {
|
||||
console.error(nls.localize('formatError', "{0}: Invalid format, JSON object expected.", configFileLocation.toString()));
|
||||
configuration = {};
|
||||
}
|
||||
this._handleConfig(languageIdentifier, configuration);
|
||||
}, (err) => {
|
||||
console.error(err);
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
.suggest-input-container .monaco-editor-background,
|
||||
.suggest-input-container .monaco-editor,
|
||||
.suggest-input-container .mtk1 {
|
||||
/* allow the embedded monaco to be styled from the outer context */
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
@@ -25,4 +23,3 @@
|
||||
margin-top: 2px;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,12 +27,13 @@ import { SuggestController } from 'vs/editor/contrib/suggest/suggestController';
|
||||
import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ColorIdentifier, editorSelectionBackground, inputBackground, inputBorder, inputForeground, inputPlaceholderForeground, selectionBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IStyleOverrides, IThemable, attachStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IStyleOverrides, attachStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer';
|
||||
import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions';
|
||||
import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard';
|
||||
import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions';
|
||||
import { IThemable } from 'vs/base/common/styler';
|
||||
|
||||
interface SuggestResultsProvider {
|
||||
/**
|
||||
@@ -81,7 +82,7 @@ export interface ISuggestEnabledInputStyleOverrides extends IStyleOverrides {
|
||||
}
|
||||
|
||||
type ISuggestEnabledInputStyles = {
|
||||
[P in keyof ISuggestEnabledInputStyleOverrides]: Color;
|
||||
[P in keyof ISuggestEnabledInputStyleOverrides]: Color | undefined;
|
||||
};
|
||||
|
||||
export function attachSuggestEnabledInputBoxStyler(widget: IThemable, themeService: IThemeService, style?: ISuggestEnabledInputStyleOverrides): IDisposable {
|
||||
@@ -223,7 +224,8 @@ export class SuggestEnabledInput extends Widget implements IThemable {
|
||||
|
||||
|
||||
public style(colors: ISuggestEnabledInputStyles): void {
|
||||
this.stylingContainer.style.backgroundColor = colors.inputBackground ? colors.inputBackground.toString() : '';
|
||||
this.placeholderText.style.backgroundColor =
|
||||
this.stylingContainer.style.backgroundColor = colors.inputBackground ? colors.inputBackground.toString() : '';
|
||||
this.stylingContainer.style.color = colors.inputForeground ? colors.inputForeground.toString() : null;
|
||||
this.placeholderText.style.color = colors.inputPlaceholderForeground ? colors.inputPlaceholderForeground.toString() : null;
|
||||
|
||||
@@ -247,9 +249,13 @@ export class SuggestEnabledInput extends Widget implements IThemable {
|
||||
}
|
||||
}
|
||||
|
||||
public onHide(): void {
|
||||
this.inputWidget.onHide();
|
||||
}
|
||||
|
||||
public layout(dimension: Dimension): void {
|
||||
this.inputWidget.layout(dimension);
|
||||
this.placeholderText.style.width = `${dimension.width}px`;
|
||||
this.placeholderText.style.width = `${dimension.width - 2}px`;
|
||||
}
|
||||
|
||||
private selectAll(): void {
|
||||
@@ -281,6 +287,12 @@ registerThemingParticipant((theme, collector) => {
|
||||
if (inputForegroundColor) {
|
||||
collector.addRule(`.suggest-input-container .monaco-editor .view-line span.inline-selected-text { color: ${inputForegroundColor}; }`);
|
||||
}
|
||||
|
||||
const backgroundColor = theme.getColor(inputBackground);
|
||||
if (backgroundColor) {
|
||||
collector.addRule(`.suggest-input-container .monaco-editor-background { background-color: ${backgroundColor}; } `);
|
||||
collector.addRule(`.suggest-input-container .monaco-editor { background-color: ${backgroundColor}; } `);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export class ToggleMinimapAction extends Action {
|
||||
}
|
||||
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMinimapAction, ToggleMinimapAction.ID, ToggleMinimapAction.LABEL), 'View: Toggle Minimap', nls.localize('view', "View"));
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleMinimapAction, ToggleMinimapAction.ID, ToggleMinimapAction.LABEL), 'View: Toggle Minimap', nls.localize('view', "View"));
|
||||
|
||||
/* {{SQL CARBON EDIT}} - Disable unused menu item
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
|
||||
@@ -66,7 +66,7 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).regi
|
||||
|
||||
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMultiCursorModifierAction, ToggleMultiCursorModifierAction.ID, ToggleMultiCursorModifierAction.LABEL), 'Toggle Multi-Cursor Modifier');
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleMultiCursorModifierAction, ToggleMultiCursorModifierAction.ID, ToggleMultiCursorModifierAction.LABEL), 'Toggle Multi-Cursor Modifier');
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSelectionMenu, {
|
||||
group: '3_multi',
|
||||
command: {
|
||||
@@ -88,4 +88,4 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSelectionMenu, {
|
||||
},
|
||||
when: multiCursorModifier.isEqualTo('altKey'),
|
||||
order: 1
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ export class ToggleRenderControlCharacterAction extends Action {
|
||||
}
|
||||
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRenderControlCharacterAction, ToggleRenderControlCharacterAction.ID, ToggleRenderControlCharacterAction.LABEL), 'View: Toggle Control Characters', nls.localize('view', "View"));
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleRenderControlCharacterAction, ToggleRenderControlCharacterAction.ID, ToggleRenderControlCharacterAction.LABEL), 'View: Toggle Control Characters', nls.localize('view', "View"));
|
||||
|
||||
/* {{SQL CARBON EDIT}} - Disable unused menu item
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
|
||||
@@ -39,7 +39,7 @@ export class ToggleRenderWhitespaceAction extends Action {
|
||||
}
|
||||
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRenderWhitespaceAction, ToggleRenderWhitespaceAction.ID, ToggleRenderWhitespaceAction.LABEL), 'View: Toggle Render Whitespace', nls.localize('view', "View"));
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(ToggleRenderWhitespaceAction, ToggleRenderWhitespaceAction.ID, ToggleRenderWhitespaceAction.LABEL), 'View: Toggle Render Whitespace', nls.localize('view', "View"));
|
||||
|
||||
/* {{SQL CARBON EDIT}} - Disable unused menu item
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
|
||||
@@ -211,6 +211,10 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution
|
||||
// in the settings editor...
|
||||
return;
|
||||
}
|
||||
if (this.editor.isSimpleWidget) {
|
||||
// in a simple widget...
|
||||
return;
|
||||
}
|
||||
// Ensure correct word wrap settings
|
||||
const newModel = this.editor.getModel();
|
||||
if (!newModel) {
|
||||
@@ -275,7 +279,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
|
||||
command: {
|
||||
id: TOGGLE_WORD_WRAP_ID,
|
||||
title: nls.localize('unwrapMinified', "Disable wrapping for this file"),
|
||||
iconLocation: {
|
||||
icon: {
|
||||
dark: WORD_WRAP_DARK_ICON,
|
||||
light: WORD_WRAP_LIGHT_ICON
|
||||
}
|
||||
@@ -292,7 +296,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
|
||||
command: {
|
||||
id: TOGGLE_WORD_WRAP_ID,
|
||||
title: nls.localize('wrapMinified', "Enable wrapping for this file"),
|
||||
iconLocation: {
|
||||
icon: {
|
||||
dark: WORD_WRAP_DARK_ICON,
|
||||
light: WORD_WRAP_LIGHT_ICON
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { ReferencesController } from 'vs/editor/contrib/referenceSearch/referencesController';
|
||||
import { ReferencesController } from 'vs/editor/contrib/gotoSymbol/peek/referencesController';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import './inputClipboardActions';
|
||||
import './sleepResumeRepaintMinimap';
|
||||
import './selectionClipboard';
|
||||
|
||||
@@ -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.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
|
||||
if (platform.isMacintosh) {
|
||||
|
||||
// On the mac, cmd+x, cmd+c and cmd+v do not result in cut / copy / paste
|
||||
// We therefore add a basic keybinding rule that invokes document.execCommand
|
||||
// This is to cover <input>s...
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'execCut',
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_X,
|
||||
handler: bindExecuteCommand('cut'),
|
||||
weight: 0,
|
||||
when: undefined,
|
||||
});
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'execCopy',
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_C,
|
||||
handler: bindExecuteCommand('copy'),
|
||||
weight: 0,
|
||||
when: undefined,
|
||||
});
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'execPaste',
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_V,
|
||||
handler: bindExecuteCommand('paste'),
|
||||
weight: 0,
|
||||
when: undefined,
|
||||
});
|
||||
|
||||
function bindExecuteCommand(command: 'cut' | 'copy' | 'paste') {
|
||||
return () => {
|
||||
document.execCommand(command);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { ICodeEditor, IEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
@@ -15,6 +15,10 @@ import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { EndOfLinePreference } from 'vs/editor/common/model';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
export class SelectionClipboard extends Disposable implements IEditorContribution {
|
||||
private static readonly SELECTION_LENGTH_LIMIT = 65536;
|
||||
@@ -31,15 +35,6 @@ export class SelectionClipboard extends Disposable implements IEditorContributio
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(editor.onMouseUp((e: IEditorMouseEvent) => {
|
||||
if (!isEnabled) {
|
||||
if (e.event.middleButton) {
|
||||
// try to stop the upcoming paste
|
||||
e.event.preventDefault();
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
let setSelectionToClipboard = this._register(new RunOnceScheduler(() => {
|
||||
if (!editor.hasModel()) {
|
||||
return;
|
||||
@@ -92,4 +87,25 @@ export class SelectionClipboard extends Disposable implements IEditorContributio
|
||||
}
|
||||
}
|
||||
|
||||
class SelectionClipboardPastePreventer implements IWorkbenchContribution {
|
||||
constructor(
|
||||
@IConfigurationService configurationService: IConfigurationService
|
||||
) {
|
||||
if (platform.isLinux) {
|
||||
document.addEventListener('mouseup', (e) => {
|
||||
if (e.button === 1) {
|
||||
// middle button
|
||||
const config = configurationService.getValue<{ selectionClipboard: boolean; }>('editor');
|
||||
if (!config.selectionClipboard) {
|
||||
// selection clipboard is disabled
|
||||
// try to stop the upcoming paste
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerEditorContribution(SelectionClipboardContributionID, SelectionClipboard);
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(SelectionClipboardPastePreventer, LifecyclePhase.Ready);
|
||||
|
||||
@@ -57,7 +57,7 @@ export class CommentNode extends Disposable {
|
||||
protected toolbar: ToolBar | undefined;
|
||||
private _commentFormActions: CommentFormActions | null = null;
|
||||
|
||||
private readonly _onDidDelete = new Emitter<CommentNode>();
|
||||
private readonly _onDidClick = new Emitter<CommentNode>();
|
||||
|
||||
public get domNode(): HTMLElement {
|
||||
return this._domNode;
|
||||
@@ -89,7 +89,7 @@ export class CommentNode extends Disposable {
|
||||
this._contextKeyService = contextKeyService.createScoped(this._domNode);
|
||||
this._commentContextValue = this._contextKeyService.createKey('comment', comment.contextValue);
|
||||
|
||||
this._domNode.tabIndex = 0;
|
||||
this._domNode.tabIndex = -1;
|
||||
const avatar = dom.append(this._domNode, dom.$('div.avatar-container'));
|
||||
if (comment.userIconPath) {
|
||||
const img = <HTMLImageElement>dom.append(avatar, dom.$('img.avatar'));
|
||||
@@ -111,10 +111,12 @@ export class CommentNode extends Disposable {
|
||||
this._domNode.setAttribute('aria-label', `${comment.userName}, ${comment.body.value}`);
|
||||
this._domNode.setAttribute('role', 'treeitem');
|
||||
this._clearTimeout = null;
|
||||
|
||||
this._register(dom.addDisposableListener(this._domNode, dom.EventType.CLICK, () => this.isEditing || this._onDidClick.fire(this)));
|
||||
}
|
||||
|
||||
public get onDidDelete(): Event<CommentNode> {
|
||||
return this._onDidDelete.event;
|
||||
public get onDidClick(): Event<CommentNode> {
|
||||
return this._onDidClick.event;
|
||||
}
|
||||
|
||||
private createHeader(commentDetailsContainer: HTMLElement): void {
|
||||
@@ -430,19 +432,31 @@ export class CommentNode extends Disposable {
|
||||
this._commentFormActions.setActions(menu);
|
||||
}
|
||||
|
||||
setFocus(focused: boolean, visible: boolean = false) {
|
||||
if (focused) {
|
||||
this._domNode.focus();
|
||||
this._actionsToolbarContainer.classList.remove('hidden');
|
||||
this._actionsToolbarContainer.classList.add('tabfocused');
|
||||
this._domNode.tabIndex = 0;
|
||||
} else {
|
||||
if (this._actionsToolbarContainer.classList.contains('tabfocused') && !this._actionsToolbarContainer.classList.contains('mouseover')) {
|
||||
this._actionsToolbarContainer.classList.add('hidden');
|
||||
this._domNode.tabIndex = -1;
|
||||
}
|
||||
this._actionsToolbarContainer.classList.remove('tabfocused');
|
||||
}
|
||||
}
|
||||
|
||||
private registerActionBarListeners(actionsContainer: HTMLElement): void {
|
||||
this._register(dom.addDisposableListener(this._domNode, 'mouseenter', () => {
|
||||
actionsContainer.classList.remove('hidden');
|
||||
actionsContainer.classList.add('mouseover');
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(this._domNode, 'focus', () => {
|
||||
actionsContainer.classList.remove('hidden');
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(this._domNode, 'mouseleave', () => {
|
||||
if (!this._domNode.contains(document.activeElement)) {
|
||||
if (actionsContainer.classList.contains('mouseover') && !actionsContainer.classList.contains('tabfocused')) {
|
||||
actionsContainer.classList.add('hidden');
|
||||
}
|
||||
actionsContainer.classList.remove('mouseover');
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -23,11 +23,11 @@ import * as modes from 'vs/editor/common/modes';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer';
|
||||
import { peekViewBorder } from 'vs/editor/contrib/referenceSearch/referencesWidget';
|
||||
import { peekViewBorder } from 'vs/editor/contrib/peekView/peekView';
|
||||
import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IMenu, MenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { IMenu, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -46,6 +46,8 @@ import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/comme
|
||||
import { SimpleCommentEditor } from './simpleCommentEditor';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
|
||||
export const COMMENTEDITOR_DECORATION_KEY = 'commenteditordecoration';
|
||||
const COLLAPSE_ACTION_CLASS = 'expand-review-action';
|
||||
@@ -84,6 +86,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
||||
private _commentEditorIsEmpty!: IContextKey<boolean>;
|
||||
private _commentFormActions!: CommentFormActions;
|
||||
private _scopedInstatiationService: IInstantiationService;
|
||||
private _focusedComment: number | undefined = undefined;
|
||||
|
||||
public get owner(): string {
|
||||
return this._owner;
|
||||
@@ -257,7 +260,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
||||
}
|
||||
|
||||
private setActionBarActions(menu: IMenu): void {
|
||||
const groups = menu.getActions({ shouldForwardArgs: true }).reduce((r, [, actions]) => [...r, ...actions], <MenuItemAction[]>[]);
|
||||
const groups = menu.getActions({ shouldForwardArgs: true }).reduce((r, [, actions]) => [...r, ...actions], <(MenuItemAction | SubmenuItemAction)[]>[]);
|
||||
this._actionbarWidget.clear();
|
||||
this._actionbarWidget.push([...groups, this._collapseAction], { label: false, icon: true });
|
||||
}
|
||||
@@ -268,6 +271,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
||||
}
|
||||
|
||||
public collapse(): Promise<void> {
|
||||
this._commentThread.collapsibleState = modes.CommentThreadCollapsibleState.Collapsed;
|
||||
if (this._commentThread.comments && this._commentThread.comments.length === 0) {
|
||||
this.deleteCommentThread();
|
||||
return Promise.resolve();
|
||||
@@ -286,11 +290,13 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
||||
|
||||
toggleExpand(lineNumber: number) {
|
||||
if (this._isExpanded) {
|
||||
this._commentThread.collapsibleState = modes.CommentThreadCollapsibleState.Collapsed;
|
||||
this.hide();
|
||||
if (!this._commentThread.comments || !this._commentThread.comments.length) {
|
||||
this.deleteCommentThread();
|
||||
}
|
||||
} else {
|
||||
this._commentThread.collapsibleState = modes.CommentThreadCollapsibleState.Expanded;
|
||||
this.show({ lineNumber: lineNumber, column: 1 }, 2);
|
||||
}
|
||||
}
|
||||
@@ -379,6 +385,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
||||
} else {
|
||||
this._commentThreadContextValue.reset();
|
||||
}
|
||||
|
||||
this.setFocusedComment(this._focusedComment);
|
||||
}
|
||||
|
||||
protected _onWidth(widthInPixel: number): void {
|
||||
@@ -401,6 +409,21 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
||||
|
||||
this._commentsElement = dom.append(this._bodyElement, dom.$('div.comments-container'));
|
||||
this._commentsElement.setAttribute('role', 'presentation');
|
||||
this._commentsElement.tabIndex = 0;
|
||||
|
||||
this._disposables.add(dom.addDisposableListener(this._commentsElement, dom.EventType.KEY_DOWN, (e) => {
|
||||
let event = new StandardKeyboardEvent(e as KeyboardEvent);
|
||||
if (event.equals(KeyCode.UpArrow) || event.equals(KeyCode.DownArrow)) {
|
||||
const moveFocusWithinBounds = (change: number): number => {
|
||||
if (this._focusedComment === undefined && change >= 0) { return 0; }
|
||||
if (this._focusedComment === undefined && change < 0) { return this._commentElements.length - 1; }
|
||||
let newIndex = this._focusedComment! + change;
|
||||
return Math.min(Math.max(0, newIndex), this._commentElements.length - 1);
|
||||
};
|
||||
|
||||
this.setFocusedComment(event.equals(KeyCode.UpArrow) ? moveFocusWithinBounds(-1) : moveFocusWithinBounds(1));
|
||||
}
|
||||
}));
|
||||
|
||||
this._commentElements = [];
|
||||
if (this._commentThread.comments) {
|
||||
@@ -565,6 +588,19 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
||||
}));
|
||||
}
|
||||
|
||||
private setFocusedComment(value: number | undefined) {
|
||||
if (this._focusedComment !== undefined) {
|
||||
this._commentElements[this._focusedComment]?.setFocus(false);
|
||||
}
|
||||
|
||||
if (this._commentElements.length === 0 || value === undefined) {
|
||||
this._focusedComment = undefined;
|
||||
} else {
|
||||
this._focusedComment = Math.min(value, this._commentElements.length - 1);
|
||||
this._commentElements[this._focusedComment].setFocus(true);
|
||||
}
|
||||
}
|
||||
|
||||
private getActiveComment(): CommentNode | ReviewZoneWidget {
|
||||
return this._commentElements.filter(node => node.isEditing)[0] || this;
|
||||
}
|
||||
@@ -613,25 +649,9 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
||||
this._markdownRenderer);
|
||||
|
||||
this._disposables.add(newCommentNode);
|
||||
this._disposables.add(newCommentNode.onDidDelete(deletedNode => {
|
||||
const deletedNodeId = deletedNode.comment.uniqueIdInThread;
|
||||
const deletedElementIndex = arrays.firstIndex(this._commentElements, commentNode => commentNode.comment.uniqueIdInThread === deletedNodeId);
|
||||
if (deletedElementIndex > -1) {
|
||||
this._commentElements.splice(deletedElementIndex, 1);
|
||||
}
|
||||
|
||||
const deletedCommentIndex = arrays.firstIndex(this._commentThread.comments!, comment => comment.uniqueIdInThread === deletedNodeId);
|
||||
if (deletedCommentIndex > -1) {
|
||||
this._commentThread.comments!.splice(deletedCommentIndex, 1);
|
||||
}
|
||||
|
||||
this._commentsElement.removeChild(deletedNode.domNode);
|
||||
deletedNode.dispose();
|
||||
|
||||
if (this._commentThread.comments!.length === 0) {
|
||||
this.dispose();
|
||||
}
|
||||
}));
|
||||
this._disposables.add(newCommentNode.onDidClick(clickedNode =>
|
||||
this.setFocusedComment(arrays.firstIndex(this._commentElements, commentNode => commentNode.comment.uniqueIdInThread === clickedNode.comment.uniqueIdInThread))
|
||||
));
|
||||
|
||||
return newCommentNode;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import { IEditorContribution, IModelChangedEvent } from 'vs/editor/common/editor
|
||||
import { IModelDecorationOptions } from 'vs/editor/common/model';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { peekViewResultsBackground, peekViewResultsSelectionBackground, peekViewTitleBackground } from 'vs/editor/contrib/referenceSearch/referencesWidget';
|
||||
import { peekViewResultsBackground, peekViewResultsSelectionBackground, peekViewTitleBackground } from 'vs/editor/contrib/peekView/peekView';
|
||||
import * as nls from 'vs/nls';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
|
||||
@@ -8,7 +8,6 @@ import * as nls from 'vs/nls';
|
||||
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels';
|
||||
import { CommentNode, CommentsModel, ResourceWithCommentThreads } from 'vs/workbench/contrib/comments/common/commentModel';
|
||||
@@ -21,6 +20,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { WorkbenchAsyncDataTree, IListService } from 'vs/platform/list/browser/listService';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { PANEL_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
|
||||
export const COMMENTS_PANEL_ID = 'workbench.panel.comments';
|
||||
export const COMMENTS_PANEL_TITLE = 'Comments';
|
||||
@@ -127,12 +127,7 @@ export class CommentNodeRenderer implements IListRenderer<ITreeNode<CommentNode>
|
||||
inline: true,
|
||||
actionHandler: {
|
||||
callback: (content) => {
|
||||
try {
|
||||
const uri = URI.parse(content);
|
||||
this.openerService.open(uri).catch(onUnexpectedError);
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
this.openerService.open(content).catch(onUnexpectedError);
|
||||
},
|
||||
disposeables: disposables
|
||||
}
|
||||
@@ -206,6 +201,9 @@ export class CommentsList extends WorkbenchAsyncDataTree<any, any> {
|
||||
},
|
||||
collapseByDefault: () => {
|
||||
return false;
|
||||
},
|
||||
overrideStyles: {
|
||||
listBackground: PANEL_BACKGROUND
|
||||
}
|
||||
},
|
||||
contextKeyService,
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
.monaco-editor .review-widget .body .review-comment .review-comment-contents {
|
||||
padding-left: 20px;
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -134,6 +135,7 @@
|
||||
width: 16px;
|
||||
height: 12px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
display: inline-block;
|
||||
margin-top: 3px;
|
||||
margin-right: 4px;
|
||||
@@ -274,10 +276,6 @@
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
-o-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
padding: 0.4em;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
@@ -362,10 +360,6 @@
|
||||
}
|
||||
|
||||
.monaco-editor .review-widget .head {
|
||||
-webkit-box-sizing: border-box;
|
||||
-o-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { EditorAction, EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions';
|
||||
import { EditorAction, EditorExtensionsRegistry, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
@@ -46,8 +46,9 @@ export class SimpleCommentEditor extends CodeEditorWidget {
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@IAccessibilityService accessibilityService: IAccessibilityService
|
||||
) {
|
||||
const codeEditorWidgetOptions = {
|
||||
contributions: [
|
||||
const codeEditorWidgetOptions: ICodeEditorWidgetOptions = {
|
||||
isSimpleWidget: true,
|
||||
contributions: <IEditorContributionDescription[]>[
|
||||
{ id: MenuPreventer.ID, ctor: MenuPreventer },
|
||||
{ id: ContextMenuController.ID, ctor: ContextMenuController },
|
||||
{ id: SuggestController.ID, ctor: SuggestController },
|
||||
|
||||
@@ -4,15 +4,19 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { firstOrDefault } from 'vs/base/common/arrays';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Command } from 'vs/editor/browser/editorExtensions';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import * as nls from 'vs/nls';
|
||||
import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IListService } from 'vs/platform/list/browser/listService';
|
||||
import { IEditorCommandsContext } from 'vs/workbench/common/editor';
|
||||
import { ICustomEditorService, CONTEXT_HAS_CUSTOM_EDITORS } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE, CONTEXT_HAS_CUSTOM_EDITORS, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { getMultiSelectedResources } from 'vs/workbench/contrib/files/browser/files';
|
||||
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
@@ -98,3 +102,72 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
});
|
||||
|
||||
// #endregion
|
||||
|
||||
|
||||
(new class UndoCustomEditorCommand extends Command {
|
||||
public static readonly ID = 'editor.action.customEditor.undo';
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: UndoCustomEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(
|
||||
CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE,
|
||||
ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z,
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public runCommand(accessor: ServicesAccessor): void {
|
||||
const customEditorService = accessor.get<ICustomEditorService>(ICustomEditorService);
|
||||
|
||||
const activeCustomEditor = customEditorService.activeCustomEditor;
|
||||
if (!activeCustomEditor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const model = customEditorService.models.get(activeCustomEditor.resource, activeCustomEditor.viewType);
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
model.undo();
|
||||
}
|
||||
}).register();
|
||||
|
||||
(new class RedoWebviewEditorCommand extends Command {
|
||||
public static readonly ID = 'editor.action.customEditor.redo';
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: RedoWebviewEditorCommand.ID,
|
||||
precondition: ContextKeyExpr.and(
|
||||
CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE,
|
||||
ContextKeyExpr.not(InputFocusedContextKey)),
|
||||
kbOpts: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
|
||||
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z },
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public runCommand(accessor: ServicesAccessor): void {
|
||||
const customEditorService = accessor.get<ICustomEditorService>(ICustomEditorService);
|
||||
|
||||
const activeCustomEditor = customEditorService.activeCustomEditor;
|
||||
if (!activeCustomEditor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const model = customEditorService.models.get(activeCustomEditor.resource, activeCustomEditor.viewType);
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
model.redo();
|
||||
}
|
||||
}).register();
|
||||
|
||||
@@ -4,38 +4,44 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
import { UnownedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
import { DataUri, isEqual } from 'vs/base/common/resources';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { WebviewContentState } from 'vs/editor/common/modes';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IEditorModel, ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { ConfirmResult, IEditorInput, Verbosity } from 'vs/workbench/common/editor';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { GroupIdentifier, IEditorInput, IRevertOptions, ISaveOptions, Verbosity } from 'vs/workbench/common/editor';
|
||||
import { ICustomEditorModel, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { IWebviewWorkbenchService, LazilyResolvedWebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService';
|
||||
import { promptSave } from 'vs/workbench/services/textfile/browser/textFileService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
export class CustomFileEditorInput extends LazilyResolvedWebviewEditorInput {
|
||||
|
||||
public static typeId = 'workbench.editors.webviewEditor';
|
||||
|
||||
private readonly _editorResource: URI;
|
||||
private _state = WebviewContentState.Readonly;
|
||||
private _model?: ICustomEditorModel;
|
||||
|
||||
constructor(
|
||||
resource: URI,
|
||||
viewType: string,
|
||||
id: string,
|
||||
webview: Lazy<UnownedDisposable<WebviewEditorOverlay>>,
|
||||
webview: Lazy<WebviewEditorOverlay>,
|
||||
@ILifecycleService lifecycleService: ILifecycleService,
|
||||
@IWebviewWorkbenchService webviewWorkbenchService: IWebviewWorkbenchService,
|
||||
@IDialogService private readonly dialogService: IDialogService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@ICustomEditorService private readonly customEditorService: ICustomEditorService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IFileDialogService private readonly fileDialogService: IFileDialogService,
|
||||
) {
|
||||
super(id, viewType, '', webview, webviewWorkbenchService);
|
||||
super(id, viewType, '', webview, webviewWorkbenchService, lifecycleService);
|
||||
this._editorResource = resource;
|
||||
}
|
||||
|
||||
@@ -47,27 +53,17 @@ export class CustomFileEditorInput extends LazilyResolvedWebviewEditorInput {
|
||||
return this._editorResource;
|
||||
}
|
||||
|
||||
public supportsSplitEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@memoize
|
||||
getName(): string {
|
||||
if (this.getResource().scheme === Schemas.data) {
|
||||
const metadata = DataUri.parseMetaData(this.getResource());
|
||||
const label = metadata.get(DataUri.META_DATA_LABEL);
|
||||
if (typeof label === 'string') {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
return basename(this.labelService.getUriLabel(this.getResource()));
|
||||
}
|
||||
|
||||
@memoize
|
||||
getDescription(): string | undefined {
|
||||
if (this.getResource().scheme === Schemas.data) {
|
||||
const metadata = DataUri.parseMetaData(this.getResource());
|
||||
const description = metadata.get(DataUri.META_DATA_DESCRIPTION);
|
||||
if (typeof description === 'string') {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
return super.getDescription();
|
||||
}
|
||||
|
||||
@@ -84,17 +80,11 @@ export class CustomFileEditorInput extends LazilyResolvedWebviewEditorInput {
|
||||
|
||||
@memoize
|
||||
private get mediumTitle(): string {
|
||||
if (this.getResource().scheme === Schemas.data) {
|
||||
return this.getName();
|
||||
}
|
||||
return this.labelService.getUriLabel(this.getResource(), { relative: true });
|
||||
}
|
||||
|
||||
@memoize
|
||||
private get longTitle(): string {
|
||||
if (this.getResource().scheme === Schemas.data) {
|
||||
return this.getName();
|
||||
}
|
||||
return this.labelService.getUriLabel(this.getResource());
|
||||
}
|
||||
|
||||
@@ -110,34 +100,71 @@ export class CustomFileEditorInput extends LazilyResolvedWebviewEditorInput {
|
||||
}
|
||||
}
|
||||
|
||||
public setState(newState: WebviewContentState): void {
|
||||
this._state = newState;
|
||||
public isReadonly(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public isDirty(): boolean {
|
||||
return this._model ? this._model.isDirty() : false;
|
||||
}
|
||||
|
||||
public save(groupId: GroupIdentifier, options?: ISaveOptions): Promise<boolean> {
|
||||
return this._model ? this._model.save(options) : Promise.resolve(false);
|
||||
}
|
||||
|
||||
public async saveAs(groupId: GroupIdentifier, options?: ISaveOptions): Promise<boolean> {
|
||||
if (!this._model) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Preserve view state by opening the editor first. In addition
|
||||
// this allows the user to review the contents of the editor.
|
||||
// let viewState: IEditorViewState | undefined = undefined;
|
||||
// const editor = await this.editorService.openEditor(this, undefined, group);
|
||||
// if (isTextEditor(editor)) {
|
||||
// viewState = editor.getViewState();
|
||||
// }
|
||||
|
||||
let dialogPath = this._editorResource;
|
||||
// if (this._editorResource.scheme === Schemas.untitled) {
|
||||
// dialogPath = this.suggestFileName(resource);
|
||||
// }
|
||||
|
||||
const target = await this.promptForPath(this._editorResource, dialogPath, options?.availableFileSystems);
|
||||
if (!target) {
|
||||
return false; // save cancelled
|
||||
}
|
||||
|
||||
await this._model.saveAs(this._editorResource, target, options);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public revert(options?: IRevertOptions): Promise<boolean> {
|
||||
return this._model ? this._model.revert(options) : Promise.resolve(false);
|
||||
}
|
||||
|
||||
public async resolve(): Promise<IEditorModel> {
|
||||
this._model = await this.customEditorService.models.loadOrCreate(this.getResource(), this.viewType);
|
||||
this._register(this._model.onDidChangeDirty(() => this._onDidChangeDirty.fire()));
|
||||
this._onDidChangeDirty.fire();
|
||||
return await super.resolve();
|
||||
}
|
||||
|
||||
public isDirty() {
|
||||
return this._state === WebviewContentState.Dirty;
|
||||
protected async promptForPath(resource: URI, defaultUri: URI, availableFileSystems?: readonly string[]): Promise<URI | undefined> {
|
||||
|
||||
// Help user to find a name for the file by opening it first
|
||||
await this.editorService.openEditor({ resource, options: { revealIfOpened: true, preserveFocus: true } });
|
||||
|
||||
return this.fileDialogService.pickFileToSave({});//this.getSaveDialogOptions(defaultUri, availableFileSystems));
|
||||
}
|
||||
|
||||
public async confirmSave(): Promise<ConfirmResult> {
|
||||
if (!this.isDirty()) {
|
||||
return ConfirmResult.DONT_SAVE;
|
||||
}
|
||||
return promptSave(this.dialogService, [this.getResource()]);
|
||||
public handleMove(groupId: GroupIdentifier, uri: URI, options?: ITextEditorOptions): IEditorInput | undefined {
|
||||
const webview = assertIsDefined(this.takeOwnershipOfWebview());
|
||||
return this.instantiationService.createInstance(CustomFileEditorInput,
|
||||
uri,
|
||||
this.viewType,
|
||||
generateUuid(),
|
||||
new Lazy(() => webview));
|
||||
}
|
||||
|
||||
public async save(): Promise<boolean> {
|
||||
if (!this.isDirty) {
|
||||
return true;
|
||||
}
|
||||
const waitingOn: Promise<boolean>[] = [];
|
||||
this._onWillSave.fire({
|
||||
waitUntil: (thenable: Promise<boolean>): void => { waitingOn.push(thenable); },
|
||||
});
|
||||
const result = await Promise.all(waitingOn);
|
||||
return result.every(x => x);
|
||||
}
|
||||
|
||||
private readonly _onWillSave = this._register(new Emitter<{ waitUntil: (thenable: Thenable<boolean>) => void }>());
|
||||
public readonly onWillSave = this._onWillSave.event;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { UnownedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -12,7 +11,7 @@ import { WebviewEditorInputFactory } from 'vs/workbench/contrib/webview/browser/
|
||||
import { IWebviewWorkbenchService } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
|
||||
export class CustomEditoInputFactory extends WebviewEditorInputFactory {
|
||||
export class CustomEditorInputFactory extends WebviewEditorInputFactory {
|
||||
|
||||
public static readonly ID = CustomFileEditorInput.typeId;
|
||||
|
||||
@@ -48,7 +47,7 @@ export class CustomEditoInputFactory extends WebviewEditorInputFactory {
|
||||
location: data.extensionLocation,
|
||||
id: data.extensionId
|
||||
} : undefined, data.group);
|
||||
return new UnownedDisposable(webviewInput.webview);
|
||||
return webviewInput.webview;
|
||||
});
|
||||
|
||||
const customInput = this._instantiationService.createInstance(CustomFileEditorInput, URI.from((data as any).editorResource), data.viewType, id, webview);
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { coalesce, distinct, mergeSort, find } from 'vs/base/common/arrays';
|
||||
import { coalesce, distinct, find, mergeSort } from 'vs/base/common/arrays';
|
||||
import * as glob from 'vs/base/common/glob';
|
||||
import { UnownedDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { basename, DataUri, isEqual } from 'vs/base/common/resources';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { basename, isEqual } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
@@ -21,15 +22,14 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { EditorInput, EditorOptions, IEditor, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { webviewEditorsExtensionPoint } from 'vs/workbench/contrib/customEditor/browser/extensionPoint';
|
||||
import { CustomEditorPriority, CustomEditorInfo, CustomEditorSelector, ICustomEditorService, CONTEXT_HAS_CUSTOM_EDITORS } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE, CONTEXT_HAS_CUSTOM_EDITORS, CustomEditorInfo, CustomEditorPriority, CustomEditorSelector, ICustomEditor, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { CustomEditorModelManager } from 'vs/workbench/contrib/customEditor/common/customEditorModelManager';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { IWebviewService, webviewHasOwnEditFunctionsContext } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
|
||||
import { CustomFileEditorInput } from './customEditorInput';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
|
||||
const defaultEditorId = 'default';
|
||||
|
||||
const defaultEditorInfo: CustomEditorInfo = {
|
||||
@@ -41,7 +41,7 @@ const defaultEditorInfo: CustomEditorInfo = {
|
||||
priority: CustomEditorPriority.default,
|
||||
};
|
||||
|
||||
export class CustomEditorStore {
|
||||
export class CustomEditorInfoStore {
|
||||
private readonly contributedEditors = new Map<string, CustomEditorInfo>();
|
||||
|
||||
public clear() {
|
||||
@@ -71,11 +71,17 @@ export class CustomEditorStore {
|
||||
export class CustomEditorService extends Disposable implements ICustomEditorService {
|
||||
_serviceBrand: any;
|
||||
|
||||
private readonly editors = new CustomEditorStore();
|
||||
private readonly _editorInfoStore = new CustomEditorInfoStore();
|
||||
|
||||
private readonly _models: CustomEditorModelManager;
|
||||
|
||||
private readonly _hasCustomEditor: IContextKey<boolean>;
|
||||
private readonly _focusedCustomEditorIsEditable: IContextKey<boolean>;
|
||||
private readonly _webviewHasOwnEditFunctions: IContextKey<boolean>;
|
||||
|
||||
constructor(
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IWorkingCopyService workingCopyService: IWorkingCopyService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@@ -84,12 +90,14 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
) {
|
||||
super();
|
||||
|
||||
this._models = new CustomEditorModelManager(workingCopyService);
|
||||
|
||||
webviewEditorsExtensionPoint.setHandler(extensions => {
|
||||
this.editors.clear();
|
||||
this._editorInfoStore.clear();
|
||||
|
||||
for (const extension of extensions) {
|
||||
for (const webviewEditorContribution of extension.value) {
|
||||
this.editors.add({
|
||||
this._editorInfoStore.add({
|
||||
id: webviewEditorContribution.viewType,
|
||||
displayName: webviewEditorContribution.displayName,
|
||||
selector: webviewEditorContribution.selector || [],
|
||||
@@ -97,24 +105,37 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
});
|
||||
}
|
||||
}
|
||||
this.updateContext();
|
||||
this.updateContexts();
|
||||
});
|
||||
|
||||
this._hasCustomEditor = CONTEXT_HAS_CUSTOM_EDITORS.bindTo(contextKeyService);
|
||||
this._focusedCustomEditorIsEditable = CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE.bindTo(contextKeyService);
|
||||
this._webviewHasOwnEditFunctions = webviewHasOwnEditFunctionsContext.bindTo(contextKeyService);
|
||||
|
||||
this._register(this.editorService.onDidActiveEditorChange(() => this.updateContext()));
|
||||
this.updateContext();
|
||||
this._register(this.editorService.onDidActiveEditorChange(() => this.updateContexts()));
|
||||
this.updateContexts();
|
||||
}
|
||||
|
||||
public get models() { return this._models; }
|
||||
|
||||
public get activeCustomEditor(): ICustomEditor | undefined {
|
||||
const activeInput = this.editorService.activeControl?.input;
|
||||
if (!(activeInput instanceof CustomFileEditorInput)) {
|
||||
return undefined;
|
||||
}
|
||||
const resource = activeInput.getResource();
|
||||
return { resource, viewType: activeInput.viewType };
|
||||
}
|
||||
|
||||
public getContributedCustomEditors(resource: URI): readonly CustomEditorInfo[] {
|
||||
return this.editors.getContributedEditors(resource);
|
||||
return this._editorInfoStore.getContributedEditors(resource);
|
||||
}
|
||||
|
||||
public getUserConfiguredCustomEditors(resource: URI): readonly CustomEditorInfo[] {
|
||||
const rawAssociations = this.configurationService.getValue<CustomEditorsAssociations>(customEditorsAssociationsKey) || [];
|
||||
return coalesce(rawAssociations
|
||||
.filter(association => matches(association, resource))
|
||||
.map(association => this.editors.get(association.viewType)));
|
||||
.map(association => this._editorInfoStore.get(association.viewType)));
|
||||
}
|
||||
|
||||
public async promptOpenWith(
|
||||
@@ -164,7 +185,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
return this.openEditorForResource(resource, fileInput, { ...options, ignoreOverrides: true }, group);
|
||||
}
|
||||
|
||||
if (!this.editors.get(viewType)) {
|
||||
if (!this._editorInfoStore.get(viewType)) {
|
||||
return this.promptOpenWith(resource, options, group);
|
||||
}
|
||||
|
||||
@@ -180,7 +201,7 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
): CustomFileEditorInput {
|
||||
const id = generateUuid();
|
||||
const webview = new Lazy(() => {
|
||||
return new UnownedDisposable(this.webviewService.createWebviewEditorOverlay(id, { customClasses: options ? options.customClasses : undefined }, {}));
|
||||
return this.webviewService.createWebviewEditorOverlay(id, { customClasses: options?.customClasses }, {});
|
||||
});
|
||||
const input = this.instantiationService.createInstance(CustomFileEditorInput, resource, viewType, id, webview);
|
||||
if (group) {
|
||||
@@ -215,22 +236,23 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
|
||||
return this.editorService.openEditor(input, options, group);
|
||||
}
|
||||
|
||||
private updateContext() {
|
||||
private updateContexts() {
|
||||
const activeControl = this.editorService.activeControl;
|
||||
if (!activeControl) {
|
||||
this._hasCustomEditor.reset();
|
||||
return;
|
||||
}
|
||||
const resource = activeControl.input.getResource();
|
||||
const resource = activeControl?.input.getResource();
|
||||
if (!resource) {
|
||||
this._hasCustomEditor.reset();
|
||||
this._focusedCustomEditorIsEditable.reset();
|
||||
this._webviewHasOwnEditFunctions.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
const possibleEditors = [
|
||||
...this.getContributedCustomEditors(resource),
|
||||
...this.getUserConfiguredCustomEditors(resource),
|
||||
];
|
||||
this._hasCustomEditor.set(possibleEditors.length > 0);
|
||||
this._focusedCustomEditorIsEditable.set(activeControl?.input instanceof CustomFileEditorInput);
|
||||
this._webviewHasOwnEditFunctions.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,6 +323,11 @@ export class CustomEditorContribution implements IWorkbenchContribution {
|
||||
};
|
||||
}
|
||||
|
||||
// If we have all optional editors, then open VS Code's standard editor
|
||||
if (contributedEditors.every(editor => editor.priority === CustomEditorPriority.option)) {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
|
||||
// Open VS Code's standard editor but prompt user to see if they wish to use a custom one instead
|
||||
return {
|
||||
override: (async () => {
|
||||
@@ -337,7 +364,7 @@ export class CustomEditorContribution implements IWorkbenchContribution {
|
||||
const editors = mergeSort(
|
||||
distinct([
|
||||
...this.customEditorService.getUserConfiguredCustomEditors(resource),
|
||||
...this.customEditorService.getContributedCustomEditors(resource),
|
||||
...this.customEditorService.getContributedCustomEditors(resource).filter(x => x.priority !== CustomEditorPriority.option),
|
||||
], editor => editor.id),
|
||||
(a, b) => {
|
||||
return priorityToRank(a.priority) - priorityToRank(b.priority);
|
||||
@@ -379,18 +406,6 @@ function priorityToRank(priority: CustomEditorPriority): number {
|
||||
}
|
||||
|
||||
function matches(selector: CustomEditorSelector, resource: URI): boolean {
|
||||
if (resource.scheme === Schemas.data) {
|
||||
if (!selector.mime) {
|
||||
return false;
|
||||
}
|
||||
const metadata = DataUri.parseMetaData(resource);
|
||||
const mime = metadata.get(DataUri.META_DATA_MIME);
|
||||
if (!mime) {
|
||||
return false;
|
||||
}
|
||||
return glob.match(selector.mime, mime.toLowerCase());
|
||||
}
|
||||
|
||||
if (selector.filenamePattern) {
|
||||
if (glob.match(selector.filenamePattern.toLowerCase(), basename(resource).toLowerCase())) {
|
||||
return true;
|
||||
|
||||
@@ -53,10 +53,6 @@ const webviewEditorsContribution: IJSONSchema = {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.selector.filenamePattern', 'Glob that the custom editor is enabled for.'),
|
||||
},
|
||||
mime: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.selector.mime', 'Glob that matches the mime type of a data uri resource.'),
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -10,9 +10,10 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { EditorDescriptor, Extensions as EditorExtensions, IEditorRegistry } from 'vs/workbench/browser/editor';
|
||||
import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration';
|
||||
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
|
||||
import { CustomEditoInputFactory } from 'vs/workbench/contrib/customEditor/browser/customEditorInputFactory';
|
||||
import { CustomEditorInputFactory } from 'vs/workbench/contrib/customEditor/browser/customEditorInputFactory';
|
||||
import { ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor';
|
||||
import './commands';
|
||||
@@ -25,7 +26,7 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
|
||||
.registerWorkbenchContribution(CustomEditorContribution, LifecyclePhase.Starting);
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
new EditorDescriptor(
|
||||
EditorDescriptor.create(
|
||||
WebviewEditor,
|
||||
WebviewEditor.ID,
|
||||
'Webview Editor',
|
||||
@@ -34,15 +35,12 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
]);
|
||||
|
||||
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(
|
||||
CustomEditoInputFactory.ID,
|
||||
CustomEditoInputFactory);
|
||||
CustomEditorInputFactory.ID,
|
||||
CustomEditorInputFactory);
|
||||
|
||||
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
|
||||
.registerConfiguration({
|
||||
'id': 'workbench',
|
||||
'order': 7,
|
||||
'title': nls.localize('workbenchConfigurationTitle', "Workbench"),
|
||||
'type': 'object',
|
||||
...workbenchConfigurationNodeBase,
|
||||
'properties': {
|
||||
[customEditorsAssociationsKey]: {
|
||||
type: 'array',
|
||||
@@ -60,7 +58,7 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
|
||||
},
|
||||
'filenamePattern': {
|
||||
type: 'string',
|
||||
description: nls.localize('editor.editorAssociations.filenamePattern', "Glob pattern the the editor should be used for."),
|
||||
description: nls.localize('editor.editorAssociations.filenamePattern', "Glob pattern the editor should be used for."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,20 +3,32 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { EditorInput, IEditor } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, IEditor, ISaveOptions, IRevertOptions } from 'vs/workbench/common/editor';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService';
|
||||
|
||||
export const ICustomEditorService = createDecorator<ICustomEditorService>('customEditorService');
|
||||
|
||||
export const CONTEXT_HAS_CUSTOM_EDITORS = new RawContextKey<boolean>('hasCustomEditors', false);
|
||||
export const CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE = new RawContextKey<boolean>('focusedCustomEditorIsEditable', false);
|
||||
|
||||
export interface ICustomEditor {
|
||||
readonly resource: URI;
|
||||
readonly viewType: string;
|
||||
}
|
||||
|
||||
export interface ICustomEditorService {
|
||||
_serviceBrand: any;
|
||||
|
||||
readonly models: ICustomEditorModelManager;
|
||||
|
||||
readonly activeCustomEditor: ICustomEditor | undefined;
|
||||
|
||||
getContributedCustomEditors(resource: URI): readonly CustomEditorInfo[];
|
||||
getUserConfiguredCustomEditors(resource: URI): readonly CustomEditorInfo[];
|
||||
|
||||
@@ -26,6 +38,45 @@ export interface ICustomEditorService {
|
||||
promptOpenWith(resource: URI, options?: ITextEditorOptions, group?: IEditorGroup): Promise<IEditor | undefined>;
|
||||
}
|
||||
|
||||
export type CustomEditorEdit = { source?: any, data: any };
|
||||
|
||||
export interface ICustomEditorModelManager {
|
||||
get(resource: URI, viewType: string): ICustomEditorModel | undefined;
|
||||
|
||||
loadOrCreate(resource: URI, viewType: string): Promise<ICustomEditorModel>;
|
||||
|
||||
disposeModel(model: ICustomEditorModel): void;
|
||||
}
|
||||
|
||||
export interface CustomEditorSaveEvent {
|
||||
readonly resource: URI;
|
||||
readonly waitUntil: (until: Promise<any>) => void;
|
||||
}
|
||||
|
||||
export interface CustomEditorSaveAsEvent {
|
||||
readonly resource: URI;
|
||||
readonly targetResource: URI;
|
||||
readonly waitUntil: (until: Promise<any>) => void;
|
||||
}
|
||||
|
||||
export interface ICustomEditorModel extends IWorkingCopy {
|
||||
readonly onUndo: Event<readonly CustomEditorEdit[]>;
|
||||
readonly onApplyEdit: Event<readonly CustomEditorEdit[]>;
|
||||
readonly onWillSave: Event<CustomEditorSaveEvent>;
|
||||
readonly onWillSaveAs: Event<CustomEditorSaveAsEvent>;
|
||||
|
||||
readonly currentEdits: readonly CustomEditorEdit[];
|
||||
|
||||
undo(): void;
|
||||
redo(): void;
|
||||
revert(options?: IRevertOptions): Promise<boolean>;
|
||||
|
||||
save(options?: ISaveOptions): Promise<boolean>;
|
||||
saveAs(resource: URI, targetResource: URI, currentOptions?: ISaveOptions): Promise<boolean>;
|
||||
|
||||
makeEdit(edit: CustomEditorEdit): void;
|
||||
}
|
||||
|
||||
export const enum CustomEditorPriority {
|
||||
default = 'default',
|
||||
builtin = 'builtin',
|
||||
@@ -34,7 +85,6 @@ export const enum CustomEditorPriority {
|
||||
|
||||
export interface CustomEditorSelector {
|
||||
readonly filenamePattern?: string;
|
||||
readonly mime?: string;
|
||||
}
|
||||
|
||||
export interface CustomEditorInfo {
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ICustomEditorModel, CustomEditorEdit, CustomEditorSaveAsEvent, CustomEditorSaveEvent } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService';
|
||||
import { ISaveOptions, IRevertOptions } from 'vs/workbench/common/editor';
|
||||
|
||||
export class CustomEditorModel extends Disposable implements ICustomEditorModel {
|
||||
|
||||
private _currentEditIndex: number = -1;
|
||||
private _savePoint: number = -1;
|
||||
private _edits: Array<any> = [];
|
||||
|
||||
constructor(
|
||||
private readonly _resource: URI,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
//#region IWorkingCopy
|
||||
|
||||
public get resource() {
|
||||
return this._resource;
|
||||
}
|
||||
|
||||
public get capabilities(): WorkingCopyCapabilities {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public isDirty(): boolean {
|
||||
return this._edits.length > 0 && this._savePoint !== this._currentEditIndex;
|
||||
}
|
||||
|
||||
protected readonly _onDidChangeDirty: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChangeDirty: Event<void> = this._onDidChangeDirty.event;
|
||||
|
||||
//#endregion
|
||||
|
||||
protected readonly _onUndo = this._register(new Emitter<readonly CustomEditorEdit[]>());
|
||||
readonly onUndo = this._onUndo.event;
|
||||
|
||||
protected readonly _onApplyEdit = this._register(new Emitter<readonly CustomEditorEdit[]>());
|
||||
readonly onApplyEdit = this._onApplyEdit.event;
|
||||
|
||||
protected readonly _onWillSave = this._register(new Emitter<CustomEditorSaveEvent>());
|
||||
readonly onWillSave = this._onWillSave.event;
|
||||
|
||||
protected readonly _onWillSaveAs = this._register(new Emitter<CustomEditorSaveAsEvent>());
|
||||
readonly onWillSaveAs = this._onWillSaveAs.event;
|
||||
|
||||
get currentEdits(): readonly CustomEditorEdit[] {
|
||||
return this._edits.slice(0, Math.max(0, this._currentEditIndex + 1));
|
||||
}
|
||||
|
||||
public makeEdit(edit: CustomEditorEdit): void {
|
||||
this._edits.splice(this._currentEditIndex + 1, this._edits.length - this._currentEditIndex, edit.data);
|
||||
this._currentEditIndex = this._edits.length - 1;
|
||||
this.updateDirty();
|
||||
this._onApplyEdit.fire([edit]);
|
||||
}
|
||||
|
||||
private updateDirty() {
|
||||
this._onDidChangeDirty.fire();
|
||||
}
|
||||
|
||||
public async save(_options?: ISaveOptions): Promise<boolean> {
|
||||
const untils: Promise<any>[] = [];
|
||||
const handler: CustomEditorSaveEvent = {
|
||||
resource: this._resource,
|
||||
waitUntil: (until: Promise<any>) => untils.push(until)
|
||||
};
|
||||
|
||||
try {
|
||||
this._onWillSave.fire(handler);
|
||||
await Promise.all(untils);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._savePoint = this._currentEditIndex;
|
||||
this.updateDirty();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async saveAs(resource: URI, targetResource: URI, _options?: ISaveOptions): Promise<boolean> {
|
||||
const untils: Promise<any>[] = [];
|
||||
const handler: CustomEditorSaveAsEvent = {
|
||||
resource,
|
||||
targetResource,
|
||||
waitUntil: (until: Promise<any>) => untils.push(until)
|
||||
};
|
||||
|
||||
try {
|
||||
this._onWillSaveAs.fire(handler);
|
||||
await Promise.all(untils);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._savePoint = this._currentEditIndex;
|
||||
this.updateDirty();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async revert(_options?: IRevertOptions) {
|
||||
if (this._currentEditIndex === this._savePoint) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this._currentEditIndex >= this._savePoint) {
|
||||
const editsToUndo = this._edits.slice(this._savePoint, this._currentEditIndex);
|
||||
this._onUndo.fire(editsToUndo.reverse());
|
||||
} else if (this._currentEditIndex < this._savePoint) {
|
||||
const editsToRedo = this._edits.slice(this._currentEditIndex, this._savePoint);
|
||||
this._onApplyEdit.fire(editsToRedo);
|
||||
}
|
||||
|
||||
this._currentEditIndex = this._savePoint;
|
||||
this._edits.splice(this._currentEditIndex + 1, this._edits.length - this._currentEditIndex);
|
||||
this.updateDirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
public undo() {
|
||||
if (this._currentEditIndex < 0) {
|
||||
// nothing to undo
|
||||
return;
|
||||
}
|
||||
|
||||
const undoneEdit = this._edits[this._currentEditIndex];
|
||||
--this._currentEditIndex;
|
||||
this._onUndo.fire([{ data: undoneEdit }]);
|
||||
|
||||
this.updateDirty();
|
||||
}
|
||||
|
||||
public redo() {
|
||||
if (this._currentEditIndex >= this._edits.length - 1) {
|
||||
// nothing to redo
|
||||
return;
|
||||
}
|
||||
|
||||
++this._currentEditIndex;
|
||||
const redoneEdit = this._edits[this._currentEditIndex];
|
||||
|
||||
this._onApplyEdit.fire([{ data: redoneEdit }]);
|
||||
|
||||
this.updateDirty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ICustomEditorModel, ICustomEditorModelManager } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { CustomEditorModel } from 'vs/workbench/contrib/customEditor/common/customEditorModel';
|
||||
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
|
||||
|
||||
export class CustomEditorModelManager implements ICustomEditorModelManager {
|
||||
private readonly _models = new Map<string, { readonly model: CustomEditorModel, readonly disposables: DisposableStore }>();
|
||||
|
||||
constructor(
|
||||
@IWorkingCopyService private readonly _workingCopyService: IWorkingCopyService,
|
||||
) { }
|
||||
|
||||
|
||||
public get(resource: URI, viewType: string): ICustomEditorModel | undefined {
|
||||
return this._models.get(this.key(resource, viewType))?.model;
|
||||
}
|
||||
|
||||
public async loadOrCreate(resource: URI, viewType: string): Promise<ICustomEditorModel> {
|
||||
const existing = this.get(resource, viewType);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
const model = new CustomEditorModel(resource);
|
||||
const disposables = new DisposableStore();
|
||||
this._workingCopyService.registerWorkingCopy(model);
|
||||
this._models.set(this.key(resource, viewType), { model, disposables });
|
||||
return model;
|
||||
}
|
||||
|
||||
public disposeModel(model: ICustomEditorModel): void {
|
||||
let foundKey: string | undefined;
|
||||
this._models.forEach((value, key) => {
|
||||
if (model === value.model) {
|
||||
value.disposables.dispose();
|
||||
foundKey = key;
|
||||
}
|
||||
});
|
||||
if (typeof foundKey === 'string') {
|
||||
this._models.delete(foundKey);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private key(resource: URI, viewType: string): string {
|
||||
return `${resource.toString()}@@@${viewType}`;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { HighlightedLabel, IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
|
||||
import { ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
|
||||
export const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024;
|
||||
export const twistiePixels = 20;
|
||||
@@ -58,7 +59,7 @@ export function renderExpressionValue(expressionOrValue: IExpressionContainer |
|
||||
// remove stale classes
|
||||
container.className = 'value';
|
||||
// when resolving expressions we represent errors from the server as a variable with name === null.
|
||||
if (value === null || ((expressionOrValue instanceof Expression || expressionOrValue instanceof Variable) && !expressionOrValue.available)) {
|
||||
if (value === null || ((expressionOrValue instanceof Expression || expressionOrValue instanceof Variable || expressionOrValue instanceof ReplEvaluationResult) && !expressionOrValue.available)) {
|
||||
dom.addClass(container, 'unavailable');
|
||||
if (value !== Expression.DEFAULT_VALUE) {
|
||||
dom.addClass(container, 'error');
|
||||
|
||||
@@ -32,6 +32,8 @@ import { distinct } from 'vs/base/common/arrays';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { BrowserFeatures } from 'vs/base/browser/canIUse';
|
||||
import { isSafari } from 'vs/base/browser/browser';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -43,7 +45,7 @@ interface IBreakpointDecoration {
|
||||
}
|
||||
|
||||
const breakpointHelperDecoration: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-breakpoint-hint',
|
||||
glyphMarginClassName: 'codicon-debug-hint',
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
|
||||
};
|
||||
|
||||
@@ -91,7 +93,7 @@ function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoi
|
||||
}
|
||||
|
||||
return {
|
||||
glyphMarginClassName: className,
|
||||
glyphMarginClassName: `${className}`,
|
||||
glyphMarginHoverMessage,
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
beforeContentClassName: breakpoint.column ? `debug-breakpoint-placeholder` : undefined,
|
||||
@@ -105,25 +107,29 @@ async function createCandidateDecorations(model: ITextModel, breakpointDecoratio
|
||||
const session = debugService.getViewModel().focusedSession;
|
||||
if (session && session.capabilities.supportsBreakpointLocationsRequest) {
|
||||
await Promise.all(lineNumbers.map(async lineNumber => {
|
||||
const positions = await session.breakpointsLocations(model.uri, lineNumber);
|
||||
if (positions.length > 1) {
|
||||
// Do not render candidates if there is only one, since it is already covered by the line breakpoint
|
||||
positions.forEach(p => {
|
||||
const range = new Range(p.lineNumber, p.column, p.lineNumber, p.column + 1);
|
||||
const breakpointAtPosition = breakpointDecorations.filter(bpd => bpd.range.equalsRange(range)).pop();
|
||||
if (breakpointAtPosition && breakpointAtPosition.inlineWidget) {
|
||||
// Space already occupied, do not render candidate.
|
||||
return;
|
||||
}
|
||||
result.push({
|
||||
range,
|
||||
options: {
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
beforeContentClassName: `debug-breakpoint-placeholder`
|
||||
},
|
||||
breakpoint: breakpointAtPosition ? breakpointAtPosition.breakpoint : undefined
|
||||
try {
|
||||
const positions = await session.breakpointsLocations(model.uri, lineNumber);
|
||||
if (positions.length > 1) {
|
||||
// Do not render candidates if there is only one, since it is already covered by the line breakpoint
|
||||
positions.forEach(p => {
|
||||
const range = new Range(p.lineNumber, p.column, p.lineNumber, p.column + 1);
|
||||
const breakpointAtPosition = breakpointDecorations.filter(bpd => bpd.range.equalsRange(range)).pop();
|
||||
if (breakpointAtPosition && breakpointAtPosition.inlineWidget) {
|
||||
// Space already occupied, do not render candidate.
|
||||
return;
|
||||
}
|
||||
result.push({
|
||||
range,
|
||||
options: {
|
||||
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
beforeContentClassName: `debug-breakpoint-placeholder`
|
||||
},
|
||||
breakpoint: breakpointAtPosition ? breakpointAtPosition.breakpoint : undefined
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// If there is an error when fetching breakpoint locations just do not render them
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -131,7 +137,6 @@ async function createCandidateDecorations(model: ITextModel, breakpointDecoratio
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
class BreakpointEditorContribution implements IBreakpointEditorContribution {
|
||||
|
||||
private breakpointHintDecoration: string[] = [];
|
||||
@@ -227,34 +232,48 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution {
|
||||
}
|
||||
}));
|
||||
|
||||
this.toDispose.push(this.editor.onMouseMove((e: IEditorMouseEvent) => {
|
||||
let showBreakpointHintAtLineNumber = -1;
|
||||
const model = this.editor.getModel();
|
||||
if (model && e.target.position && (e.target.type === MouseTargetType.GUTTER_GLYPH_MARGIN || e.target.type === MouseTargetType.GUTTER_LINE_NUMBERS) && this.debugService.getConfigurationManager().canSetBreakpointsIn(model) &&
|
||||
this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
|
||||
const data = e.target.detail as IMarginData;
|
||||
if (!data.isAfterLines) {
|
||||
showBreakpointHintAtLineNumber = e.target.position.lineNumber;
|
||||
if (!(BrowserFeatures.pointerEvents && isSafari)) {
|
||||
/**
|
||||
* We disable the hover feature for Safari on iOS as
|
||||
* 1. Browser hover events are handled specially by the system (it treats first click as hover if there is `:hover` css registered). Below hover behavior will confuse users with inconsistent expeirence.
|
||||
* 2. When users click on line numbers, the breakpoint hint displays immediately, however it doesn't create the breakpoint unless users click on the left gutter. On a touch screen, it's hard to click on that small area.
|
||||
*/
|
||||
this.toDispose.push(this.editor.onMouseMove((e: IEditorMouseEvent) => {
|
||||
let showBreakpointHintAtLineNumber = -1;
|
||||
const model = this.editor.getModel();
|
||||
if (model && e.target.position && (e.target.type === MouseTargetType.GUTTER_GLYPH_MARGIN || e.target.type === MouseTargetType.GUTTER_LINE_NUMBERS) && this.debugService.getConfigurationManager().canSetBreakpointsIn(model) &&
|
||||
this.marginFreeFromNonDebugDecorations(e.target.position.lineNumber)) {
|
||||
const data = e.target.detail as IMarginData;
|
||||
if (!data.isAfterLines) {
|
||||
showBreakpointHintAtLineNumber = e.target.position.lineNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber);
|
||||
}));
|
||||
this.toDispose.push(this.editor.onMouseLeave((e: IEditorMouseEvent) => {
|
||||
this.ensureBreakpointHintDecoration(-1);
|
||||
}));
|
||||
this.ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber);
|
||||
}));
|
||||
this.toDispose.push(this.editor.onMouseLeave(() => {
|
||||
this.ensureBreakpointHintDecoration(-1);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
this.toDispose.push(this.editor.onDidChangeModel(async () => {
|
||||
this.closeBreakpointWidget();
|
||||
await this.setDecorations();
|
||||
}));
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(async () => {
|
||||
this.toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(() => {
|
||||
if (!this.ignoreBreakpointsChangeEvent && !this.setDecorationsScheduler.isScheduled()) {
|
||||
this.setDecorationsScheduler.schedule();
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(this.debugService.onDidChangeState(() => {
|
||||
// We need to update breakpoint decorations when state changes since the top stack frame and breakpoint decoration might change
|
||||
if (!this.setDecorationsScheduler.isScheduled()) {
|
||||
this.setDecorationsScheduler.schedule();
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(this.editor.onDidChangeModelDecorations(() => this.onModelDecorationsChanged()));
|
||||
this.toDispose.push(this.configurationService.onDidChangeConfiguration(async (e) => {
|
||||
if (e.affectsConfiguration('debug.showBreakpointsInOverviewRuler')) {
|
||||
if (e.affectsConfiguration('debug.showBreakpointsInOverviewRuler') || e.affectsConfiguration('debug.showInlineBreakpointCandidates')) {
|
||||
await this.setDecorations();
|
||||
}
|
||||
}));
|
||||
@@ -338,7 +357,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution {
|
||||
const decorations = this.editor.getLineDecorations(line);
|
||||
if (decorations) {
|
||||
for (const { options } of decorations) {
|
||||
if (options.glyphMarginClassName && options.glyphMarginClassName.indexOf('debug') === -1) {
|
||||
if (options.glyphMarginClassName && options.glyphMarginClassName.indexOf('codicon-') === -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -406,7 +425,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution {
|
||||
}
|
||||
|
||||
// Set breakpoint candidate decorations
|
||||
const desiredCandidateDecorations = await createCandidateDecorations(this.editor.getModel(), this.breakpointDecorations, this.debugService);
|
||||
const desiredCandidateDecorations = debugSettings.showInlineBreakpointCandidates ? await createCandidateDecorations(this.editor.getModel(), this.breakpointDecorations, this.debugService) : [];
|
||||
const candidateDecorationIds = this.editor.deltaDecorations(this.candidateDecorations.map(c => c.decorationId), desiredCandidateDecorations);
|
||||
this.candidateDecorations.forEach(candidate => {
|
||||
candidate.inlineWidget.dispose();
|
||||
@@ -416,7 +435,7 @@ class BreakpointEditorContribution implements IBreakpointEditorContribution {
|
||||
// Candidate decoration has a breakpoint attached when a breakpoint is already at that location and we did not yet set a decoration there
|
||||
// In practice this happens for the first breakpoint that was set on a line
|
||||
// We could have also rendered this first decoration as part of desiredBreakpointDecorations however at that moment we have no location information
|
||||
const cssClass = candidate.breakpoint ? getBreakpointMessageAndClassName(this.debugService, candidate.breakpoint).className : 'debug-breakpoint-disabled';
|
||||
const cssClass = candidate.breakpoint ? getBreakpointMessageAndClassName(this.debugService, candidate.breakpoint).className : 'codicon-debug-breakpoint-disabled';
|
||||
const contextMenuActions = () => this.getContextMenuActions(candidate.breakpoint ? [candidate.breakpoint] : [], activeCodeEditor.getModel().uri, candidate.range.startLineNumber, candidate.range.startColumn);
|
||||
const inlineWidget = new InlineBreakpointWidget(activeCodeEditor, decorationId, cssClass, candidate.breakpoint, this.debugService, this.contextMenuService, contextMenuActions);
|
||||
|
||||
@@ -537,6 +556,7 @@ class InlineBreakpointWidget implements IContentWidget, IDisposable {
|
||||
|
||||
private create(cssClass: string | null | undefined): void {
|
||||
this.domNode = $('.inline-breakpoint-widget');
|
||||
this.domNode.classList.add('codicon');
|
||||
if (cssClass) {
|
||||
this.domNode.classList.add(cssClass);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
|
||||
import { getSimpleEditorOptions, getSimpleCodeEditorWidgetOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
const $ = dom.$;
|
||||
const IPrivateBreakpointWidgetService = createDecorator<IPrivateBreakpointWidgetService>('privateBreakpointWidgetService');
|
||||
@@ -48,6 +50,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private selectContainer!: HTMLElement;
|
||||
private inputContainer!: HTMLElement;
|
||||
private input!: IActiveCodeEditor;
|
||||
private toDispose: lifecycle.IDisposable[];
|
||||
private conditionInput = '';
|
||||
@@ -55,6 +58,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
|
||||
private logMessageInput = '';
|
||||
private breakpoint: IBreakpoint | undefined;
|
||||
private context: Context;
|
||||
private heightInPx: number | undefined;
|
||||
|
||||
constructor(editor: ICodeEditor, private lineNumber: number, private column: number | undefined, context: Context | undefined,
|
||||
@IContextViewService private readonly contextViewService: IContextViewService,
|
||||
@@ -64,6 +68,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IModelService private readonly modelService: IModelService,
|
||||
@ICodeEditorService private readonly codeEditorService: ICodeEditorService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService
|
||||
) {
|
||||
super(editor, { showFrame: true, showArrow: false, frameWidth: 1 });
|
||||
|
||||
@@ -158,7 +163,8 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
|
||||
this.input.focus();
|
||||
});
|
||||
|
||||
this.createBreakpointInput(dom.append(container, $('.inputContainer')));
|
||||
this.inputContainer = $('.inputContainer');
|
||||
this.createBreakpointInput(dom.append(container, this.inputContainer));
|
||||
|
||||
this.input.getModel().setValue(this.getInputValue(this.breakpoint));
|
||||
this.toDispose.push(this.input.getModel().onDidChangeContent(() => {
|
||||
@@ -170,7 +176,9 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
|
||||
}
|
||||
|
||||
protected _doLayout(heightInPixel: number, widthInPixel: number): void {
|
||||
this.heightInPx = heightInPixel;
|
||||
this.input.layout({ height: heightInPixel, width: widthInPixel - 113 });
|
||||
this.centerInputVertically();
|
||||
}
|
||||
|
||||
private createBreakpointInput(container: HTMLElement): void {
|
||||
@@ -180,7 +188,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
|
||||
const scopedInstatiationService = this.instantiationService.createChild(new ServiceCollection(
|
||||
[IContextKeyService, scopedContextKeyService], [IPrivateBreakpointWidgetService, this]));
|
||||
|
||||
const options = getSimpleEditorOptions();
|
||||
const options = this.createEditorOptions();
|
||||
const codeEditorWidgetOptions = getSimpleCodeEditorWidgetOptions();
|
||||
this.input = <IActiveCodeEditor>scopedInstatiationService.createInstance(CodeEditorWidget, container, options, codeEditorWidgetOptions);
|
||||
CONTEXT_IN_BREAKPOINT_WIDGET.bindTo(scopedContextKeyService).set(true);
|
||||
@@ -227,6 +235,29 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
|
||||
return suggestionsPromise;
|
||||
}
|
||||
}));
|
||||
|
||||
this.toDispose.push(this._configurationService.onDidChangeConfiguration((e) => {
|
||||
if (e.affectsConfiguration('editor.fontSize') || e.affectsConfiguration('editor.lineHeight')) {
|
||||
this.input.updateOptions(this.createEditorOptions());
|
||||
this.centerInputVertically();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private createEditorOptions(): IEditorOptions {
|
||||
const editorConfig = this._configurationService.getValue<IEditorOptions>('editor');
|
||||
const options = getSimpleEditorOptions();
|
||||
options.fontSize = editorConfig.fontSize;
|
||||
return options;
|
||||
}
|
||||
|
||||
private centerInputVertically() {
|
||||
if (this.container && typeof this.heightInPx === 'number') {
|
||||
const lineHeight = this.input.getOption(EditorOption.lineHeight);
|
||||
const lineNum = this.input.getModel().getLineCount();
|
||||
const newTopMargin = (this.heightInPx - lineNum * lineHeight) / 2;
|
||||
this.inputContainer.style.marginTop = newTopMargin + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
private createDecorations(): IDecorationOptions[] {
|
||||
|
||||
@@ -28,9 +28,11 @@ import { attachInputBoxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||
import { ViewletPane, IViewletPaneOptions } from 'vs/workbench/browser/parts/views/paneViewlet';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { Gesture } from 'vs/base/browser/touch';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -38,11 +40,12 @@ function createCheckbox(): HTMLInputElement {
|
||||
const checkbox = <HTMLInputElement>$('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.tabIndex = -1;
|
||||
Gesture.ignoreTarget(checkbox);
|
||||
|
||||
return checkbox;
|
||||
}
|
||||
|
||||
export class BreakpointsView extends ViewletPanel {
|
||||
export class BreakpointsView extends ViewletPane {
|
||||
|
||||
private static readonly MAX_VISIBLE_FILES = 9;
|
||||
private list!: WorkbenchList<IEnablement>;
|
||||
@@ -60,7 +63,7 @@ export class BreakpointsView extends ViewletPanel {
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
) {
|
||||
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('breakpointsSection', "Breakpoints Section") }, keybindingService, contextMenuService, configurationService, contextKeyService);
|
||||
super({ ...(options as IViewletPaneOptions), ariaHeaderLabel: nls.localize('breakpointsSection', "Breakpoints Section") }, keybindingService, contextMenuService, configurationService, contextKeyService);
|
||||
|
||||
this.minimumBodySize = this.maximumBodySize = this.getExpandedBodySize();
|
||||
this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange()));
|
||||
@@ -85,6 +88,9 @@ export class BreakpointsView extends ViewletPanel {
|
||||
getPosInSet: (_: IEnablement, index: number) => index,
|
||||
getRole: (breakpoint: IEnablement) => 'checkbox',
|
||||
isChecked: (breakpoint: IEnablement) => breakpoint.enabled
|
||||
},
|
||||
overrideStyles: {
|
||||
listBackground: SIDE_BAR_BACKGROUND
|
||||
}
|
||||
});
|
||||
|
||||
@@ -346,7 +352,7 @@ class BreakpointsRenderer implements IListRenderer<IBreakpoint, IBreakpointTempl
|
||||
data.checkbox.checked = breakpoint.enabled;
|
||||
|
||||
const { message, className } = getBreakpointMessageAndClassName(this.debugService, breakpoint);
|
||||
data.icon.className = className + ' icon';
|
||||
data.icon.className = `codicon ${className}`;
|
||||
data.breakpoint.title = breakpoint.message || message || '';
|
||||
|
||||
const debugActive = this.debugService.state === State.Running || this.debugService.state === State.Stopped;
|
||||
@@ -441,7 +447,7 @@ class FunctionBreakpointsRenderer implements IListRenderer<FunctionBreakpoint, I
|
||||
data.context = functionBreakpoint;
|
||||
data.name.textContent = functionBreakpoint.name;
|
||||
const { className, message } = getBreakpointMessageAndClassName(this.debugService, functionBreakpoint);
|
||||
data.icon.className = className + ' icon';
|
||||
data.icon.className = `codicon ${className}`;
|
||||
data.icon.title = message ? message : '';
|
||||
data.checkbox.checked = functionBreakpoint.enabled;
|
||||
data.breakpoint.title = message ? message : '';
|
||||
@@ -496,7 +502,7 @@ class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IBaseBrea
|
||||
data.context = dataBreakpoint;
|
||||
data.name.textContent = dataBreakpoint.label;
|
||||
const { className, message } = getBreakpointMessageAndClassName(this.debugService, dataBreakpoint);
|
||||
data.icon.className = className + ' icon';
|
||||
data.icon.className = `codicon ${className}`;
|
||||
data.icon.title = message ? message : '';
|
||||
data.checkbox.checked = dataBreakpoint.enabled;
|
||||
data.breakpoint.title = message ? message : '';
|
||||
@@ -587,7 +593,7 @@ class FunctionBreakpointInputRenderer implements IListRenderer<IFunctionBreakpoi
|
||||
data.reactedOnEvent = false;
|
||||
const { className, message } = getBreakpointMessageAndClassName(this.debugService, functionBreakpoint);
|
||||
|
||||
data.icon.className = className + ' icon';
|
||||
data.icon.className = `codicon ${className}`;
|
||||
data.icon.title = message ? message : '';
|
||||
data.checkbox.checked = functionBreakpoint.enabled;
|
||||
data.checkbox.disabled = true;
|
||||
@@ -638,7 +644,7 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
|
||||
if (!breakpoint.enabled || !debugService.getModel().areBreakpointsActivated()) {
|
||||
return {
|
||||
className: breakpoint instanceof DataBreakpoint ? 'debug-data-breakpoint-disabled' : breakpoint instanceof FunctionBreakpoint ? 'debug-function-breakpoint-disabled' : breakpoint.logMessage ? 'debug-breakpoint-log-disabled' : 'debug-breakpoint-disabled',
|
||||
className: breakpoint instanceof DataBreakpoint ? 'codicon-debug-breakpoint-data-disabled' : breakpoint instanceof FunctionBreakpoint ? 'codicon-debug-breakpoint-function-disabled' : breakpoint.logMessage ? 'codicon-debug-breakpoint-log-disabled' : 'codicon-debug-breakpoint-disabled',
|
||||
message: breakpoint.logMessage ? nls.localize('disabledLogpoint', "Disabled Logpoint") : nls.localize('disabledBreakpoint', "Disabled Breakpoint"),
|
||||
};
|
||||
}
|
||||
@@ -648,7 +654,7 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
};
|
||||
if (debugActive && !breakpoint.verified) {
|
||||
return {
|
||||
className: breakpoint instanceof DataBreakpoint ? 'debug-data-breakpoint-unverified' : breakpoint instanceof FunctionBreakpoint ? 'debug-function-breakpoint-unverified' : breakpoint.logMessage ? 'debug-breakpoint-log-unverified' : 'debug-breakpoint-unverified',
|
||||
className: breakpoint instanceof DataBreakpoint ? 'codicon-debug-breakpoint-data-unverified' : breakpoint instanceof FunctionBreakpoint ? 'codicon-debug-breakpoint-function-unverified' : breakpoint.logMessage ? 'codicon-debug-breakpoint-log-unverified' : 'codicon-debug-breakpoint-unverified',
|
||||
message: breakpoint.message || (breakpoint.logMessage ? nls.localize('unverifiedLogpoint', "Unverified Logpoint") : nls.localize('unverifiedBreakopint', "Unverified Breakpoint")),
|
||||
};
|
||||
}
|
||||
@@ -656,13 +662,13 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
if (breakpoint instanceof FunctionBreakpoint) {
|
||||
if (!breakpoint.supported) {
|
||||
return {
|
||||
className: 'debug-function-breakpoint-unverified',
|
||||
className: 'codicon-debug-breakpoint-function-unverified',
|
||||
message: nls.localize('functionBreakpointUnsupported', "Function breakpoints not supported by this debug type"),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
className: 'debug-function-breakpoint',
|
||||
className: 'codicon-debug-breakpoint-function',
|
||||
message: breakpoint.message || nls.localize('functionBreakpoint', "Function Breakpoint")
|
||||
};
|
||||
}
|
||||
@@ -670,13 +676,13 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
if (breakpoint instanceof DataBreakpoint) {
|
||||
if (!breakpoint.supported) {
|
||||
return {
|
||||
className: 'debug-data-breakpoint-unverified',
|
||||
className: 'codicon-debug-breakpoint-data-unverified',
|
||||
message: nls.localize('dataBreakpointUnsupported', "Data breakpoints not supported by this debug type"),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
className: 'debug-data-breakpoint',
|
||||
className: 'codicon-debug-breakpoint-data',
|
||||
message: breakpoint.message || nls.localize('dataBreakpoint', "Data Breakpoint")
|
||||
};
|
||||
}
|
||||
@@ -686,7 +692,7 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
|
||||
if (!breakpoint.supported) {
|
||||
return {
|
||||
className: 'debug-breakpoint-unsupported',
|
||||
className: 'codicon-debug-breakpoint-unsupported',
|
||||
message: nls.localize('breakpointUnsupported', "Breakpoints of this type are not supported by the debugger"),
|
||||
};
|
||||
}
|
||||
@@ -702,13 +708,32 @@ export function getBreakpointMessageAndClassName(debugService: IDebugService, br
|
||||
}
|
||||
|
||||
return {
|
||||
className: breakpoint.logMessage ? 'debug-breakpoint-log' : 'debug-breakpoint-conditional',
|
||||
className: breakpoint.logMessage ? 'codicon-debug-breakpoint-log' : 'codicon-debug-breakpoint-conditional',
|
||||
message: appendMessage(messages.join('\n'))
|
||||
};
|
||||
}
|
||||
|
||||
const focusedThread = debugService.getViewModel().focusedThread;
|
||||
if (focusedThread) {
|
||||
const callStack = focusedThread ? focusedThread.getCallStack() : undefined;
|
||||
const topStackFrame = callStack ? callStack[0] : undefined;
|
||||
if (topStackFrame && topStackFrame.source.uri.toString() === breakpoint.uri.toString() && topStackFrame.range.startLineNumber === breakpoint.lineNumber) {
|
||||
if (topStackFrame.range.startColumn === breakpoint.column) {
|
||||
return {
|
||||
className: 'codicon-debug-breakpoint-stackframe-dot',
|
||||
message: breakpoint.message || nls.localize('breakpoint', "Breakpoint")
|
||||
};
|
||||
} else if (breakpoint.column === undefined) {
|
||||
return {
|
||||
className: 'codicon-debug-breakpoint',
|
||||
message: breakpoint.message || nls.localize('breakpoint', "Breakpoint")
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
className: 'debug-breakpoint',
|
||||
className: 'codicon-debug-breakpoint',
|
||||
message: breakpoint.message || nls.localize('breakpoint', "Breakpoint")
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,14 +18,13 @@ import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IViewletPanelOptions, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||
import { IViewletPaneOptions, ViewletPane } from 'vs/workbench/browser/parts/views/paneViewlet';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { ITreeRenderer, ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
|
||||
import { TreeResourceNavigator2, WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { createMatches, FuzzyScore } from 'vs/base/common/filters';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
@@ -35,12 +34,26 @@ import { isSessionAttach } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { STOP_ID, STOP_LABEL, DISCONNECT_ID, DISCONNECT_LABEL, RESTART_SESSION_ID, RESTART_LABEL, STEP_OVER_ID, STEP_OVER_LABEL, STEP_INTO_LABEL, STEP_INTO_ID, STEP_OUT_LABEL, STEP_OUT_ID, PAUSE_ID, PAUSE_LABEL, CONTINUE_ID, CONTINUE_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { CollapseAction } from 'vs/workbench/browser/viewlet';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
type CallStackItem = IStackFrame | IThread | IDebugSession | string | ThreadAndSessionIds | IStackFrame[];
|
||||
|
||||
export class CallStackView extends ViewletPanel {
|
||||
function getContext(element: CallStackItem | null): any {
|
||||
return element instanceof StackFrame ? {
|
||||
sessionId: element.thread.session.getId(),
|
||||
threadId: element.thread.getId(),
|
||||
frameId: element.getId()
|
||||
} : element instanceof Thread ? {
|
||||
sessionId: element.session.getId(),
|
||||
threadId: element.getId()
|
||||
} : isDebugSession(element) ? {
|
||||
sessionId: element.getId()
|
||||
} : undefined;
|
||||
}
|
||||
|
||||
export class CallStackView extends ViewletPane {
|
||||
|
||||
private pauseMessage!: HTMLSpanElement;
|
||||
private pauseMessageLabel!: HTMLSpanElement;
|
||||
@@ -66,7 +79,7 @@ export class CallStackView extends ViewletPanel {
|
||||
@IMenuService menuService: IMenuService,
|
||||
@IContextKeyService readonly contextKeyService: IContextKeyService,
|
||||
) {
|
||||
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('callstackSection', "Call Stack Section") }, keybindingService, contextMenuService, configurationService, contextKeyService);
|
||||
super({ ...(options as IViewletPaneOptions), ariaHeaderLabel: nls.localize('callstackSection', "Call Stack Section") }, keybindingService, contextMenuService, configurationService, contextKeyService);
|
||||
this.callStackItemType = CONTEXT_CALLSTACK_ITEM_TYPE.bindTo(contextKeyService);
|
||||
|
||||
this.contributedContextMenu = menuService.createMenu(MenuId.DebugCallStackContext, contextKeyService);
|
||||
@@ -90,7 +103,7 @@ export class CallStackView extends ViewletPanel {
|
||||
} else {
|
||||
this.pauseMessage.hidden = true;
|
||||
if (this.toolbar) {
|
||||
const collapseAction = new CollapseAction(this.tree, true, 'explorer-action collapse-explorer');
|
||||
const collapseAction = new CollapseAction(this.tree, true, 'explorer-action codicon-collapse-all');
|
||||
this.toolbar.setActions([collapseAction])();
|
||||
}
|
||||
}
|
||||
@@ -122,7 +135,7 @@ export class CallStackView extends ViewletPanel {
|
||||
const treeContainer = renderViewTree(container);
|
||||
|
||||
this.dataSource = new CallStackDataSource(this.debugService);
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'CallStackView', treeContainer, new CallStackDelegate(), [
|
||||
this.tree = this.instantiationService.createInstance<typeof WorkbenchAsyncDataTree, WorkbenchAsyncDataTree<CallStackItem | IDebugModel, CallStackItem, FuzzyScore>>(WorkbenchAsyncDataTree, 'CallStackView', treeContainer, new CallStackDelegate(), [
|
||||
new SessionsRenderer(this.instantiationService),
|
||||
new ThreadsRenderer(this.instantiationService),
|
||||
this.instantiationService.createInstance(StackFramesRenderer),
|
||||
@@ -162,10 +175,13 @@ export class CallStackView extends ViewletPanel {
|
||||
return nls.localize('showMoreStackFrames2', "Show More Stack Frames");
|
||||
}
|
||||
},
|
||||
expandOnlyOnTwistieClick: true
|
||||
expandOnlyOnTwistieClick: true,
|
||||
overrideStyles: {
|
||||
listBackground: SIDE_BAR_BACKGROUND
|
||||
}
|
||||
});
|
||||
|
||||
this.tree.setInput(this.debugService.getModel()).then(undefined, onUnexpectedError);
|
||||
this.tree.setInput(this.debugService.getModel());
|
||||
|
||||
const callstackNavigator = new TreeResourceNavigator2(this.tree);
|
||||
this._register(callstackNavigator);
|
||||
@@ -326,15 +342,15 @@ export class CallStackView extends ViewletPanel {
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => e.anchor,
|
||||
getActions: () => actions,
|
||||
getActionsContext: () => element && element instanceof StackFrame ? element.getId() : undefined,
|
||||
getActionsContext: () => getContext(element),
|
||||
onHide: () => dispose(actionsDisposable)
|
||||
});
|
||||
}
|
||||
|
||||
private getContextForContributedActions(element: CallStackItem | null): string | number | undefined {
|
||||
private getContextForContributedActions(element: CallStackItem | null): string | number {
|
||||
if (element instanceof StackFrame) {
|
||||
if (element.source.inMemory) {
|
||||
return element.source.raw.path || element.source.reference;
|
||||
return element.source.raw.path || element.source.reference || '';
|
||||
}
|
||||
|
||||
return element.source.uri.toString();
|
||||
@@ -346,7 +362,7 @@ export class CallStackView extends ViewletPanel {
|
||||
return element.getId();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,6 +398,7 @@ interface IStackFrameTemplateData {
|
||||
fileName: HTMLElement;
|
||||
lineNumber: HTMLElement;
|
||||
label: HighlightedLabel;
|
||||
actionBar: ActionBar;
|
||||
}
|
||||
|
||||
class SessionsRenderer implements ITreeRenderer<IDebugSession, FuzzyScore, ISessionTemplateData> {
|
||||
@@ -478,8 +495,9 @@ class StackFramesRenderer implements ITreeRenderer<IStackFrame, FuzzyScore, ISta
|
||||
const wrapper = dom.append(file, $('span.line-number-wrapper'));
|
||||
const lineNumber = dom.append(wrapper, $('span.line-number'));
|
||||
const label = new HighlightedLabel(labelDiv, false);
|
||||
const actionBar = new ActionBar(stackFrame);
|
||||
|
||||
return { file, fileName, label, lineNumber, stackFrame };
|
||||
return { file, fileName, label, lineNumber, stackFrame, actionBar };
|
||||
}
|
||||
|
||||
renderElement(element: ITreeNode<IStackFrame, FuzzyScore>, index: number, data: IStackFrameTemplateData): void {
|
||||
@@ -487,6 +505,8 @@ class StackFramesRenderer implements ITreeRenderer<IStackFrame, FuzzyScore, ISta
|
||||
dom.toggleClass(data.stackFrame, 'disabled', !stackFrame.source || !stackFrame.source.available || isDeemphasized(stackFrame));
|
||||
dom.toggleClass(data.stackFrame, 'label', stackFrame.presentationHint === 'label');
|
||||
dom.toggleClass(data.stackFrame, 'subtle', stackFrame.presentationHint === 'subtle');
|
||||
const hasActions = stackFrame.thread.session.capabilities.supportsRestartFrame;
|
||||
dom.toggleClass(data.stackFrame, 'has-actions', hasActions);
|
||||
|
||||
data.file.title = stackFrame.source.inMemory ? stackFrame.source.uri.path : this.labelService.getUriLabel(stackFrame.source.uri);
|
||||
if (stackFrame.source.raw.origin) {
|
||||
@@ -503,10 +523,18 @@ class StackFramesRenderer implements ITreeRenderer<IStackFrame, FuzzyScore, ISta
|
||||
} else {
|
||||
dom.addClass(data.lineNumber, 'unavailable');
|
||||
}
|
||||
|
||||
data.actionBar.clear();
|
||||
if (hasActions) {
|
||||
const action = new Action('debug.callStack.restartFrame', nls.localize('restartFrame', "Restart Frame"), 'codicon-debug-restart-frame', true, () => {
|
||||
return stackFrame.restart();
|
||||
});
|
||||
data.actionBar.push(action, { icon: true, label: false });
|
||||
}
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IStackFrameTemplateData): void {
|
||||
// noop
|
||||
templateData.actionBar.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -644,7 +672,7 @@ class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem
|
||||
if (sessions.length === 0) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
if (sessions.length > 1) {
|
||||
if (sessions.length > 1 || this.debugService.getViewModel().isMultiSessionView()) {
|
||||
return Promise.resolve(sessions.filter(s => !s.parentSession));
|
||||
}
|
||||
|
||||
@@ -786,11 +814,11 @@ class StopAction extends Action {
|
||||
private readonly session: IDebugSession,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${STOP_ID}`, STOP_LABEL, 'debug-action stop');
|
||||
super(`action.${STOP_ID}`, STOP_LABEL, 'debug-action codicon-debug-stop');
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(STOP_ID, this.session.getId(), this.session);
|
||||
return this.commandService.executeCommand(STOP_ID, getContext(this.session));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -800,11 +828,11 @@ class DisconnectAction extends Action {
|
||||
private readonly session: IDebugSession,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${DISCONNECT_ID}`, DISCONNECT_LABEL, 'debug-action disconnect');
|
||||
super(`action.${DISCONNECT_ID}`, DISCONNECT_LABEL, 'debug-action codicon-debug-disconnect');
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(DISCONNECT_ID, this.session.getId(), this.session);
|
||||
return this.commandService.executeCommand(DISCONNECT_ID, getContext(this.session));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -814,11 +842,11 @@ class RestartAction extends Action {
|
||||
private readonly session: IDebugSession,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${RESTART_SESSION_ID}`, RESTART_LABEL, 'debug-action restart');
|
||||
super(`action.${RESTART_SESSION_ID}`, RESTART_LABEL, 'debug-action codicon-debug-restart');
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(RESTART_SESSION_ID, this.session.getId(), this.session);
|
||||
return this.commandService.executeCommand(RESTART_SESSION_ID, getContext(this.session));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -828,11 +856,11 @@ class StepOverAction extends Action {
|
||||
private readonly thread: IThread,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${STEP_OVER_ID}`, STEP_OVER_LABEL, 'debug-action step-over', thread.stopped);
|
||||
super(`action.${STEP_OVER_ID}`, STEP_OVER_LABEL, 'debug-action codicon-debug-step-over', thread.stopped);
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(STEP_OVER_ID, this.thread.threadId, this.thread);
|
||||
return this.commandService.executeCommand(STEP_OVER_ID, getContext(this.thread));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -842,11 +870,11 @@ class StepIntoAction extends Action {
|
||||
private readonly thread: IThread,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${STEP_INTO_ID}`, STEP_INTO_LABEL, 'debug-action step-into', thread.stopped);
|
||||
super(`action.${STEP_INTO_ID}`, STEP_INTO_LABEL, 'debug-action codicon-debug-step-into', thread.stopped);
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(STEP_INTO_ID, this.thread.threadId, this.thread);
|
||||
return this.commandService.executeCommand(STEP_INTO_ID, getContext(this.thread));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -856,11 +884,11 @@ class StepOutAction extends Action {
|
||||
private readonly thread: IThread,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${STEP_OUT_ID}`, STEP_OUT_LABEL, 'debug-action step-out', thread.stopped);
|
||||
super(`action.${STEP_OUT_ID}`, STEP_OUT_LABEL, 'debug-action codicon-debug-step-out', thread.stopped);
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(STEP_OUT_ID, this.thread.threadId, this.thread);
|
||||
return this.commandService.executeCommand(STEP_OUT_ID, getContext(this.thread));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -870,11 +898,11 @@ class PauseAction extends Action {
|
||||
private readonly thread: IThread,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${PAUSE_ID}`, PAUSE_LABEL, 'debug-action pause', !thread.stopped);
|
||||
super(`action.${PAUSE_ID}`, PAUSE_LABEL, 'debug-action codicon-debug-pause', !thread.stopped);
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(PAUSE_ID, this.thread.threadId, this.thread);
|
||||
return this.commandService.executeCommand(PAUSE_ID, getContext(this.thread));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -884,10 +912,10 @@ class ContinueAction extends Action {
|
||||
private readonly thread: IThread,
|
||||
@ICommandService private readonly commandService: ICommandService
|
||||
) {
|
||||
super(`action.${CONTINUE_ID}`, CONTINUE_LABEL, 'debug-action continue', thread.stopped);
|
||||
super(`action.${CONTINUE_ID}`, CONTINUE_LABEL, 'debug-action codicon-debug-continue', thread.stopped);
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
return this.commandService.executeCommand(CONTINUE_ID, this.thread.threadId, this.thread);
|
||||
return this.commandService.executeCommand(CONTINUE_ID, getContext(this.thread));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import { CallStackView } from 'vs/workbench/contrib/debug/browser/callStackView'
|
||||
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import {
|
||||
IDebugService, VIEWLET_ID, REPL_ID, CONTEXT_IN_DEBUG_MODE, INTERNAL_CONSOLE_OPTIONS_SCHEMA,
|
||||
CONTEXT_DEBUG_STATE, VARIABLES_VIEW_ID, CALLSTACK_VIEW_ID, WATCH_VIEW_ID, BREAKPOINTS_VIEW_ID, VIEW_CONTAINER, LOADED_SCRIPTS_VIEW_ID, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_CALLSTACK_ITEM_TYPE, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED,
|
||||
CONTEXT_DEBUG_STATE, VARIABLES_VIEW_ID, CALLSTACK_VIEW_ID, WATCH_VIEW_ID, BREAKPOINTS_VIEW_ID, VIEW_CONTAINER, LOADED_SCRIPTS_VIEW_ID, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_CALLSTACK_ITEM_TYPE, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_DEBUG_UX,
|
||||
} from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
@@ -47,8 +47,9 @@ import { WatchExpressionsView } from 'vs/workbench/contrib/debug/browser/watchEx
|
||||
import { VariablesView } from 'vs/workbench/contrib/debug/browser/variablesView';
|
||||
import { ClearReplAction, Repl } from 'vs/workbench/contrib/debug/browser/repl';
|
||||
import { DebugContentProvider } from 'vs/workbench/contrib/debug/common/debugContentProvider';
|
||||
import { registerAndGetAmdImageURL } from 'vs/base/common/amd';
|
||||
import { DebugCallStackContribution } from 'vs/workbench/contrib/debug/browser/debugCallStackContribution';
|
||||
import { StartView } from 'vs/workbench/contrib/debug/browser/startView';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
class OpenDebugViewletAction extends ShowViewletAction {
|
||||
public static readonly ID = VIEWLET_ID;
|
||||
@@ -80,13 +81,12 @@ class OpenDebugPanelAction extends TogglePanelAction {
|
||||
}
|
||||
|
||||
// register viewlet
|
||||
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor(
|
||||
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(ViewletDescriptor.create(
|
||||
DebugViewlet,
|
||||
VIEWLET_ID,
|
||||
nls.localize('debug', "Debug"),
|
||||
'debug',
|
||||
// {{SQL CARBON EDIT}}
|
||||
13
|
||||
nls.localize('debugAndRun', "Debug And Run"),
|
||||
'codicon-debug',
|
||||
13 // {{SQL CARBON EDIT}}
|
||||
));
|
||||
|
||||
const openViewletKb: IKeybindings = {
|
||||
@@ -97,7 +97,7 @@ const openPanelKb: IKeybindings = {
|
||||
};
|
||||
|
||||
// register repl panel
|
||||
Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(new PanelDescriptor(
|
||||
Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(PanelDescriptor.create(
|
||||
Repl,
|
||||
REPL_ID,
|
||||
nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugPanel' }, 'Debug Console'),
|
||||
@@ -108,18 +108,19 @@ Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(new PanelDescri
|
||||
|
||||
// Register default debug views
|
||||
const viewsRegistry = Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry);
|
||||
viewsRegistry.registerViews([{ id: VARIABLES_VIEW_ID, name: nls.localize('variables', "Variables"), ctorDescriptor: { ctor: VariablesView }, order: 10, weight: 40, canToggleVisibility: true, focusCommand: { id: 'workbench.debug.action.focusVariablesView' } }], VIEW_CONTAINER);
|
||||
viewsRegistry.registerViews([{ id: WATCH_VIEW_ID, name: nls.localize('watch', "Watch"), ctorDescriptor: { ctor: WatchExpressionsView }, order: 20, weight: 10, canToggleVisibility: true, focusCommand: { id: 'workbench.debug.action.focusWatchView' } }], VIEW_CONTAINER);
|
||||
viewsRegistry.registerViews([{ id: CALLSTACK_VIEW_ID, name: nls.localize('callStack', "Call Stack"), ctorDescriptor: { ctor: CallStackView }, order: 30, weight: 30, canToggleVisibility: true, focusCommand: { id: 'workbench.debug.action.focusCallStackView' } }], VIEW_CONTAINER);
|
||||
viewsRegistry.registerViews([{ id: BREAKPOINTS_VIEW_ID, name: nls.localize('breakpoints', "Breakpoints"), ctorDescriptor: { ctor: BreakpointsView }, order: 40, weight: 20, canToggleVisibility: true, focusCommand: { id: 'workbench.debug.action.focusBreakpointsView' } }], VIEW_CONTAINER);
|
||||
viewsRegistry.registerViews([{ id: LOADED_SCRIPTS_VIEW_ID, name: nls.localize('loadedScripts', "Loaded Scripts"), ctorDescriptor: { ctor: LoadedScriptsView }, order: 35, weight: 5, canToggleVisibility: true, collapsed: true, when: CONTEXT_LOADED_SCRIPTS_SUPPORTED }], VIEW_CONTAINER);
|
||||
viewsRegistry.registerViews([{ id: VARIABLES_VIEW_ID, name: nls.localize('variables', "Variables"), ctorDescriptor: { ctor: VariablesView }, order: 10, weight: 40, canToggleVisibility: true, focusCommand: { id: 'workbench.debug.action.focusVariablesView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], VIEW_CONTAINER);
|
||||
viewsRegistry.registerViews([{ id: WATCH_VIEW_ID, name: nls.localize('watch', "Watch"), ctorDescriptor: { ctor: WatchExpressionsView }, order: 20, weight: 10, canToggleVisibility: true, focusCommand: { id: 'workbench.debug.action.focusWatchView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], VIEW_CONTAINER);
|
||||
viewsRegistry.registerViews([{ id: CALLSTACK_VIEW_ID, name: nls.localize('callStack', "Call Stack"), ctorDescriptor: { ctor: CallStackView }, order: 30, weight: 30, canToggleVisibility: true, focusCommand: { id: 'workbench.debug.action.focusCallStackView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], VIEW_CONTAINER);
|
||||
viewsRegistry.registerViews([{ id: BREAKPOINTS_VIEW_ID, name: nls.localize('breakpoints', "Breakpoints"), ctorDescriptor: { ctor: BreakpointsView }, order: 40, weight: 20, canToggleVisibility: true, focusCommand: { id: 'workbench.debug.action.focusBreakpointsView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], VIEW_CONTAINER);
|
||||
viewsRegistry.registerViews([{ id: StartView.ID, name: StartView.LABEL, ctorDescriptor: { ctor: StartView }, order: 10, weight: 40, canToggleVisibility: true, when: CONTEXT_DEBUG_UX.isEqualTo('simple') }], VIEW_CONTAINER);
|
||||
viewsRegistry.registerViews([{ id: LOADED_SCRIPTS_VIEW_ID, name: nls.localize('loadedScripts', "Loaded Scripts"), ctorDescriptor: { ctor: LoadedScriptsView }, order: 35, weight: 5, canToggleVisibility: true, collapsed: true, when: ContextKeyExpr.and(CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_DEBUG_UX.isEqualTo('default')) }], VIEW_CONTAINER);
|
||||
|
||||
registerCommands();
|
||||
|
||||
// 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.registerWorkbenchAction(SyncActionDescriptor.create(OpenDebugPanelAction, OpenDebugPanelAction.ID, OpenDebugPanelAction.LABEL, openPanelKb), 'View: Debug Console', nls.localize('view', "View"));
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenDebugViewletAction, OpenDebugViewletAction.ID, OpenDebugViewletAction.LABEL, openViewletKb), 'View: Show Debug', nls.localize('view', "View"));
|
||||
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugCallStackContribution, LifecyclePhase.Restored);
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugToolBar, LifecyclePhase.Restored);
|
||||
@@ -128,16 +129,16 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).regi
|
||||
|
||||
const debugCategory = nls.localize('debugCategory', "Debug");
|
||||
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(StartAction, StartAction.ID, StartAction.LABEL, { primary: KeyCode.F5 }, CONTEXT_IN_DEBUG_MODE.toNegated()), 'Debug: Start Debugging', 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, mac: { primary: KeyMod.WinCtrl | KeyCode.F5 } }), '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(SelectAndStartAction, SelectAndStartAction.ID, SelectAndStartAction.LABEL), 'Debug: Select and Start Debugging', debugCategory);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL), 'Debug: Clear Console', debugCategory);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(StartAction, StartAction.ID, StartAction.LABEL, { primary: KeyCode.F5 }, CONTEXT_IN_DEBUG_MODE.toNegated()), 'Debug: Start Debugging', debugCategory);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(ConfigureAction, ConfigureAction.ID, ConfigureAction.LABEL), 'Debug: Open launch.json', debugCategory);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(AddFunctionBreakpointAction, AddFunctionBreakpointAction.ID, AddFunctionBreakpointAction.LABEL), 'Debug: Add Function Breakpoint', debugCategory);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(ReapplyBreakpointsAction, ReapplyBreakpointsAction.ID, ReapplyBreakpointsAction.LABEL), 'Debug: Reapply All Breakpoints', debugCategory);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(RunAction, RunAction.ID, RunAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.F5, mac: { primary: KeyMod.WinCtrl | KeyCode.F5 } }), 'Debug: Start Without Debugging', debugCategory);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(RemoveAllBreakpointsAction, RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL), 'Debug: Remove All Breakpoints', debugCategory);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(EnableAllBreakpointsAction, EnableAllBreakpointsAction.ID, EnableAllBreakpointsAction.LABEL), 'Debug: Enable All Breakpoints', debugCategory);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(DisableAllBreakpointsAction, DisableAllBreakpointsAction.ID, DisableAllBreakpointsAction.LABEL), 'Debug: Disable All Breakpoints', debugCategory);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(SelectAndStartAction, SelectAndStartAction.ID, SelectAndStartAction.LABEL), 'Debug: Select and Start Debugging', debugCategory);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.create(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL), 'Debug: Clear Console', debugCategory);
|
||||
|
||||
const registerDebugCommandPaletteItem = (id: string, title: string, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => {
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
||||
@@ -167,7 +168,7 @@ registerDebugCommandPaletteItem(TOGGLE_INLINE_BREAKPOINT_ID, nls.localize('inlin
|
||||
|
||||
// Register Quick Open
|
||||
(Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler(
|
||||
new QuickOpenHandlerDescriptor(
|
||||
QuickOpenHandlerDescriptor.create(
|
||||
DebugQuickOpenHandler,
|
||||
DebugQuickOpenHandler.ID,
|
||||
'debug ',
|
||||
@@ -270,6 +271,11 @@ configurationRegistry.registerConfiguration({
|
||||
type: 'boolean',
|
||||
description: nls.localize({ comment: ['This is the description for a setting'], key: 'showBreakpointsInOverviewRuler' }, "Controls whether breakpoints should be shown in the overview ruler."),
|
||||
default: false
|
||||
},
|
||||
'debug.showInlineBreakpointCandidates': {
|
||||
type: 'boolean',
|
||||
description: nls.localize({ comment: ['This is the description for a setting'], key: 'showInlineBreakpointCandidates' }, "Controls whether inline breakpoints candidate decorations should be shown in the editor while debugging."),
|
||||
default: true
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -279,7 +285,7 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).regi
|
||||
|
||||
// Debug toolbar
|
||||
|
||||
const registerDebugToolBarItem = (id: string, title: string, iconLightUri: URI, iconDarkUri: URI, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => {
|
||||
const registerDebugToolBarItem = (id: string, title: string, order: number, icon: { light?: URI, dark?: URI } | ThemeIcon, when?: ContextKeyExpr, precondition?: ContextKeyExpr) => {
|
||||
MenuRegistry.appendMenuItem(MenuId.DebugToolBar, {
|
||||
group: 'navigation',
|
||||
when,
|
||||
@@ -287,25 +293,22 @@ const registerDebugToolBarItem = (id: string, title: string, iconLightUri: URI,
|
||||
command: {
|
||||
id,
|
||||
title,
|
||||
iconLocation: {
|
||||
light: iconLightUri,
|
||||
dark: iconDarkUri
|
||||
},
|
||||
icon,
|
||||
precondition
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
registerDebugToolBarItem(CONTINUE_ID, CONTINUE_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/continue-dark.svg')), 10, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(PAUSE_ID, PAUSE_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/pause-dark.svg')), 10, CONTEXT_DEBUG_STATE.notEqualsTo('stopped'));
|
||||
registerDebugToolBarItem(STOP_ID, STOP_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/stop-dark.svg')), 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated());
|
||||
registerDebugToolBarItem(DISCONNECT_ID, DISCONNECT_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/disconnect-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/disconnect-dark.svg')), 70, CONTEXT_FOCUSED_SESSION_IS_ATTACH);
|
||||
registerDebugToolBarItem(STEP_OVER_ID, STEP_OVER_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-over-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-over-dark.svg')), 20, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(STEP_INTO_ID, STEP_INTO_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-into-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-into-dark.svg')), 30, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(STEP_OUT_ID, STEP_OUT_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-out-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-out-dark.svg')), 40, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(RESTART_SESSION_ID, RESTART_LABEL, URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/restart-dark.svg')), 60);
|
||||
registerDebugToolBarItem(STEP_BACK_ID, nls.localize('stepBackDebug', "Step Back"), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-back-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/step-back-dark.svg')), 50, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(REVERSE_CONTINUE_ID, nls.localize('reverseContinue', "Reverse"), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/reverse-continue-light.svg')), URI.parse(registerAndGetAmdImageURL('vs/workbench/contrib/debug/browser/media/reverse-continue-dark.svg')), 60, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(CONTINUE_ID, CONTINUE_LABEL, 10, { id: 'codicon/debug-continue' }, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(PAUSE_ID, PAUSE_LABEL, 10, { id: 'codicon/debug-pause' }, CONTEXT_DEBUG_STATE.notEqualsTo('stopped'));
|
||||
registerDebugToolBarItem(STOP_ID, STOP_LABEL, 70, { id: 'codicon/debug-stop' }, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated());
|
||||
registerDebugToolBarItem(DISCONNECT_ID, DISCONNECT_LABEL, 70, { id: 'codicon/debug-disconnect' }, CONTEXT_FOCUSED_SESSION_IS_ATTACH);
|
||||
registerDebugToolBarItem(STEP_OVER_ID, STEP_OVER_LABEL, 20, { id: 'codicon/debug-step-over' }, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(STEP_INTO_ID, STEP_INTO_LABEL, 30, { id: 'codicon/debug-step-into' }, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(STEP_OUT_ID, STEP_OUT_LABEL, 40, { id: 'codicon/debug-step-out' }, undefined, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(RESTART_SESSION_ID, RESTART_LABEL, 60, { id: 'codicon/debug-restart' });
|
||||
registerDebugToolBarItem(STEP_BACK_ID, nls.localize('stepBackDebug', "Step Back"), 50, { id: 'codicon/debug-step-back' }, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
registerDebugToolBarItem(REVERSE_CONTINUE_ID, nls.localize('reverseContinue', "Reverse"), 60, { id: 'codicon/debug-reverse-continue' }, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
|
||||
|
||||
// Debug callstack context menu
|
||||
const registerDebugCallstackItem = (id: string, title: string, order: number, when?: ContextKeyExpr, precondition?: ContextKeyExpr, group = 'navigation') => {
|
||||
@@ -370,7 +373,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarDebugMenu, {
|
||||
group: '1_debug',
|
||||
command: {
|
||||
id: RunAction.ID,
|
||||
title: nls.localize({ key: 'miStartWithoutDebugging', comment: ['&& denotes a mnemonic'] }, "Start &&Without Debugging")
|
||||
title: nls.localize({ key: 'miRun', comment: ['&& denotes a mnemonic'] }, "Run &&Without Debugging")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
@@ -554,7 +557,7 @@ if (isMacintosh) {
|
||||
command: {
|
||||
id,
|
||||
title,
|
||||
iconLocation: { dark: iconUri }
|
||||
icon: { dark: iconUri }
|
||||
},
|
||||
when,
|
||||
group: '9_debug',
|
||||
|
||||
@@ -69,7 +69,7 @@ export class StartDebugActionViewItem implements IActionViewItem {
|
||||
render(container: HTMLElement): void {
|
||||
this.container = container;
|
||||
dom.addClass(container, 'start-debug-action-item');
|
||||
this.start = dom.append(container, $('.icon'));
|
||||
this.start = dom.append(container, $('.codicon.codicon-debug-start'));
|
||||
this.start.title = this.action.label;
|
||||
this.start.setAttribute('role', 'button');
|
||||
this.start.tabIndex = 0;
|
||||
|
||||
@@ -62,7 +62,7 @@ export class ConfigureAction extends AbstractDebugAction {
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService
|
||||
) {
|
||||
super(id, label, 'debug-action configure', debugService, keybindingService);
|
||||
super(id, label, 'debug-action codicon codicon-gear', debugService, keybindingService);
|
||||
this._register(debugService.getConfigurationManager().onDidSelectConfiguration(() => this.updateClass()));
|
||||
this.updateClass();
|
||||
}
|
||||
@@ -78,7 +78,7 @@ export class ConfigureAction extends AbstractDebugAction {
|
||||
private updateClass(): void {
|
||||
const configurationManager = this.debugService.getConfigurationManager();
|
||||
const configurationCount = configurationManager.getLaunches().map(l => l.getConfigurationNames().length).reduce((sum, current) => sum + current);
|
||||
this.class = configurationCount > 0 ? 'debug-action configure' : 'debug-action configure notification';
|
||||
this.class = configurationCount > 0 ? 'debug-action codicon codicon-gear' : 'debug-action codicon codicon-gear notification';
|
||||
}
|
||||
|
||||
async run(event?: any): Promise<any> {
|
||||
@@ -143,7 +143,7 @@ export class StartAction extends AbstractDebugAction {
|
||||
|
||||
export class RunAction extends StartAction {
|
||||
static readonly ID = 'workbench.action.debug.run';
|
||||
static LABEL = nls.localize('startWithoutDebugging', "Start Without Debugging");
|
||||
static LABEL = nls.localize('startWithoutDebugging', "Run (Start Without Debugging)");
|
||||
|
||||
protected isNoDebug(): boolean {
|
||||
return true;
|
||||
@@ -186,7 +186,7 @@ export class RemoveAllBreakpointsAction extends AbstractDebugAction {
|
||||
static readonly 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);
|
||||
super(id, label, 'debug-action codicon-close-all', debugService, keybindingService);
|
||||
this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ export class ToggleBreakpointsActivatedAction extends AbstractDebugAction {
|
||||
static readonly 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);
|
||||
super(id, label, 'debug-action codicon-activate-breakpoints', debugService, keybindingService);
|
||||
this.updateLabel(this.debugService.getModel().areBreakpointsActivated() ? ToggleBreakpointsActivatedAction.DEACTIVATE_LABEL : ToggleBreakpointsActivatedAction.ACTIVATE_LABEL);
|
||||
|
||||
this._register(this.debugService.getModel().onDidChangeBreakpoints(() => {
|
||||
@@ -287,7 +287,7 @@ export class AddFunctionBreakpointAction extends AbstractDebugAction {
|
||||
static readonly 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);
|
||||
super(id, label, 'debug-action codicon-add', debugService, keybindingService);
|
||||
this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ export class AddWatchExpressionAction extends AbstractDebugAction {
|
||||
static readonly 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);
|
||||
super(id, label, 'debug-action codicon-add', debugService, keybindingService);
|
||||
this._register(this.debugService.getModel().onDidChangeWatchExpressions(() => this.updateEnablement()));
|
||||
this._register(this.debugService.getViewModel().onDidSelectExpression(() => this.updateEnablement()));
|
||||
}
|
||||
@@ -326,7 +326,7 @@ export class RemoveAllWatchExpressionsAction extends AbstractDebugAction {
|
||||
static readonly 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);
|
||||
super(id, label, 'debug-action codicon-close-all', debugService, keybindingService);
|
||||
this._register(this.debugService.getModel().onDidChangeWatchExpressions(() => this.updateEnablement()));
|
||||
}
|
||||
|
||||
|
||||
@@ -128,12 +128,12 @@ export class DebugCallStackContribution implements IWorkbenchContribution {
|
||||
static readonly STICKINESS = TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges;
|
||||
// we need a separate decoration for glyph margin, since we do not want it on each line of a multi line statement.
|
||||
private static TOP_STACK_FRAME_MARGIN: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-top-stack-frame',
|
||||
glyphMarginClassName: 'codicon-debug-breakpoint-stackframe',
|
||||
stickiness
|
||||
};
|
||||
|
||||
private static FOCUSED_STACK_FRAME_MARGIN: IModelDecorationOptions = {
|
||||
glyphMarginClassName: 'debug-focused-stack-frame',
|
||||
glyphMarginClassName: 'codicon-debug-breakpoint-stackframe-focused',
|
||||
stickiness
|
||||
};
|
||||
|
||||
@@ -176,7 +176,68 @@ registerThemingParticipant((theme, collector) => {
|
||||
if (focusedStackFrame) {
|
||||
collector.addRule(`.monaco-editor .view-overlays .debug-focused-stack-frame-line { background: ${focusedStackFrame}; }`);
|
||||
}
|
||||
|
||||
const debugIconBreakpointColor = theme.getColor(debugIconBreakpointForeground);
|
||||
if (debugIconBreakpointColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .codicon-debug-breakpoint,
|
||||
.monaco-workbench .codicon-debug-breakpoint-conditional,
|
||||
.monaco-workbench .codicon-debug-breakpoint-log,
|
||||
.monaco-workbench .codicon-debug-breakpoint-function,
|
||||
.monaco-workbench .codicon-debug-breakpoint-data,
|
||||
.monaco-workbench .codicon-debug-breakpoint-unsupported,
|
||||
.monaco-workbench .codicon-debug-hint:not(*[class*='codicon-debug-breakpoint']) ,
|
||||
.monaco-workbench .codicon-debug-breakpoint-stackframe-dot,
|
||||
.monaco-workbench .codicon-debug-breakpoint.codicon-debug-breakpoint-stackframe-focused::after {
|
||||
color: ${debugIconBreakpointColor} !important;
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
const debugIconBreakpointDisabledColor = theme.getColor(debugIconBreakpointDisabledForeground);
|
||||
if (debugIconBreakpointDisabledColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .codicon[class*='-disabled'] {
|
||||
color: ${debugIconBreakpointDisabledColor} !important;
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
const debugIconBreakpointUnverifiedColor = theme.getColor(debugIconBreakpointUnverifiedForeground);
|
||||
if (debugIconBreakpointUnverifiedColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .codicon[class*='-unverified'] {
|
||||
color: ${debugIconBreakpointUnverifiedColor} !important;
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
const debugIconBreakpointStackframeColor = theme.getColor(debugIconBreakpointStackframeForeground);
|
||||
if (debugIconBreakpointStackframeColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .codicon-debug-breakpoint-stackframe,
|
||||
.monaco-workbench .codicon-debug-breakpoint-stackframe-dot::after {
|
||||
color: ${debugIconBreakpointStackframeColor} !important;
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
const debugIconBreakpointStackframeFocusedColor = theme.getColor(debugIconBreakpointStackframeFocusedForeground);
|
||||
if (debugIconBreakpointStackframeFocusedColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .codicon-debug-breakpoint-stackframe-focused {
|
||||
color: ${debugIconBreakpointStackframeFocusedColor} !important;
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
const topStackFrameColor = registerColor('editor.stackFrameHighlightBackground', { dark: '#ffff0033', light: '#ffff6673', hc: '#fff600' }, localize('topStackFrameLineHighlight', 'Background color for the highlight of line at the top stack frame position.'));
|
||||
const focusedStackFrameColor = registerColor('editor.focusedStackFrameHighlightBackground', { dark: '#7abd7a4d', light: '#cee7ce73', hc: '#cee7ce' }, localize('focusedStackFrameLineHighlight', 'Background color for the highlight of line at focused stack frame position.'));
|
||||
|
||||
const debugIconBreakpointForeground = registerColor('debugIcon.breakpointForeground', { dark: '#E51400', light: '#E51400', hc: '#E51400' }, localize('debugIcon.breakpointForeground', 'Icon color for breakpoints.'));
|
||||
const debugIconBreakpointDisabledForeground = registerColor('debugIcon.breakpointDisabledForeground', { dark: '#848484', light: '#848484', hc: '#848484' }, localize('debugIcon.breakpointDisabledForeground', 'Icon color for disabled breakpoints.'));
|
||||
const debugIconBreakpointUnverifiedForeground = registerColor('debugIcon.breakpointUnverifiedForeground', { dark: '#848484', light: '#848484', hc: '#848484' }, localize('debugIcon.breakpointUnverifiedForeground', 'Icon color for unverified breakpoints.'));
|
||||
const debugIconBreakpointStackframeForeground = registerColor('debugIcon.breakpointStackframeForeground', { dark: '#FFCC00', light: '#FFCC00', hc: '#FFCC00' }, localize('debugIcon.breakpointStackframeForeground', 'Icon color for breakpoints.'));
|
||||
const debugIconBreakpointStackframeFocusedForeground = registerColor('debugIcon.breakpointStackframeFocusedForeground', { dark: '#89D185', light: '#89D185', hc: '#89D185' }, localize('debugIcon.breakpointStackframeFocusedForeground', 'Icon color for breakpoints.'));
|
||||
|
||||
@@ -58,15 +58,24 @@ export const DISCONNECT_LABEL = nls.localize('disconnect', "Disconnect");
|
||||
export const STOP_LABEL = nls.localize('stop', "Stop");
|
||||
export const CONTINUE_LABEL = nls.localize('continueDebug', "Continue");
|
||||
|
||||
async function getThreadAndRun(accessor: ServicesAccessor, threadId: number | any, run: (thread: IThread) => Promise<void>): Promise<void> {
|
||||
interface CallStackContext {
|
||||
sessionId: string;
|
||||
threadId: string;
|
||||
frameId: string;
|
||||
}
|
||||
|
||||
function isThreadContext(obj: any): obj is CallStackContext {
|
||||
return obj && typeof obj.sessionId === 'string' && typeof obj.threadId === 'string';
|
||||
}
|
||||
|
||||
async function getThreadAndRun(accessor: ServicesAccessor, sessionAndThreadId: CallStackContext | unknown, run: (thread: IThread) => Promise<void>): Promise<void> {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
let thread: IThread | undefined;
|
||||
if (typeof threadId === 'number') {
|
||||
debugService.getModel().getSessions().forEach(s => {
|
||||
if (!thread) {
|
||||
thread = s.getThread(threadId);
|
||||
}
|
||||
});
|
||||
if (isThreadContext(sessionAndThreadId)) {
|
||||
const session = debugService.getModel().getSession(sessionAndThreadId.sessionId);
|
||||
if (session) {
|
||||
thread = session.getAllThreads().filter(t => t.getId() === sessionAndThreadId.threadId).pop();
|
||||
}
|
||||
} else {
|
||||
thread = debugService.getViewModel().focusedThread;
|
||||
if (!thread) {
|
||||
@@ -81,18 +90,17 @@ async function getThreadAndRun(accessor: ServicesAccessor, threadId: number | an
|
||||
}
|
||||
}
|
||||
|
||||
function getFrame(debugService: IDebugService, frameId: string | undefined): IStackFrame | undefined {
|
||||
if (!frameId) {
|
||||
return undefined;
|
||||
}
|
||||
function isStackFrameContext(obj: any): obj is CallStackContext {
|
||||
return obj && typeof obj.sessionId === 'string' && typeof obj.threadId === 'string' && typeof obj.frameId === 'string';
|
||||
}
|
||||
|
||||
const sessions = debugService.getModel().getSessions();
|
||||
for (let s of sessions) {
|
||||
for (let t of s.getAllThreads()) {
|
||||
for (let sf of t.getCallStack()) {
|
||||
if (sf.getId() === frameId) {
|
||||
return sf;
|
||||
}
|
||||
function getFrame(debugService: IDebugService, context: CallStackContext | unknown): IStackFrame | undefined {
|
||||
if (isStackFrameContext(context)) {
|
||||
const session = debugService.getModel().getSession(context.sessionId);
|
||||
if (session) {
|
||||
const thread = session.getAllThreads().filter(t => t.getId() === context.threadId).pop();
|
||||
if (thread) {
|
||||
return thread.getCallStack().filter(sf => sf.getId() === context.frameId).pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,6 +108,10 @@ function getFrame(debugService: IDebugService, frameId: string | undefined): ISt
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isSessionContext(obj: any): obj is CallStackContext {
|
||||
return obj && typeof obj.sessionId === 'string';
|
||||
}
|
||||
|
||||
export function registerCommands(): void {
|
||||
|
||||
// These commands are used in call stack context menu, call stack inline actions, command pallete, debug toolbar, mac native touch bar
|
||||
@@ -108,10 +120,10 @@ export function registerCommands(): void {
|
||||
// Same for stackFrame commands and session commands.
|
||||
CommandsRegistry.registerCommand({
|
||||
id: COPY_STACK_TRACE_ID,
|
||||
handler: async (accessor: ServicesAccessor, _: string, frameId: string | undefined) => {
|
||||
handler: async (accessor: ServicesAccessor, context: CallStackContext | unknown) => {
|
||||
const textResourcePropertiesService = accessor.get(ITextResourcePropertiesService);
|
||||
const clipboardService = accessor.get(IClipboardService);
|
||||
let frame = getFrame(accessor.get(IDebugService), frameId);
|
||||
let frame = getFrame(accessor.get(IDebugService), context);
|
||||
if (frame) {
|
||||
const eol = textResourcePropertiesService.getEOL(frame.source.uri);
|
||||
await clipboardService.writeText(frame.thread.getCallStack().map(sf => sf.toString()).join(eol));
|
||||
@@ -121,22 +133,22 @@ export function registerCommands(): void {
|
||||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: REVERSE_CONTINUE_ID,
|
||||
handler: (accessor: ServicesAccessor, threadId: number | any) => {
|
||||
getThreadAndRun(accessor, threadId, thread => thread.reverseContinue());
|
||||
handler: (accessor: ServicesAccessor, context: CallStackContext | unknown) => {
|
||||
getThreadAndRun(accessor, context, thread => thread.reverseContinue());
|
||||
}
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: STEP_BACK_ID,
|
||||
handler: (accessor: ServicesAccessor, threadId: number | any) => {
|
||||
getThreadAndRun(accessor, threadId, thread => thread.stepBack());
|
||||
handler: (accessor: ServicesAccessor, context: CallStackContext | unknown) => {
|
||||
getThreadAndRun(accessor, context, thread => thread.stepBack());
|
||||
}
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: TERMINATE_THREAD_ID,
|
||||
handler: (accessor: ServicesAccessor, threadId: number | any) => {
|
||||
getThreadAndRun(accessor, threadId, thread => thread.terminate());
|
||||
handler: (accessor: ServicesAccessor, context: CallStackContext | unknown) => {
|
||||
getThreadAndRun(accessor, context, thread => thread.terminate());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -194,9 +206,12 @@ export function registerCommands(): void {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.F5,
|
||||
when: CONTEXT_IN_DEBUG_MODE,
|
||||
handler: (accessor: ServicesAccessor, _: string, session: IDebugSession | undefined) => {
|
||||
handler: (accessor: ServicesAccessor, context: CallStackContext | unknown) => {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
if (!session || !session.getId) {
|
||||
let session: IDebugSession | undefined;
|
||||
if (isSessionContext(context)) {
|
||||
session = debugService.getModel().getSession(context.sessionId);
|
||||
} else {
|
||||
session = debugService.getViewModel().focusedSession;
|
||||
}
|
||||
|
||||
@@ -215,8 +230,8 @@ export function registerCommands(): void {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyCode.F10,
|
||||
when: CONTEXT_DEBUG_STATE.isEqualTo('stopped'),
|
||||
handler: (accessor: ServicesAccessor, threadId: number | any) => {
|
||||
getThreadAndRun(accessor, threadId, (thread: IThread) => thread.next());
|
||||
handler: (accessor: ServicesAccessor, context: CallStackContext | unknown) => {
|
||||
getThreadAndRun(accessor, context, (thread: IThread) => thread.next());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -224,9 +239,9 @@ export function registerCommands(): void {
|
||||
id: STEP_INTO_ID,
|
||||
weight: KeybindingWeight.WorkbenchContrib + 10, // Have a stronger weight to have priority over full screen when debugging
|
||||
primary: KeyCode.F11,
|
||||
when: CONTEXT_IN_DEBUG_MODE,
|
||||
handler: (accessor: ServicesAccessor, threadId: number | any) => {
|
||||
getThreadAndRun(accessor, threadId, (thread: IThread) => thread.stepIn());
|
||||
when: CONTEXT_DEBUG_STATE.isEqualTo('stopped'),
|
||||
handler: (accessor: ServicesAccessor, context: CallStackContext | unknown) => {
|
||||
getThreadAndRun(accessor, context, (thread: IThread) => thread.stepIn());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -235,8 +250,8 @@ export function registerCommands(): void {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.Shift | KeyCode.F11,
|
||||
when: CONTEXT_DEBUG_STATE.isEqualTo('stopped'),
|
||||
handler: (accessor: ServicesAccessor, threadId: number | any) => {
|
||||
getThreadAndRun(accessor, threadId, (thread: IThread) => thread.stepOut());
|
||||
handler: (accessor: ServicesAccessor, context: CallStackContext | unknown) => {
|
||||
getThreadAndRun(accessor, context, (thread: IThread) => thread.stepOut());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -245,8 +260,8 @@ export function registerCommands(): void {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyCode.F6,
|
||||
when: CONTEXT_DEBUG_STATE.isEqualTo('running'),
|
||||
handler: (accessor: ServicesAccessor, threadId: number | any) => {
|
||||
getThreadAndRun(accessor, threadId, thread => thread.pause());
|
||||
handler: (accessor: ServicesAccessor, context: CallStackContext | unknown) => {
|
||||
getThreadAndRun(accessor, context, thread => thread.pause());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -264,9 +279,15 @@ export function registerCommands(): void {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.Shift | KeyCode.F5,
|
||||
when: CONTEXT_IN_DEBUG_MODE,
|
||||
handler: (accessor: ServicesAccessor, sessionId: string | undefined) => {
|
||||
handler: (accessor: ServicesAccessor, context: CallStackContext | unknown) => {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
let session = debugService.getModel().getSession(sessionId) || debugService.getViewModel().focusedSession;
|
||||
let session: IDebugSession | undefined;
|
||||
if (isSessionContext(context)) {
|
||||
session = debugService.getModel().getSession(context.sessionId);
|
||||
} else {
|
||||
session = debugService.getViewModel().focusedSession;
|
||||
}
|
||||
|
||||
const configurationService = accessor.get(IConfigurationService);
|
||||
const showSubSessions = configurationService.getValue<IDebugConfiguration>('debug').showSubSessionsInToolBar;
|
||||
// Stop should be sent to the root parent session
|
||||
@@ -280,9 +301,9 @@ export function registerCommands(): void {
|
||||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: RESTART_FRAME_ID,
|
||||
handler: async (accessor: ServicesAccessor, _: string, frameId: string | undefined) => {
|
||||
handler: async (accessor: ServicesAccessor, context: CallStackContext | unknown) => {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
let frame = getFrame(debugService, frameId);
|
||||
let frame = getFrame(debugService, context);
|
||||
if (frame) {
|
||||
await frame.restart();
|
||||
}
|
||||
@@ -294,8 +315,8 @@ export function registerCommands(): void {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyCode.F5,
|
||||
when: CONTEXT_IN_DEBUG_MODE,
|
||||
handler: (accessor: ServicesAccessor, threadId: number | any) => {
|
||||
getThreadAndRun(accessor, threadId, thread => thread.continue());
|
||||
handler: (accessor: ServicesAccessor, context: CallStackContext | unknown) => {
|
||||
getThreadAndRun(accessor, context, thread => thread.continue());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import * as objects from 'vs/base/common/objects';
|
||||
import { URI as uri } from 'vs/base/common/uri';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IEditor } from 'vs/workbench/common/editor';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
@@ -56,6 +57,7 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
private adapterDescriptorFactories: IDebugAdapterDescriptorFactory[];
|
||||
private debugAdapterFactories = new Map<string, IDebugAdapterFactory>();
|
||||
private debugConfigurationTypeContext: IContextKey<string>;
|
||||
private readonly _onDidRegisterDebugger = new Emitter<void>();
|
||||
|
||||
constructor(
|
||||
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
|
||||
@@ -166,6 +168,10 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
get onDidRegisterDebugger(): Event<void> {
|
||||
return this._onDidRegisterDebugger.event;
|
||||
}
|
||||
|
||||
// debug configurations
|
||||
|
||||
registerDebugConfigurationProvider(debugConfigurationProvider: IDebugConfigurationProvider): IDisposable {
|
||||
@@ -196,11 +202,15 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
const providers = this.configProviders.filter(p => p.type === type && p.resolveDebugConfiguration)
|
||||
.concat(this.configProviders.filter(p => p.type === '*' && p.resolveDebugConfiguration));
|
||||
|
||||
let result: IConfig | null | undefined = config;
|
||||
await sequence(providers.map(provider => async () => {
|
||||
config = (await provider.resolveDebugConfiguration!(folderUri, config, token)) || config;
|
||||
// If any provider returned undefined or null make sure to respect that and do not pass the result to more resolver
|
||||
if (result) {
|
||||
result = await provider.resolveDebugConfiguration!(folderUri, result, token);
|
||||
}
|
||||
}));
|
||||
|
||||
return config;
|
||||
return result;
|
||||
}
|
||||
|
||||
async provideDebugConfigurations(folderUri: uri | undefined, type: string, token: CancellationToken): Promise<any[]> {
|
||||
@@ -262,6 +272,7 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
});
|
||||
|
||||
this.setCompoundSchemaValues();
|
||||
this._onDidRegisterDebugger.fire();
|
||||
});
|
||||
|
||||
breakpointsExtPoint.setHandler((extensions, delta) => {
|
||||
@@ -275,7 +286,8 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
|
||||
this.toDispose.push(this.contextService.onDidChangeWorkspaceFolders(() => {
|
||||
this.initLaunches();
|
||||
this.selectConfiguration(this.selectedLaunch);
|
||||
const toSelect = this.selectedLaunch || (this.launches.length > 0 ? this.launches[0] : undefined);
|
||||
this.selectConfiguration(toSelect);
|
||||
this.setCompoundSchemaValues();
|
||||
}));
|
||||
this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => {
|
||||
@@ -384,6 +396,17 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
return this.debuggers.filter(dbg => strings.equalsIgnoreCase(dbg.type, type)).pop();
|
||||
}
|
||||
|
||||
getDebuggerLabelsForEditor(editor: editorCommon.IEditor | undefined): string[] {
|
||||
if (isCodeEditor(editor)) {
|
||||
const model = editor.getModel();
|
||||
const language = model ? model.getLanguageIdentifier().language : undefined;
|
||||
|
||||
return this.debuggers.filter(a => language && a.languages && a.languages.indexOf(language) >= 0).map(d => d.label);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
async guessDebugger(type?: string): Promise<Debugger | undefined> {
|
||||
if (type) {
|
||||
const adapter = this.getDebugger(type);
|
||||
@@ -411,16 +434,16 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
|
||||
candidates.sort((first, second) => first.label.localeCompare(second.label));
|
||||
const picks = candidates.map(c => ({ label: c.label, debugger: c }));
|
||||
const picked = await this.quickInputService.pick<{ label: string, debugger: Debugger | undefined }>([...picks, { type: 'separator' }, { label: 'More...', debugger: undefined }], { placeHolder: nls.localize('selectDebug', "Select Environment") });
|
||||
|
||||
if (picked && picked.debugger) {
|
||||
return picked.debugger;
|
||||
}
|
||||
if (picked) {
|
||||
this.commandService.executeCommand('debug.installAdditionalDebuggers');
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return this.quickInputService.pick<{ label: string, debugger: Debugger | undefined }>([...picks, { type: 'separator' }, { label: nls.localize('more', "More..."), debugger: undefined }], { placeHolder: nls.localize('selectDebug', "Select Environment") })
|
||||
.then(picked => {
|
||||
if (picked && picked.debugger) {
|
||||
return picked.debugger;
|
||||
}
|
||||
if (picked) {
|
||||
this.commandService.executeCommand('debug.installAdditionalDebuggers');
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
async activateDebuggers(activationEvent: string, debugType?: string): Promise<void> {
|
||||
|
||||
@@ -111,7 +111,7 @@ export class RunToCursorAction extends EditorAction {
|
||||
label: RunToCursorAction.LABEL,
|
||||
alias: 'Debug: Run to Cursor',
|
||||
precondition: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, PanelFocusContext.toNegated(), CONTEXT_DEBUG_STATE.isEqualTo('stopped'), EditorContextKeys.editorTextFocus),
|
||||
menuOpts: {
|
||||
contextMenuOpts: {
|
||||
group: 'debug',
|
||||
order: 2
|
||||
}
|
||||
@@ -160,7 +160,7 @@ class SelectionToReplAction extends EditorAction {
|
||||
label: nls.localize('debugEvaluate', "Debug: Evaluate"),
|
||||
alias: 'Debug: Evaluate',
|
||||
precondition: ContextKeyExpr.and(EditorContextKeys.hasNonEmptySelection, CONTEXT_IN_DEBUG_MODE, EditorContextKeys.editorTextFocus),
|
||||
menuOpts: {
|
||||
contextMenuOpts: {
|
||||
group: 'debug',
|
||||
order: 0
|
||||
}
|
||||
@@ -190,7 +190,7 @@ class SelectionToWatchExpressionsAction extends EditorAction {
|
||||
label: nls.localize('debugAddToWatch', "Debug: Add to Watch"),
|
||||
alias: 'Debug: Add to Watch',
|
||||
precondition: ContextKeyExpr.and(EditorContextKeys.hasNonEmptySelection, CONTEXT_IN_DEBUG_MODE, EditorContextKeys.editorTextFocus),
|
||||
menuOpts: {
|
||||
contextMenuOpts: {
|
||||
group: 'debug',
|
||||
order: 1
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ 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 { ICodeEditor, IEditorMouseEvent, MouseTargetType, IPartialEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
|
||||
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { IDecorationOptions } from 'vs/editor/common/editorCommon';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
@@ -80,7 +80,7 @@ class DebugEditorContribution implements IDebugEditorContribution {
|
||||
this.toDispose.push(this.editor.onMouseDown((e: IEditorMouseEvent) => this.onEditorMouseDown(e)));
|
||||
this.toDispose.push(this.editor.onMouseUp(() => this.mouseDown = false));
|
||||
this.toDispose.push(this.editor.onMouseMove((e: IEditorMouseEvent) => this.onEditorMouseMove(e)));
|
||||
this.toDispose.push(this.editor.onMouseLeave((e: IEditorMouseEvent) => {
|
||||
this.toDispose.push(this.editor.onMouseLeave((e: IPartialEditorMouseEvent) => {
|
||||
this.provideNonDebugHoverScheduler.cancel();
|
||||
const hoverDomNode = this.hoverWidget.getDomNode();
|
||||
if (!hoverDomNode) {
|
||||
|
||||
@@ -20,7 +20,7 @@ import { renderExpressionValue, replaceWhitespace } from 'vs/workbench/contrib/d
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import { attachStylerCallback } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { editorHoverBackground, editorHoverBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { editorHoverBackground, editorHoverBorder, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { getExactExpressionStartAndEnd } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree';
|
||||
@@ -73,12 +73,15 @@ export class DebugHoverWidget implements IContentWidget {
|
||||
this.treeContainer.setAttribute('role', 'tree');
|
||||
const dataSource = new DebugHoverDataSource();
|
||||
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'DebugHover', this.treeContainer, new DebugHoverDelegate(), [this.instantiationService.createInstance(VariablesRenderer)],
|
||||
this.tree = this.instantiationService.createInstance<typeof WorkbenchAsyncDataTree, WorkbenchAsyncDataTree<IExpression, IExpression, any>>(WorkbenchAsyncDataTree, 'DebugHover', this.treeContainer, new DebugHoverDelegate(), [this.instantiationService.createInstance(VariablesRenderer)],
|
||||
dataSource, {
|
||||
ariaLabel: nls.localize('treeAriaLabel', "Debug Hover"),
|
||||
accessibilityProvider: new DebugHoverAccessibilityProvider(),
|
||||
mouseSupport: false,
|
||||
horizontalScrolling: true
|
||||
horizontalScrolling: true,
|
||||
overrideStyles: {
|
||||
listBackground: editorHoverBackground
|
||||
}
|
||||
});
|
||||
|
||||
this.valueContainer = $('.value');
|
||||
@@ -90,7 +93,7 @@ export class DebugHoverWidget implements IContentWidget {
|
||||
|
||||
this.editor.applyFontInfo(this.domNode);
|
||||
|
||||
this.toDispose.push(attachStylerCallback(this.themeService, { editorHoverBackground, editorHoverBorder }, colors => {
|
||||
this.toDispose.push(attachStylerCallback(this.themeService, { editorHoverBackground, editorHoverBorder, editorHoverForeground }, colors => {
|
||||
if (colors.editorHoverBackground) {
|
||||
this.domNode.style.backgroundColor = colors.editorHoverBackground.toString();
|
||||
} else {
|
||||
@@ -101,6 +104,11 @@ export class DebugHoverWidget implements IContentWidget {
|
||||
} else {
|
||||
this.domNode.style.border = '';
|
||||
}
|
||||
if (colors.editorHoverForeground) {
|
||||
this.domNode.style.color = colors.editorHoverForeground.toString();
|
||||
} else {
|
||||
this.domNode.style.color = null;
|
||||
}
|
||||
}));
|
||||
this.toDispose.push(this.tree.onDidChangeContentHeight(() => this.layoutTreeAndContainer()));
|
||||
|
||||
|
||||
@@ -40,13 +40,14 @@ import { IAction } from 'vs/base/common/actions';
|
||||
import { deepClone, equals } from 'vs/base/common/objects';
|
||||
import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IDebugService, State, IDebugSession, CONTEXT_DEBUG_TYPE, CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_MODE, IThread, IDebugConfiguration, VIEWLET_ID, REPL_ID, IConfig, ILaunch, IViewModel, IConfigurationManager, IDebugModel, IEnablement, IBreakpoint, IBreakpointData, ICompound, IGlobalConfig, IStackFrame, AdapterEndEvent, getStateLabel, IDebugSessionOptions } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebugService, State, IDebugSession, CONTEXT_DEBUG_TYPE, CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_MODE, IThread, IDebugConfiguration, VIEWLET_ID, REPL_ID, IConfig, ILaunch, IViewModel, IConfigurationManager, IDebugModel, IEnablement, IBreakpoint, IBreakpointData, ICompound, IGlobalConfig, IStackFrame, AdapterEndEvent, getStateLabel, IDebugSessionOptions, CONTEXT_DEBUG_UX } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { isExtensionHostDebugging } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { isErrorWithActions, createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
|
||||
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||
|
||||
const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint';
|
||||
const DEBUG_FUNCTION_BREAKPOINTS_KEY = 'debug.functionbreakpoint';
|
||||
@@ -85,6 +86,7 @@ export class DebugService implements IDebugService {
|
||||
private debugType: IContextKey<string>;
|
||||
private debugState: IContextKey<string>;
|
||||
private inDebugMode: IContextKey<boolean>;
|
||||
private debugUx: IContextKey<string>;
|
||||
private breakpointsToSendOnResourceSaved: Set<string>;
|
||||
private initializing = false;
|
||||
private previousState: State | undefined;
|
||||
@@ -126,6 +128,8 @@ export class DebugService implements IDebugService {
|
||||
this.debugType = CONTEXT_DEBUG_TYPE.bindTo(contextKeyService);
|
||||
this.debugState = CONTEXT_DEBUG_STATE.bindTo(contextKeyService);
|
||||
this.inDebugMode = CONTEXT_IN_DEBUG_MODE.bindTo(contextKeyService);
|
||||
this.debugUx = CONTEXT_DEBUG_UX.bindTo(contextKeyService);
|
||||
this.debugUx.set(!!this.configurationManager.selectedConfiguration.name ? 'default' : 'simple');
|
||||
|
||||
this.model = new DebugModel(this.loadBreakpoints(), this.loadFunctionBreakpoints(),
|
||||
this.loadExceptionBreakpoints(), this.loadDataBreakpoints(), this.loadWatchExpressions(), this.textFileService);
|
||||
@@ -169,6 +173,9 @@ export class DebugService implements IDebugService {
|
||||
this.toDispose.push(this.viewModel.onDidFocusSession(() => {
|
||||
this.onStateChange();
|
||||
}));
|
||||
this.toDispose.push(this.configurationManager.onDidSelectConfiguration(() => {
|
||||
this.debugUx.set(!!(this.state !== State.Inactive || this.configurationManager.selectedConfiguration.name) ? 'default' : 'simple');
|
||||
}));
|
||||
}
|
||||
|
||||
getModel(): IDebugModel {
|
||||
@@ -225,6 +232,7 @@ export class DebugService implements IDebugService {
|
||||
if (this.previousState !== state) {
|
||||
this.debugState.set(getStateLabel(state));
|
||||
this.inDebugMode.set(state !== State.Inactive);
|
||||
this.debugUx.set(!!(state !== State.Inactive || this.configurationManager.selectedConfiguration.name) ? 'default' : 'simple');
|
||||
this.previousState = state;
|
||||
this._onDidChangeState.fire(state);
|
||||
}
|
||||
@@ -258,7 +266,7 @@ export class DebugService implements IDebugService {
|
||||
try {
|
||||
// make sure to save all files and that the configuration is up to date
|
||||
await this.extensionService.activateByEvent('onDebug');
|
||||
await this.textFileService.saveAll();
|
||||
await this.editorService.saveAll();
|
||||
await this.configurationService.reloadConfiguration(launch ? launch.workspace : undefined);
|
||||
await this.extensionService.whenInstalledExtensionsRegistered();
|
||||
|
||||
@@ -488,8 +496,6 @@ export class DebugService implements IDebugService {
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : error;
|
||||
this.telemetryDebugMisconfiguration(session.configuration ? session.configuration.type : undefined, errorMessage);
|
||||
|
||||
await this.showError(errorMessage, isErrorWithActions(error) ? error.actions : []);
|
||||
return false;
|
||||
}
|
||||
@@ -570,7 +576,7 @@ export class DebugService implements IDebugService {
|
||||
}
|
||||
|
||||
async restartSession(session: IDebugSession, restartData?: any): Promise<any> {
|
||||
await this.textFileService.saveAll();
|
||||
await this.editorService.saveAll();
|
||||
const isAutoRestart = !!restartData;
|
||||
|
||||
const runTasks: () => Promise<TaskRunResult> = async () => {
|
||||
@@ -583,19 +589,19 @@ export class DebugService implements IDebugService {
|
||||
return this.runTaskAndCheckErrors(session.root, session.configuration.preLaunchTask);
|
||||
};
|
||||
|
||||
if (session.capabilities.supportsRestartRequest) {
|
||||
if (isExtensionHostDebugging(session.configuration)) {
|
||||
const taskResult = await runTasks();
|
||||
if (taskResult === TaskRunResult.Success) {
|
||||
await session.restart();
|
||||
this.extensionHostDebugService.reload(session.getId());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExtensionHostDebugging(session.configuration)) {
|
||||
if (session.capabilities.supportsRestartRequest) {
|
||||
const taskResult = await runTasks();
|
||||
if (taskResult === TaskRunResult.Success) {
|
||||
this.extensionHostDebugService.reload(session.getId());
|
||||
await session.restart();
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -793,6 +799,7 @@ export class DebugService implements IDebugService {
|
||||
// Check that the task isn't busy and if it is, wait for it
|
||||
const busyTasks = await this.taskService.getBusyTasks();
|
||||
if (busyTasks.filter(t => t._id === task._id).length) {
|
||||
taskStarted = true;
|
||||
return inactivePromise;
|
||||
}
|
||||
// task is already running and isn't busy - nothing to do.
|
||||
@@ -808,7 +815,7 @@ export class DebugService implements IDebugService {
|
||||
return inactivePromise;
|
||||
}
|
||||
|
||||
return taskPromise;
|
||||
return taskPromise.then(withUndefinedAsNull);
|
||||
});
|
||||
|
||||
return new Promise((c, e) => {
|
||||
@@ -1200,19 +1207,6 @@ export class DebugService implements IDebugService {
|
||||
});
|
||||
}
|
||||
|
||||
private telemetryDebugMisconfiguration(debugType: string | undefined, message: string): Promise<any> {
|
||||
/* __GDPR__
|
||||
"debugMisconfiguration" : {
|
||||
"type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"error": { "classification": "CallstackOrException", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
return this.telemetryService.publicLog('debugMisconfiguration', {
|
||||
type: debugType,
|
||||
error: message
|
||||
});
|
||||
}
|
||||
|
||||
private telemetryDebugAddBreakpoint(breakpoint: IBreakpoint, context: string): Promise<any> {
|
||||
/* __GDPR__
|
||||
"debugAddBreakpoint" : {
|
||||
|
||||
@@ -720,8 +720,8 @@ export class DebugSession implements IDebugSession {
|
||||
await this.debugService.sendAllBreakpoints(this);
|
||||
} finally {
|
||||
await sendConfigurationDone();
|
||||
await this.fetchThreads();
|
||||
}
|
||||
await this.fetchThreads();
|
||||
}));
|
||||
|
||||
this.rawListeners.push(this.raw.onDidStop(async event => {
|
||||
|
||||
@@ -19,7 +19,7 @@ import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/co
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { Themable } from 'vs/workbench/common/theme';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { registerColor, contrastBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
@@ -41,12 +41,73 @@ export const debugToolBarBackground = registerColor('debugToolBar.background', {
|
||||
light: '#F3F3F3',
|
||||
hc: '#000000'
|
||||
}, localize('debugToolBarBackground', "Debug toolbar background color."));
|
||||
|
||||
export const debugToolBarBorder = registerColor('debugToolBar.border', {
|
||||
dark: null,
|
||||
light: null,
|
||||
hc: null
|
||||
}, localize('debugToolBarBorder', "Debug toolbar border color."));
|
||||
|
||||
export const debugIconStartForeground = registerColor('debugIcon.startForeground', {
|
||||
dark: '#89D185',
|
||||
light: '#388A34',
|
||||
hc: '#89D185'
|
||||
}, localize('debugIcon.startForeground', "Debug toolbar icon for start debugging."));
|
||||
|
||||
export const debugIconPauseForeground = registerColor('debugIcon.pauseForeground', {
|
||||
dark: '#75BEFF',
|
||||
light: '#007ACC',
|
||||
hc: '#75BEFF'
|
||||
}, localize('debugIcon.pauseForeground', "Debug toolbar icon for pause."));
|
||||
|
||||
export const debugIconStopForeground = registerColor('debugIcon.stopForeground', {
|
||||
dark: '#F48771',
|
||||
light: '#A1260D',
|
||||
hc: '#F48771'
|
||||
}, localize('debugIcon.stopForeground', "Debug toolbar icon for stop."));
|
||||
|
||||
export const debugIconDisconnectForeground = registerColor('debugIcon.disconnectForeground', {
|
||||
dark: '#F48771',
|
||||
light: '#A1260D',
|
||||
hc: '#F48771'
|
||||
}, localize('debugIcon.disconnectForeground', "Debug toolbar icon for disconnect."));
|
||||
|
||||
export const debugIconRestartForeground = registerColor('debugIcon.restartForeground', {
|
||||
dark: '#89D185',
|
||||
light: '#388A34',
|
||||
hc: '#89D185'
|
||||
}, localize('debugIcon.restartForeground', "Debug toolbar icon for restart."));
|
||||
|
||||
export const debugIconStepOverForeground = registerColor('debugIcon.stepOverForeground', {
|
||||
dark: '#75BEFF',
|
||||
light: '#007ACC',
|
||||
hc: '#75BEFF'
|
||||
}, localize('debugIcon.stepOverForeground', "Debug toolbar icon for step over."));
|
||||
|
||||
export const debugIconStepIntoForeground = registerColor('debugIcon.stepIntoForeground', {
|
||||
dark: '#75BEFF',
|
||||
light: '#007ACC',
|
||||
hc: '#75BEFF'
|
||||
}, localize('debugIcon.stepIntoForeground', "Debug toolbar icon for step into."));
|
||||
|
||||
export const debugIconStepOutForeground = registerColor('debugIcon.stepOutForeground', {
|
||||
dark: '#75BEFF',
|
||||
light: '#007ACC',
|
||||
hc: '#75BEFF'
|
||||
}, localize('debugIcon.stepOutForeground', "Debug toolbar icon for step over."));
|
||||
|
||||
export const debugIconContinueForeground = registerColor('debugIcon.continueForeground', {
|
||||
dark: '#75BEFF',
|
||||
light: '#007ACC',
|
||||
hc: '#75BEFF'
|
||||
}, localize('debugIcon.continueForeground', "Debug toolbar icon for continue."));
|
||||
|
||||
export const debugIconStepBackForeground = registerColor('debugIcon.stepBackForeground', {
|
||||
dark: '#75BEFF',
|
||||
light: '#007ACC',
|
||||
hc: '#75BEFF'
|
||||
}, localize('debugIcon.stepBackForeground', "Debug toolbar icon for step back."));
|
||||
|
||||
export class DebugToolBar extends Themable implements IWorkbenchContribution {
|
||||
|
||||
private $el: HTMLElement;
|
||||
@@ -56,6 +117,7 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
|
||||
private updateScheduler: RunOnceScheduler;
|
||||
private debugToolBarMenu: IMenu;
|
||||
private disposeOnUpdate: IDisposable | undefined;
|
||||
private yCoordinate = 0;
|
||||
|
||||
private isVisible = false;
|
||||
private isBuilt = false;
|
||||
@@ -79,7 +141,7 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
|
||||
this.$el = dom.$('div.debug-toolbar');
|
||||
this.$el.style.top = `${layoutService.getTitleBarOffset()}px`;
|
||||
|
||||
this.dragArea = dom.append(this.$el, dom.$('div.drag-area'));
|
||||
this.dragArea = dom.append(this.$el, dom.$('div.drag-area.codicon.codicon-gripper'));
|
||||
|
||||
const actionBarContainer = dom.append(this.$el, dom.$('div.action-bar-container'));
|
||||
this.debugToolBarMenu = menuService.createMenu(MenuId.DebugToolBar, contextKeyService);
|
||||
@@ -146,7 +208,7 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
|
||||
}));
|
||||
this._register(dom.addDisposableListener(window, dom.EventType.RESIZE, () => this.setCoordinates()));
|
||||
|
||||
this._register(dom.addDisposableListener(this.dragArea, dom.EventType.MOUSE_UP, (event: MouseEvent) => {
|
||||
this._register(dom.addDisposableGenericMouseUpListner(this.dragArea, (event: MouseEvent) => {
|
||||
const mouseClickEvent = new StandardMouseEvent(event);
|
||||
if (mouseClickEvent.detail === 2) {
|
||||
// double click on debug bar centers it again #8250
|
||||
@@ -156,10 +218,10 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(this.dragArea, dom.EventType.MOUSE_DOWN, (event: MouseEvent) => {
|
||||
this._register(dom.addDisposableGenericMouseDownListner(this.dragArea, (event: MouseEvent) => {
|
||||
dom.addClass(this.dragArea, 'dragged');
|
||||
|
||||
const mouseMoveListener = dom.addDisposableListener(window, 'mousemove', (e: MouseEvent) => {
|
||||
const mouseMoveListener = dom.addDisposableGenericMouseMoveListner(window, (e: MouseEvent) => {
|
||||
const mouseMoveEvent = new StandardMouseEvent(e);
|
||||
// Prevent default to stop editor selecting text #8524
|
||||
mouseMoveEvent.preventDefault();
|
||||
@@ -167,7 +229,7 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
|
||||
this.setCoordinates(mouseMoveEvent.posx - 14, mouseMoveEvent.posy - this.layoutService.getTitleBarOffset());
|
||||
});
|
||||
|
||||
const mouseUpListener = dom.addDisposableListener(window, 'mouseup', (e: MouseEvent) => {
|
||||
const mouseUpListener = dom.addDisposableGenericMouseUpListner(window, (e: MouseEvent) => {
|
||||
this.storePosition();
|
||||
dom.removeClass(this.dragArea, 'dragged');
|
||||
|
||||
@@ -209,9 +271,10 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
|
||||
}
|
||||
}
|
||||
|
||||
private setYCoordinate(y = 0): void {
|
||||
private setYCoordinate(y = this.yCoordinate): void {
|
||||
const titlebarOffset = this.layoutService.getTitleBarOffset();
|
||||
this.$el.style.top = `${titlebarOffset + y}px`;
|
||||
this.yCoordinate = y;
|
||||
}
|
||||
|
||||
private setCoordinates(x?: number, y?: number): void {
|
||||
@@ -289,3 +352,56 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
|
||||
const debugIconStartColor = theme.getColor(debugIconStartForeground);
|
||||
if (debugIconStartColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-debug-start { color: ${debugIconStartColor} !important; }`);
|
||||
}
|
||||
|
||||
const debugIconPauseColor = theme.getColor(debugIconPauseForeground);
|
||||
if (debugIconPauseColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-debug-pause { color: ${debugIconPauseColor} !important; }`);
|
||||
}
|
||||
|
||||
const debugIconStopColor = theme.getColor(debugIconStopForeground);
|
||||
if (debugIconStopColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-debug-stop { color: ${debugIconStopColor} !important; }`);
|
||||
}
|
||||
|
||||
const debugIconDisconnectColor = theme.getColor(debugIconDisconnectForeground);
|
||||
if (debugIconDisconnectColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-debug-disconnect { color: ${debugIconDisconnectColor} !important; }`);
|
||||
}
|
||||
|
||||
const debugIconRestartColor = theme.getColor(debugIconRestartForeground);
|
||||
if (debugIconRestartColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-debug-restart, .monaco-workbench .codicon-debug-restart-frame { color: ${debugIconRestartColor} !important; }`);
|
||||
}
|
||||
|
||||
const debugIconStepOverColor = theme.getColor(debugIconStepOverForeground);
|
||||
if (debugIconStepOverColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-debug-step-over { color: ${debugIconStepOverColor} !important; }`);
|
||||
}
|
||||
|
||||
const debugIconStepIntoColor = theme.getColor(debugIconStepIntoForeground);
|
||||
if (debugIconStepIntoColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-debug-step-into { color: ${debugIconStepIntoColor} !important; }`);
|
||||
}
|
||||
|
||||
const debugIconStepOutColor = theme.getColor(debugIconStepOutForeground);
|
||||
if (debugIconStepOutColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-debug-step-out { color: ${debugIconStepOutColor} !important; }`);
|
||||
}
|
||||
|
||||
const debugIconContinueColor = theme.getColor(debugIconContinueForeground);
|
||||
if (debugIconContinueColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-debug-continue,.monaco-workbench .codicon-debug-reverse-continue { color: ${debugIconContinueColor} !important; }`);
|
||||
}
|
||||
|
||||
const debugIconStepBackColor = theme.getColor(debugIconStepBackForeground);
|
||||
if (debugIconStepBackColor) {
|
||||
collector.addRule(`.monaco-workbench .codicon-debug-step-back { color: ${debugIconStepBackColor} !important; }`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ import { IAction } from 'vs/base/common/actions';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { IDebugService, VIEWLET_ID, State, BREAKPOINTS_VIEW_ID, IDebugConfiguration, REPL_ID } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebugService, VIEWLET_ID, State, BREAKPOINTS_VIEW_ID, IDebugConfiguration, REPL_ID, CONTEXT_DEBUG_UX, CONTEXT_DEBUG_UX_KEY } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { StartAction, ConfigureAction, SelectAndStartAction, FocusSessionAction } from 'vs/workbench/contrib/debug/browser/debugActions';
|
||||
import { StartDebugActionViewItem, FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -26,20 +26,21 @@ import { memoize } from 'vs/base/common/decorators';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||
import { ViewletPane } from 'vs/workbench/browser/parts/views/paneViewlet';
|
||||
import { IMenu, MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { TogglePanelAction } from 'vs/workbench/browser/panel';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { StartView } from 'vs/workbench/contrib/debug/browser/startView';
|
||||
|
||||
export class DebugViewlet extends ViewContainerViewlet {
|
||||
|
||||
private startDebugActionViewItem: StartDebugActionViewItem | undefined;
|
||||
private progressResolve: (() => void) | undefined;
|
||||
private breakpointView: ViewletPanel | undefined;
|
||||
private panelListeners = new Map<string, IDisposable>();
|
||||
private breakpointView: ViewletPane | undefined;
|
||||
private paneListeners = new Map<string, IDisposable>();
|
||||
private debugToolBarMenu: IMenu | undefined;
|
||||
private disposeOnTitleUpdate: IDisposable | undefined;
|
||||
|
||||
@@ -61,10 +62,16 @@ export class DebugViewlet extends ViewContainerViewlet {
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@INotificationService private readonly notificationService: INotificationService
|
||||
) {
|
||||
super(VIEWLET_ID, `${VIEWLET_ID}.state`, false, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
|
||||
super(VIEWLET_ID, `${VIEWLET_ID}.state`, true, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
|
||||
|
||||
this._register(this.debugService.onDidChangeState(state => this.onDebugServiceStateChange(state)));
|
||||
this._register(this.debugService.onDidNewSession(() => this.updateToolBar()));
|
||||
this._register(this.contextKeyService.onDidChangeContext(e => {
|
||||
if (e.affectsSome(new Set(CONTEXT_DEBUG_UX_KEY))) {
|
||||
this.updateTitleArea();
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateTitleArea()));
|
||||
this._register(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('debug.toolBarLocation')) {
|
||||
@@ -83,6 +90,8 @@ export class DebugViewlet extends ViewContainerViewlet {
|
||||
|
||||
if (this.startDebugActionViewItem) {
|
||||
this.startDebugActionViewItem.focus();
|
||||
} else {
|
||||
this.focusView(StartView.ID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +116,9 @@ export class DebugViewlet extends ViewContainerViewlet {
|
||||
}
|
||||
|
||||
getActions(): IAction[] {
|
||||
if (CONTEXT_DEBUG_UX.getValue(this.contextKeyService) === 'simple') {
|
||||
return [];
|
||||
}
|
||||
if (this.showInitialDebugActions) {
|
||||
return [this.startAction, this.configureAction, this.toggleReplAction];
|
||||
}
|
||||
@@ -181,32 +193,32 @@ export class DebugViewlet extends ViewContainerViewlet {
|
||||
}
|
||||
}
|
||||
|
||||
addPanels(panels: { panel: ViewletPanel, size: number, index?: number }[]): void {
|
||||
super.addPanels(panels);
|
||||
addPanes(panes: { pane: ViewletPane, size: number, index?: number }[]): void {
|
||||
super.addPanes(panes);
|
||||
|
||||
for (const { panel } of panels) {
|
||||
for (const { pane: pane } of panes) {
|
||||
// attach event listener to
|
||||
if (panel.id === BREAKPOINTS_VIEW_ID) {
|
||||
this.breakpointView = panel;
|
||||
if (pane.id === BREAKPOINTS_VIEW_ID) {
|
||||
this.breakpointView = pane;
|
||||
this.updateBreakpointsMaxSize();
|
||||
} else {
|
||||
this.panelListeners.set(panel.id, panel.onDidChange(() => this.updateBreakpointsMaxSize()));
|
||||
this.paneListeners.set(pane.id, pane.onDidChange(() => this.updateBreakpointsMaxSize()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removePanels(panels: ViewletPanel[]): void {
|
||||
super.removePanels(panels);
|
||||
for (const panel of panels) {
|
||||
dispose(this.panelListeners.get(panel.id));
|
||||
this.panelListeners.delete(panel.id);
|
||||
removePanes(panes: ViewletPane[]): void {
|
||||
super.removePanes(panes);
|
||||
for (const pane of panes) {
|
||||
dispose(this.paneListeners.get(pane.id));
|
||||
this.paneListeners.delete(pane.id);
|
||||
}
|
||||
}
|
||||
|
||||
private updateBreakpointsMaxSize(): void {
|
||||
if (this.breakpointView) {
|
||||
// We need to update the breakpoints view since all other views are collapsed #25384
|
||||
const allOtherCollapsed = this.panels.every(view => !view.isExpanded() || view === this.breakpointView);
|
||||
const allOtherCollapsed = this.panes.every(view => !view.isExpanded() || view === this.breakpointView);
|
||||
this.breakpointView.maximumBodySize = allOtherCollapsed ? Number.POSITIVE_INFINITY : this.breakpointView.minimumBodySize;
|
||||
}
|
||||
}
|
||||
@@ -220,6 +232,6 @@ class ToggleReplAction extends TogglePanelAction {
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@IPanelService panelService: IPanelService
|
||||
) {
|
||||
super(id, label, REPL_ID, panelService, layoutService, 'debug-action toggle-repl');
|
||||
super(id, label, REPL_ID, panelService, layoutService, 'debug-action codicon-terminal');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { mapToSerializable } from 'vs/base/common/map';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IWorkspaceProvider, IWorkspace } from 'vs/workbench/services/host/browser/browserHostService';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient implements IExtensionHostDebugService {
|
||||
|
||||
@@ -23,7 +26,8 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i
|
||||
|
||||
constructor(
|
||||
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
@ILogService logService: ILogService
|
||||
) {
|
||||
const connection = remoteAgentService.getConnection();
|
||||
let channel: IChannel;
|
||||
@@ -32,7 +36,7 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i
|
||||
} else {
|
||||
channel = { call: async () => undefined, listen: () => Event.None } as any;
|
||||
// TODO@weinand TODO@isidorn fallback?
|
||||
console.warn('Extension Host Debugging not available due to missing connection.');
|
||||
logService.warn('Extension Host Debugging not available due to missing connection.');
|
||||
}
|
||||
|
||||
super(channel);
|
||||
@@ -41,14 +45,9 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i
|
||||
this.workspaceProvider = environmentService.options.workspaceProvider;
|
||||
} else {
|
||||
this.workspaceProvider = { open: async () => undefined, workspace: undefined };
|
||||
console.warn('Extension Host Debugging not available due to missing workspace provider.');
|
||||
logService.warn('Extension Host Debugging not available due to missing workspace provider.');
|
||||
}
|
||||
|
||||
this.registerListeners(environmentService);
|
||||
}
|
||||
|
||||
private registerListeners(environmentService: IWorkbenchEnvironmentService): void {
|
||||
|
||||
// Reload window on reload request
|
||||
this._register(this.onReload(event => {
|
||||
if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) {
|
||||
@@ -64,7 +63,8 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i
|
||||
}));
|
||||
}
|
||||
|
||||
async openExtensionDevelopmentHostWindow(args: string[]): Promise<void> {
|
||||
openExtensionDevelopmentHostWindow(args: string[], env: IProcessEnvironment): Promise<void> {
|
||||
|
||||
if (!this.workspaceProvider.payload) {
|
||||
// TODO@Ben remove me once environment is adopted
|
||||
return this.openExtensionDevelopmentHostWindowLegacy(args);
|
||||
@@ -75,16 +75,31 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i
|
||||
const folderUriArg = this.findArgument('folder-uri', args);
|
||||
if (folderUriArg) {
|
||||
debugWorkspace = { folderUri: URI.parse(folderUriArg) };
|
||||
} else {
|
||||
const fileUriArg = this.findArgument('file-uri', args);
|
||||
if (fileUriArg && hasWorkspaceFileExtension(fileUriArg)) {
|
||||
debugWorkspace = { workspaceUri: URI.parse(fileUriArg) };
|
||||
}
|
||||
}
|
||||
|
||||
// Add environment parameters required for debug to work
|
||||
const environment = new Map<string, string>();
|
||||
|
||||
const fileUriArg = this.findArgument('file-uri', args);
|
||||
if (fileUriArg && !hasWorkspaceFileExtension(fileUriArg)) {
|
||||
environment.set('openFile', fileUriArg);
|
||||
}
|
||||
|
||||
const extensionDevelopmentPath = this.findArgument('extensionDevelopmentPath', args);
|
||||
if (extensionDevelopmentPath) {
|
||||
environment.set('extensionDevelopmentPath', extensionDevelopmentPath);
|
||||
}
|
||||
|
||||
const extensionTestsPath = this.findArgument('extensionTestsPath', args);
|
||||
if (extensionTestsPath) {
|
||||
environment.set('extensionTestsPath', extensionTestsPath);
|
||||
}
|
||||
|
||||
const debugId = this.findArgument('debugId', args);
|
||||
if (debugId) {
|
||||
environment.set('debugId', debugId);
|
||||
@@ -96,13 +111,13 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i
|
||||
}
|
||||
|
||||
// Open debug window as new window. Pass ParsedArgs over.
|
||||
this.workspaceProvider.open(debugWorkspace, {
|
||||
return this.workspaceProvider.open(debugWorkspace, {
|
||||
reuse: false, // debugging always requires a new window
|
||||
payload: mapToSerializable(environment) // mandatory properties to enable debugging
|
||||
});
|
||||
}
|
||||
|
||||
private async openExtensionDevelopmentHostWindowLegacy(args: string[]): Promise<void> {
|
||||
private openExtensionDevelopmentHostWindowLegacy(args: string[]): Promise<void> {
|
||||
// we pass the "args" as query parameters of the URL
|
||||
|
||||
let newAddress = `${document.location.origin}${document.location.pathname}?`;
|
||||
@@ -142,6 +157,11 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i
|
||||
addQueryParameter('extensionDevelopmentPath', ep);
|
||||
}
|
||||
|
||||
const etp = findArgument('extensionTestsPath');
|
||||
if (etp) {
|
||||
addQueryParameter('extensionTestsPath', etp);
|
||||
}
|
||||
|
||||
const di = findArgument('debugId');
|
||||
if (di) {
|
||||
addQueryParameter('debugId', di);
|
||||
|
||||
@@ -12,6 +12,7 @@ import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
const CONTROL_CODES = '\\u0000-\\u0020\\u007f-\\u009f';
|
||||
const WEB_LINK_REGEX = new RegExp('(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}:\\/\\/|data:|www\\.)[^\\s' + CONTROL_CODES + '"]{2,}[^\\s' + CONTROL_CODES + '"\')}\\],:;.!?]', 'ug');
|
||||
@@ -37,7 +38,8 @@ export class LinkDetector {
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IOpenerService private readonly openerService: IOpenerService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
// noop
|
||||
}
|
||||
@@ -96,7 +98,7 @@ export class LinkDetector {
|
||||
private createWebLink(url: string): Node {
|
||||
const link = this.createLink(url);
|
||||
const uri = URI.parse(url);
|
||||
this.decorateLink(link, () => this.openerService.open(uri));
|
||||
this.decorateLink(link, () => this.openerService.open(uri, { allowTunneling: !!this.workbenchEnvironmentService.configuration.remoteAuthority }));
|
||||
return link;
|
||||
}
|
||||
|
||||
@@ -142,7 +144,7 @@ export class LinkDetector {
|
||||
private decorateLink(link: HTMLElement, onclick: () => void) {
|
||||
link.classList.add('link');
|
||||
link.title = platform.isMacintosh ? nls.localize('fileLinkMac', "Cmd + click to follow link") : nls.localize('fileLink', "Ctrl + click to follow link");
|
||||
link.onmousemove = (event) => link.classList.toggle('pointer', platform.isMacintosh ? event.metaKey : event.ctrlKey);
|
||||
link.onmousemove = (event) => { link.classList.toggle('pointer', platform.isMacintosh ? event.metaKey : event.ctrlKey); };
|
||||
link.onmouseleave = () => link.classList.remove('pointer');
|
||||
link.onclick = (event) => {
|
||||
const selection = window.getSelection();
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { normalize, isAbsolute, posix } from 'vs/base/common/path';
|
||||
import { IViewletPanelOptions, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||
import { IViewletPaneOptions, ViewletPane } from 'vs/workbench/browser/parts/views/paneViewlet';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -34,6 +34,7 @@ import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { createMatches, FuzzyScore } from 'vs/base/common/filters';
|
||||
import { DebugContentProvider } from 'vs/workbench/contrib/debug/common/debugContentProvider';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
|
||||
const SMART = true;
|
||||
|
||||
@@ -111,7 +112,11 @@ class BaseTreeItem {
|
||||
// a dynamic ID based on the parent chain; required for reparenting (see #55448)
|
||||
getId(): string {
|
||||
const parent = this.getParent();
|
||||
return parent ? `${parent.getId()}/${this._label}` : this._label;
|
||||
return parent ? `${parent.getId()}/${this.getInternalId()}` : this.getInternalId();
|
||||
}
|
||||
|
||||
getInternalId(): string {
|
||||
return this._label;
|
||||
}
|
||||
|
||||
// skips intermediate single-child nodes
|
||||
@@ -254,6 +259,10 @@ class SessionTreeItem extends BaseTreeItem {
|
||||
this._session = session;
|
||||
}
|
||||
|
||||
getInternalId(): string {
|
||||
return this._session.getId();
|
||||
}
|
||||
|
||||
getSession(): IDebugSession {
|
||||
return this._session;
|
||||
}
|
||||
@@ -379,7 +388,7 @@ class SessionTreeItem extends BaseTreeItem {
|
||||
}
|
||||
}
|
||||
|
||||
export class LoadedScriptsView extends ViewletPanel {
|
||||
export class LoadedScriptsView extends ViewletPane {
|
||||
|
||||
private treeContainer!: HTMLElement;
|
||||
private loadedScriptsItemType: IContextKey<string>;
|
||||
@@ -402,7 +411,7 @@ export class LoadedScriptsView extends ViewletPanel {
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
@ILabelService private readonly labelService: ILabelService
|
||||
) {
|
||||
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('loadedScriptsSection', "Loaded Scripts Section") }, keybindingService, contextMenuService, configurationService, contextKeyService);
|
||||
super({ ...(options as IViewletPaneOptions), ariaHeaderLabel: nls.localize('loadedScriptsSection', "Loaded Scripts Section") }, keybindingService, contextMenuService, configurationService, contextKeyService);
|
||||
this.loadedScriptsItemType = CONTEXT_LOADED_SCRIPTS_ITEM_TYPE.bindTo(contextKeyService);
|
||||
}
|
||||
|
||||
@@ -419,7 +428,7 @@ export class LoadedScriptsView extends ViewletPanel {
|
||||
this.treeLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility });
|
||||
this._register(this.treeLabels);
|
||||
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'LoadedScriptsView', this.treeContainer, new LoadedScriptsDelegate(),
|
||||
this.tree = this.instantiationService.createInstance<typeof WorkbenchAsyncDataTree, WorkbenchAsyncDataTree<LoadedScriptsItem, LoadedScriptsItem, FuzzyScore>>(WorkbenchAsyncDataTree, 'LoadedScriptsView', this.treeContainer, new LoadedScriptsDelegate(),
|
||||
[new LoadedScriptsRenderer(this.treeLabels)],
|
||||
new LoadedScriptsDataSource(),
|
||||
{
|
||||
@@ -432,6 +441,9 @@ export class LoadedScriptsView extends ViewletPanel {
|
||||
filter: this.filter,
|
||||
accessibilityProvider: new LoadedSciptsAccessibilityProvider(),
|
||||
ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'loadedScriptsAriaLabel' }, "Debug Loaded Scripts"),
|
||||
overrideStyles: {
|
||||
listBackground: SIDE_BAR_BACKGROUND
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 7V8H8V14H7V8H1V7H7V1H8V7H14Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 163 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 7V8H8V14H7V8H1V7H7V1H8V7H14Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 161 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 7V8H8V14H7V8H1V7H7V1H8V7H14Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 163 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 8C4 5.79086 5.79086 4 8 4C10.2091 4 12 5.79086 12 8C12 10.2091 10.2091 12 8 12C5.79086 12 4 10.2091 4 8ZM6 10L6 9L10 9L10 10L6 10ZM6 6L6 7L10 7L10 6L6 6Z" fill="#E51400"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 327 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.2376 8L9.9282 12H5.3094L3 8L5.3094 4H9.9282L12.2376 8Z" fill="#848484"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 189 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.487 8L9.55293 11.35H5.68468L3.75056 8L5.68468 4.65H9.55293L11.487 8Z" stroke="#848484" stroke-width="1.3"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 224 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.2376 8L9.9282 12H5.3094L3 8L5.3094 4H9.9282L12.2376 8Z" fill="#E51400"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 189 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 4C8.36719 4 8.72135 4.04818 9.0625 4.14453C9.40365 4.23828 9.72135 4.3724 10.0156 4.54688C10.3125 4.72135 10.582 4.93099 10.8242 5.17578C11.069 5.41797 11.2786 5.6875 11.4531 5.98438C11.6276 6.27865 11.7617 6.59635 11.8555 6.9375C11.9518 7.27865 12 7.63281 12 8C12 8.36719 11.9518 8.72135 11.8555 9.0625C11.7617 9.40365 11.6276 9.72266 11.4531 10.0195C11.2786 10.3138 11.069 10.5833 10.8242 10.8281C10.582 11.0703 10.3125 11.2786 10.0156 11.4531C9.72135 11.6276 9.40365 11.763 9.0625 11.8594C8.72135 11.9531 8.36719 12 8 12C7.63281 12 7.27865 11.9531 6.9375 11.8594C6.59635 11.763 6.27734 11.6276 5.98047 11.4531C5.6862 11.2786 5.41667 11.0703 5.17188 10.8281C4.92969 10.5833 4.72135 10.3138 4.54688 10.0195C4.3724 9.72266 4.23698 9.40365 4.14062 9.0625C4.04688 8.72135 4 8.36719 4 8C4 7.63281 4.04688 7.27865 4.14062 6.9375C4.23698 6.59635 4.3724 6.27865 4.54688 5.98438C4.72135 5.6875 4.92969 5.41797 5.17188 5.17578C5.41667 4.93099 5.6862 4.72135 5.98047 4.54688C6.27734 4.3724 6.59635 4.23828 6.9375 4.14453C7.27865 4.04818 7.63281 4 8 4Z" fill="#848484"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 4L12 10.9048H4L8 4Z" fill="#848484"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 153 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.923 10.375H5.07699L8 5.25973L10.923 10.375Z" stroke="#848484" stroke-width="1.25"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 200 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 4L12 10.9048H4L8 4Z" fill="#E51400"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 153 B |
@@ -1,5 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g opacity="0.5">
|
||||
<path d="M8 4C8.36719 4 8.72135 4.04818 9.0625 4.14453C9.40365 4.23828 9.72135 4.3724 10.0156 4.54688C10.3125 4.72135 10.582 4.93099 10.8242 5.17578C11.069 5.41797 11.2786 5.6875 11.4531 5.98438C11.6276 6.27865 11.7617 6.59635 11.8555 6.9375C11.9518 7.27865 12 7.63281 12 8C12 8.36719 11.9518 8.72135 11.8555 9.0625C11.7617 9.40365 11.6276 9.72266 11.4531 10.0195C11.2786 10.3138 11.069 10.5833 10.8242 10.8281C10.582 11.0703 10.3125 11.2786 10.0156 11.4531C9.72135 11.6276 9.40365 11.763 9.0625 11.8594C8.72135 11.9531 8.36719 12 8 12C7.63281 12 7.27865 11.9531 6.9375 11.8594C6.59635 11.763 6.27734 11.6276 5.98047 11.4531C5.6862 11.2786 5.41667 11.0703 5.17188 10.8281C4.92969 10.5833 4.72135 10.3138 4.54688 10.0195C4.3724 9.72266 4.23698 9.40365 4.14062 9.0625C4.04688 8.72135 4 8.36719 4 8C4 7.63281 4.04688 7.27865 4.14062 6.9375C4.23698 6.59635 4.3724 6.27865 4.54688 5.98438C4.72135 5.6875 4.92969 5.41797 5.17188 5.17578C5.41667 4.93099 5.6862 4.72135 5.98047 4.54688C6.27734 4.3724 6.59635 4.23828 6.9375 4.14453C7.27865 4.04818 7.63281 4 8 4Z" fill="#E51400"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 3L13 8L8 13L3 8L8 3Z" fill="#848484"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 154 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.02039 7.97961L8 3L12.9796 7.97961L8 12.9592L3.02039 7.97961ZM8 10.7696L10.79 7.97961L8 5.18956L5.20996 7.97961L8 10.7696Z" fill="#848484"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 295 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 3L13 8L8 13L3 8L8 3Z" fill="#E51400"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 154 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.3259 10.2223C11.7654 9.56448 12 8.79112 12 8C12.0001 7.47467 11.8968 6.95447 11.6958 6.4691C11.4948 5.98374 11.2002 5.54273 10.8287 5.17126C10.4573 4.7998 10.0163 4.50517 9.5309 4.3042C9.04553 4.10323 8.52533 3.99986 8 4C7.20888 4 6.43552 4.2346 5.77772 4.67412C5.11992 5.11365 4.60723 5.73836 4.30448 6.46927C4.00173 7.20017 3.92252 8.00444 4.07686 8.78036C4.2312 9.55628 4.61216 10.269 5.17157 10.8284C5.73098 11.3878 6.44372 11.7688 7.21964 11.9231C7.99556 12.0775 8.79983 11.9983 9.53073 11.6955C10.2616 11.3928 10.8864 10.8801 11.3259 10.2223ZM8.65 10H7.4V11H8.65V10ZM7.4 9V5H8.65V9H7.4Z" fill="#E51400"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 767 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 12C10.2091 12 12 10.2091 12 8C12 5.79086 10.2091 4 8 4C5.79086 4 4 5.79086 4 8C4 10.2091 5.79086 12 8 12ZM10.6093 8C10.6093 9.44108 9.44107 10.6093 8 10.6093C6.55893 10.6093 5.39071 9.44108 5.39071 8C5.39071 6.55893 6.55893 5.39071 8 5.39071C9.44107 5.39071 10.6093 6.55893 10.6093 8ZM8 5.24613C9.52092 5.24613 10.7539 6.47908 10.7539 8C10.7539 8 10.7539 8 10.7539 8C10.7539 6.47908 9.52092 5.24613 8 5.24613Z" fill="#848484"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 583 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 4C8.36719 4 8.72135 4.04818 9.0625 4.14453C9.40365 4.23828 9.72135 4.3724 10.0156 4.54688C10.3125 4.72135 10.582 4.93099 10.8242 5.17578C11.069 5.41797 11.2786 5.6875 11.4531 5.98438C11.6276 6.27865 11.7617 6.59635 11.8555 6.9375C11.9518 7.27865 12 7.63281 12 8C12 8.36719 11.9518 8.72135 11.8555 9.0625C11.7617 9.40365 11.6276 9.72266 11.4531 10.0195C11.2786 10.3138 11.069 10.5833 10.8242 10.8281C10.582 11.0703 10.3125 11.2786 10.0156 11.4531C9.72135 11.6276 9.40365 11.763 9.0625 11.8594C8.72135 11.9531 8.36719 12 8 12C7.63281 12 7.27865 11.9531 6.9375 11.8594C6.59635 11.763 6.27734 11.6276 5.98047 11.4531C5.6862 11.2786 5.41667 11.0703 5.17188 10.8281C4.92969 10.5833 4.72135 10.3138 4.54688 10.0195C4.3724 9.72266 4.23698 9.40365 4.14062 9.0625C4.04688 8.72135 4 8.36719 4 8C4 7.63281 4.04688 7.27865 4.14062 6.9375C4.23698 6.59635 4.3724 6.27865 4.54688 5.98438C4.72135 5.6875 4.92969 5.41797 5.17188 5.17578C5.41667 4.93099 5.6862 4.72135 5.98047 4.54688C6.27734 4.3724 6.59635 4.23828 6.9375 4.14453C7.27865 4.04818 7.63281 4 8 4Z" fill="#E51400"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -16,7 +16,16 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .breakpoint-select-container .monaco-select-box {
|
||||
min-width: 100px;
|
||||
min-height: 18px;
|
||||
padding: 2px 20px 2px 8px;
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .breakpoint-select-container:after {
|
||||
right: 14px;
|
||||
}
|
||||
|
||||
.monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .inputContainer {
|
||||
flex: 1;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.62132 8.0858L7.91421 7.37869L6.5 8.7929L5.08579 7.37869L4.37868 8.0858L5.79289 9.50001L4.37868 10.9142L5.08579 11.6213L6.5 10.2071L7.91421 11.6213L8.62132 10.9142L7.20711 9.50001L8.62132 8.0858Z" fill="#C5C5C5"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 3L6 2H13L14 3V10L13 11H11V13L10 14H3L2 13V6L3 5H5V3ZM6 5H10L11 6V10H13V3H6V5ZM10 6H3V13H10V6Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 532 B |
@@ -1,4 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.62132 8.0858L7.91421 7.37869L6.5 8.7929L5.08579 7.37869L4.37868 8.0858L5.79289 9.50001L4.37868 10.9142L5.08579 11.6213L6.5 10.2071L7.91421 11.6213L8.62132 10.9142L7.20711 9.50001L8.62132 8.0858Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 3L6 2H13L14 3V10L13 11H11V13L10 14H3L2 13V6L3 5H5V3ZM6 5H10L11 6V10H13V3H6V5ZM10 6H3V13H10V6Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 528 B |
@@ -1,4 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.62132 8.0858L7.91421 7.37869L6.5 8.7929L5.08579 7.37869L4.37868 8.0858L5.79289 9.50001L4.37868 10.9142L5.08579 11.6213L6.5 10.2071L7.91421 11.6213L8.62132 10.9142L7.20711 9.50001L8.62132 8.0858Z" fill="#424242"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 3L6 2H13L14 3V10L13 11H11V13L10 14H3L2 13V6L3 5H5V3ZM6 5H10L11 6V10H13V3H6V5ZM10 6H3V13H10V6Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 532 B |
|
Before Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 9.9 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 1H15V15H1V1ZM2 14H14V2H2V14ZM4.00008 5.70709L4.70718 4.99999L8.24272 8.53552L7.53561 9.24263L7.53558 9.2426L4.70711 12.0711L4 11.364L6.82848 8.53549L4.00008 5.70709Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 339 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 1H15V15H1V1ZM2 14H14V2H2V14ZM4.00008 5.70709L4.70718 4.99999L8.24272 8.53552L7.53561 9.24263L7.53558 9.2426L4.70711 12.0711L4 11.364L6.82848 8.53549L4.00008 5.70709Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 337 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 1H15V15H1V1ZM2 14H14V2H2V14ZM4.00008 5.70709L4.70718 4.99999L8.24272 8.53552L7.53561 9.24263L7.53558 9.2426L4.70711 12.0711L4 11.364L6.82848 8.53549L4.00008 5.70709Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 339 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.5 2H4V2.24001L4 14L2.5 14L2.5 2ZM6 2.18094V14L15 8.06218L6 2.18094ZM12.3148 8.06218L7.50024 5L7.50024 11.1809L12.3148 8.06218Z" fill="#75BEFF"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 300 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.5 2H4V2.24001L4 14L2.5 14L2.5 2ZM6 2.18094V14L15 8.06218L6 2.18094ZM12.3148 8.06218L7.50024 5L7.50024 11.1809L12.3148 8.06218Z" fill="#75BEFF"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 300 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.5 2H4V2.24001L4 14L2.5 14L2.5 2ZM6 2.18094V14L15 8.06218L6 2.18094ZM12.3148 8.06218L7.50024 5L7.50024 11.1809L12.3148 8.06218Z" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 300 B |
@@ -1,4 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 8C10 8.39556 9.8827 8.78224 9.66294 9.11114C9.44318 9.44004 9.13082 9.69638 8.76537 9.84776C8.39992 9.99913 7.99778 10.0387 7.60982 9.96157C7.22186 9.8844 6.86549 9.69392 6.58579 9.41421C6.30608 9.13451 6.1156 8.77814 6.03843 8.39018C5.96126 8.00222 6.00087 7.60009 6.15224 7.23463C6.30362 6.86918 6.55996 6.55682 6.88886 6.33706C7.21776 6.1173 7.60444 6 8 6C8.53043 6 9.03914 6.21071 9.41421 6.58579C9.78929 6.96086 10 7.46957 10 8Z" fill="#E51400"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 3.25L4.25 2H9.30677L10.2355 2.41331L14.4986 7.14518L14.5 8.81702L10.2368 13.5647L9.30677 13.9796H4.25L3 12.7296V3.25ZM4.25 12.7296V3.25H9.30677L13.5699 7.98187L9.30677 12.7296H4.25Z" fill="#FFCC00"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 820 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 3.25L4.25 2H9.30677L10.2355 2.41331L14.4986 7.14518L14.5 8.81702L10.2368 13.5647L9.30677 13.9796H4.25L3 12.7296V3.25ZM4.25 12.7296V3.25H9.30677L13.5699 7.98187L9.30677 12.7296H4.25Z" fill="#FFCC00"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 355 B |
@@ -1,5 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.46279 12.86L3.45815 12.79C3.45964 12.8134 3.46119 12.8367 3.46279 12.86Z" fill="white"/>
|
||||
<path d="M10.7275 13.5509L7.69304 10.501L8.70723 9.4868L11.9159 12.7117L15.0789 9.54875L16.0931 10.5629L13.0589 13.5972L16.0934 16.647L15.0792 17.6612L11.8705 14.4362L8.70748 17.5993L7.69329 16.5851L10.7275 13.5509Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.9329 5.00286V6H18.2784L21.1205 3.15788L22.1347 4.17207L19.4435 6.86321L19.476 6.94805C20.0424 8.42597 20.3614 10.094 20.3614 11.86C20.3614 12.1955 20.3499 12.5274 20.3274 12.8552L20.3222 12.93H23.8629V14.3643H20.142L20.1315 14.4217C19.8292 16.075 19.2409 17.5825 18.4398 18.851L18.3802 18.9454L21.8027 22.3852L20.7859 23.3968L17.512 20.1063L17.4131 20.2169C15.934 21.8712 14.0177 22.8629 11.93 22.8629C9.81001 22.8629 7.86653 21.8402 6.37842 20.1395L6.27988 20.0268L3.07125 23.2355L2.05706 22.2213L5.42258 18.8558L5.36431 18.7615C4.59172 17.5118 4.02373 16.0363 3.72847 14.4217L3.71797 14.3643H0V12.93H3.53777L3.53262 12.8552C3.51009 12.5274 3.49858 12.1955 3.49858 11.86C3.49858 10.117 3.80935 8.46951 4.36194 7.00599L4.39377 6.92168L1.63228 4.14621L2.64904 3.13457L5.50003 6H6.92715V5.00286C6.92715 2.23986 9.16701 0 11.93 0C14.693 0 16.9329 2.23986 16.9329 5.00286ZM8.36144 5.00286V6H15.4986V5.00286C15.4986 3.03199 13.9009 1.43429 11.93 1.43429C9.95914 1.43429 8.36144 3.03199 8.36144 5.00286ZM18.1609 7.52498L18.1267 7.43429H5.73328L5.69915 7.52498C5.21331 8.81605 4.93286 10.2859 4.93286 11.86C4.93286 14.6199 5.7951 17.061 7.11691 18.7793C8.43755 20.4962 10.1529 21.4286 11.93 21.4286C13.7072 21.4286 15.4225 20.4962 16.7431 18.7793C18.0649 17.061 18.9271 14.6199 18.9271 11.86C18.9271 10.2859 18.6467 8.81605 18.1609 7.52498Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -3,49 +3,43 @@
|
||||
* 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-activity-bar.svg') no-repeat 50% 50%;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame-column::before {
|
||||
background: url('current-arrow.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-breakpoint-hint {
|
||||
background: url('breakpoint-hint.svg') center center no-repeat;
|
||||
.codicon-debug-hint {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.debug-breakpoint-disabled,
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-disabled {
|
||||
background: url('breakpoint-disabled.svg') center center no-repeat;
|
||||
.codicon-debug-hint:not(*[class*='codicon-debug-breakpoint']) {
|
||||
opacity: .4 !important;
|
||||
}
|
||||
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-disabled:hover {
|
||||
background: url('breakpoint-hint.svg') center center no-repeat;
|
||||
.inline-breakpoint-widget.codicon {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* overlapped icons */
|
||||
.inline-breakpoint-widget.codicon-debug-breakpoint-stackframe-dot::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
display: table;
|
||||
}
|
||||
|
||||
.codicon-debug-breakpoint.codicon-debug-breakpoint-stackframe-focused::after {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.inline-breakpoint-widget.codicon-debug-breakpoint-stackframe-dot::after {
|
||||
content: "\eb8b";
|
||||
}
|
||||
|
||||
.codicon-debug-breakpoint.codicon-debug-breakpoint-stackframe-focused::after {
|
||||
content: "\eb8a";
|
||||
}
|
||||
|
||||
.monaco-editor .inline-breakpoint-widget.line-start {
|
||||
left: -0.45em !important;
|
||||
}
|
||||
|
||||
.debug-breakpoint-unverified,
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-unverified {
|
||||
background: url('breakpoint-unverified.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame {
|
||||
background: url('current-arrow.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-focused-stack-frame {
|
||||
background: url('stackframe-arrow.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-breakpoint,
|
||||
.monaco-editor .inline-breakpoint-widget {
|
||||
background: url('breakpoint.svg') center center no-repeat;
|
||||
left: -8px !important;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-breakpoint-placeholder::before,
|
||||
@@ -58,6 +52,14 @@
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
/* Do not show call stack decoration when we plan to show breakpoint and top stack frame in one decoration */
|
||||
.monaco-editor .debug-breakpoint-placeholder ~ .debug-top-stack-frame-column::before {
|
||||
width: 0em;
|
||||
content: "";
|
||||
margin-right: 0px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame-column::before {
|
||||
height: 1.3em;
|
||||
}
|
||||
@@ -66,68 +68,6 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.debug-function-breakpoint {
|
||||
background: url('breakpoint-function.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-function-breakpoint-unverified {
|
||||
background: url('breakpoint-function-unverified.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-function-breakpoint-disabled {
|
||||
background: url('breakpoint-function-disabled.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-data-breakpoint {
|
||||
background: url('breakpoint-data.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-data-breakpoint-unverified {
|
||||
background: url('breakpoint-data-unverified.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-data-breakpoint-disabled {
|
||||
background: url('breakpoint-data-disabled.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-breakpoint-conditional,
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-conditional {
|
||||
background: url('breakpoint-conditional.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-breakpoint-log,
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log {
|
||||
background: url('breakpoint-log.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-breakpoint-log-disabled,
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log-disabled {
|
||||
background: url('breakpoint-log-disabled.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-breakpoint-log-unverified,
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-log-unverified {
|
||||
background: url('breakpoint-log-unverified.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.debug-breakpoint-unsupported,
|
||||
.monaco-editor .inline-breakpoint-widget.debug-breakpoint-unsupported {
|
||||
background: url('breakpoint-unsupported.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-top-stack-frame.debug-breakpoint,
|
||||
.monaco-editor .debug-top-stack-frame.debug-breakpoint-conditional,
|
||||
.monaco-editor .debug-top-stack-frame.debug-breakpoint-log,
|
||||
.monaco-editor .inline-breakpoint-widget.debug-top-stack-frame-column {
|
||||
background: url('current-and-breakpoint.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .debug-focused-stack-frame.debug-breakpoint,
|
||||
.monaco-editor .debug-focused-stack-frame.debug-breakpoint-conditional,
|
||||
.monaco-editor .debug-focused-stack-frame.debug-breakpoint-log {
|
||||
background: url('stackframe-and-breakpoint.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
/* Error editor */
|
||||
.debug-error-editor:focus {
|
||||
outline: none !important;
|
||||
|
||||