Merge from vscode 8e0f348413f4f616c23a88ae30030efa85811973 (#6381)

* Merge from vscode 8e0f348413f4f616c23a88ae30030efa85811973

* disable strict null check
This commit is contained in:
Anthony Dresser
2019-07-15 22:35:46 -07:00
committed by GitHub
parent f720ec642f
commit 0b7e7ddbf9
2406 changed files with 59140 additions and 35464 deletions

View File

@@ -16,8 +16,6 @@ const AUTO_SAVE_AFTER_DELAY_DISABLED_TIME = CONTENT_CHANGE_EVENT_BUFFER_DELAY +
export class BackupModelTracker extends Disposable implements IWorkbenchContribution {
_serviceBrand: any;
private configuredAutoSaveAfterDelay: boolean;
constructor(

View File

@@ -33,6 +33,7 @@ import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/action
import { ILabelService } from 'vs/platform/label/common/label';
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';
const enum State {
Loading = 'loading',
@@ -117,7 +118,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
this.create();
this._peekViewService.addExclusiveWidget(editor, this);
this._applyTheme(themeService.getTheme());
themeService.onThemeChange(this._applyTheme, this, this._disposables);
this._disposables.add(themeService.onThemeChange(this._applyTheme, this));
}
dispose(): void {
@@ -230,18 +231,18 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
}
}, Sizing.Distribute);
this._splitView.onDidSashChange(() => {
this._disposables.add(this._splitView.onDidSashChange(() => {
if (this._dim.width) {
this._layoutInfo.ratio = this._splitView.getViewSize(0) / this._dim.width;
}
}, undefined, this._disposables);
}));
// session state
let localDispose: IDisposable[] = [];
this._disposables.push({ dispose() { dispose(localDispose); } });
this._disposables.add({ dispose() { dispose(localDispose); } });
// update editor
this._tree.onDidChangeFocus(e => {
this._disposables.add(this._tree.onDidChangeFocus(e => {
const [element] = e.elements;
if (element && isNonEmptyArray(element.locations)) {
@@ -287,9 +288,9 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
}
this.setMetaTitle(localize('meta', " {0}", names.join(' → ')));
}
}, undefined, this._disposables);
}));
this._editor.onMouseDown(e => {
this._disposables.add(this._editor.onMouseDown(e => {
const { event, target } = e;
if (event.detail !== 2) {
return;
@@ -304,9 +305,13 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
options: { selection: target.range! }
});
}, undefined, this._disposables);
}));
this._disposables.add(this._tree.onMouseDblClick(e => {
if (e.target === TreeMouseEventTarget.Twistie) {
return;
}
this._tree.onMouseDblClick(e => {
if (e.element && isNonEmptyArray(e.element.locations)) {
this.dispose();
this._editorService.openEditor({
@@ -314,9 +319,9 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
options: { selection: e.element.locations[0].range }
});
}
}, undefined, this._disposables);
}));
this._tree.onDidChangeSelection(e => {
this._disposables.add(this._tree.onDidChangeSelection(e => {
const [element] = e.elements;
// don't close on click
if (element && isNonEmptyArray(element.locations) && e.browserEvent instanceof KeyboardEvent) {
@@ -326,7 +331,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
options: { selection: element.locations[0].range }
});
}
}, undefined, this._disposables);
}));
}
showLoading(): void {
@@ -380,7 +385,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
}
};
this._changeDirectionAction = new ChangeHierarchyDirectionAction(this._direction, changeDirection);
this._disposables.push(this._changeDirectionAction);
this._disposables.add(this._changeDirectionAction);
this._actionbarWidget.push(this._changeDirectionAction, { icon: true, label: false });
}
}

View File

@@ -30,7 +30,7 @@ export interface CallHierarchyProvider {
provideCallHierarchyItem(
document: ITextModel,
postion: IPosition,
position: IPosition,
token: CancellationToken
): ProviderResult<CallHierarchyItem>;

View File

@@ -190,6 +190,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 \'code\' command in PATH', category);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(UninstallAction, UninstallAction.ID, UninstallAction.LABEL), 'Shell Command: Uninstall \'code\' command from PATH', category);
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);
}

View File

@@ -27,7 +27,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { contrastBorder, editorWidgetBackground, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
import { contrastBorder, editorWidgetBackground, widgetShadow, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
@@ -321,6 +321,11 @@ registerThemingParticipant((theme, collector) => {
collector.addRule(`.monaco-editor .accessibilityHelpWidget { background-color: ${widgetBackground}; }`);
}
const widgetForeground = theme.getColor(editorWidgetForeground);
if (widgetBackground) {
collector.addRule(`.monaco-editor .accessibilityHelpWidget { color: ${widgetForeground}; }`);
}
const widgetShadowColor = theme.getColor(widgetShadow);
if (widgetShadowColor) {
collector.addRule(`.monaco-editor .accessibilityHelpWidget { box-shadow: 0 2px 8px ${widgetShadowColor}; }`);

View File

@@ -9,6 +9,10 @@ import { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IUntitledResourceInput } 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';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { Action } from 'vs/base/common/actions';
class InspectKeyMap extends EditorAction {
@@ -30,3 +34,24 @@ class InspectKeyMap extends EditorAction {
}
registerEditorAction(InspectKeyMap);
class InspectKeyMapJSON extends Action {
public static readonly ID = 'workbench.action.inspectKeyMappingsJSON';
public static readonly LABEL = nls.localize('workbench.action.inspectKeyMapJSON', "Inspect Key Mappings (JSON)");
constructor(
id: string,
label: string,
@IKeybindingService private readonly _keybindingService: IKeybindingService,
@IEditorService private readonly _editorService: IEditorService
) {
super(id, label);
}
public run(): Promise<any> {
return this._editorService.openEditor({ contents: this._keybindingService._dumpDebugInfoJSON(), options: { pinned: true } } as IUntitledResourceInput);
}
}
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"));

View File

@@ -9,7 +9,7 @@ import { Widget } from 'vs/base/browser/ui/widget';
import { Color } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IDisposable } from 'vs/base/common/lifecycle';
import { mixin } from 'vs/base/common/objects';
import { isMacintosh } from 'vs/base/common/platform';
import { URI as uri } from 'vs/base/common/uri';
@@ -103,7 +103,6 @@ export class SuggestEnabledInput extends Widget implements IThemable {
private _onInputDidChange = new Emitter<string | undefined>();
readonly onInputDidChange: Event<string | undefined> = this._onInputDidChange.event;
private disposables: IDisposable[] = [];
private readonly inputWidget: CodeEditorWidget;
private readonly inputModel: ITextModel;
private stylingContainer: HTMLDivElement;
@@ -134,31 +133,31 @@ export class SuggestEnabledInput extends Widget implements IThemable {
contributions: [SuggestController, SnippetController2, ContextMenuController, MenuPreventer, SelectionClipboard],
isSimpleWidget: true,
});
this.disposables.push(this.inputWidget);
this._register(this.inputWidget);
let scopeHandle = uri.parse(resourceHandle);
this.inputModel = modelService.createModel('', null, scopeHandle, true);
this.inputWidget.setModel(this.inputModel);
this.disposables.push(this.inputWidget.onDidPaste(() => this.setValue(this.getValue()))); // setter cleanses
this._register(this.inputWidget.onDidPaste(() => this.setValue(this.getValue()))); // setter cleanses
this.disposables.push((this.inputWidget.onDidFocusEditorText(() => {
this._register((this.inputWidget.onDidFocusEditorText(() => {
if (options.focusContextKey) { options.focusContextKey.set(true); }
addClass(this.stylingContainer, 'synthetic-focus');
})));
this.disposables.push((this.inputWidget.onDidBlurEditorText(() => {
this._register((this.inputWidget.onDidBlurEditorText(() => {
if (options.focusContextKey) { options.focusContextKey.set(false); }
removeClass(this.stylingContainer, 'synthetic-focus');
})));
const onKeyDownMonaco = Event.chain(this.inputWidget.onKeyDown);
onKeyDownMonaco.filter(e => e.keyCode === KeyCode.Enter).on(e => { e.preventDefault(); this._onEnter.fire(); }, this, this.disposables);
onKeyDownMonaco.filter(e => e.keyCode === KeyCode.DownArrow && (isMacintosh ? e.metaKey : e.ctrlKey)).on(() => this._onShouldFocusResults.fire(), this, this.disposables);
this._register(onKeyDownMonaco.filter(e => e.keyCode === KeyCode.Enter).on(e => { e.preventDefault(); this._onEnter.fire(); }, this));
this._register(onKeyDownMonaco.filter(e => e.keyCode === KeyCode.DownArrow && (isMacintosh ? e.metaKey : e.ctrlKey)).on(() => this._onShouldFocusResults.fire(), this));
let preexistingContent = this.getValue();
const inputWidgetModel = this.inputWidget.getModel();
if (inputWidgetModel) {
this.disposables.push(inputWidgetModel.onDidChangeContent(() => {
this._register(inputWidgetModel.onDidChangeContent(() => {
let content = this.getValue();
this.placeholderText.style.visibility = content ? 'hidden' : 'visible';
if (preexistingContent.trim() === content.trim()) { return; }
@@ -175,7 +174,7 @@ export class SuggestEnabledInput extends Widget implements IThemable {
this.setValue(options.value || '');
this.disposables.push(modes.CompletionProviderRegistry.register({ scheme: scopeHandle.scheme, pattern: '**/' + scopeHandle.path, hasAccessToAllModels: true }, {
this._register(modes.CompletionProviderRegistry.register({ scheme: scopeHandle.scheme, pattern: '**/' + scopeHandle.path, hasAccessToAllModels: true }, {
triggerCharacters: validatedSuggestProvider.triggerCharacters,
provideCompletionItems: (model: ITextModel, position: Position, _context: modes.CompletionContext) => {
let query = model.getValue();
@@ -249,11 +248,6 @@ export class SuggestEnabledInput extends Widget implements IThemable {
private selectAll(): void {
this.inputWidget.setSelection(new Range(1, 1, 1, this.getValue().length + 1));
}
dispose(): void {
this.disposables = dispose(this.disposables);
super.dispose();
}
}
// Override styles in selections.ts

View File

@@ -13,7 +13,7 @@ import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/wor
export class ToggleMinimapAction extends Action {
public static readonly ID = 'editor.action.toggleMinimap';
public static readonly LABEL = nls.localize('toggleMinimap', "View: Toggle Minimap");
public static readonly LABEL = nls.localize('toggleMinimap', "Toggle Minimap");
constructor(
id: string,
@@ -30,16 +30,16 @@ export class ToggleMinimapAction extends Action {
}
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMinimapAction, ToggleMinimapAction.ID, ToggleMinimapAction.LABEL), 'View: Toggle Minimap');
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMinimapAction, ToggleMinimapAction.ID, ToggleMinimapAction.LABEL), 'View: Toggle Minimap', nls.localize('view', "View"));
// {{SQL CARBON EDIT}} - Disable unused menu item
// MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
// group: '5_editor',
// command: {
// id: ToggleMinimapAction.ID,
// title: nls.localize({ key: 'miToggleMinimap', comment: ['&& denotes a mnemonic'] }, "Toggle &&Minimap"),
// toggled: ContextKeyExpr.equals('config.editor.minimap.enabled', true)
// },
// order: 2
// });
// {{SQL CARBON EDIT}} - End
/* {{SQL CARBON EDIT}} - Disable unused menu item
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
group: '5_editor',
command: {
id: ToggleMinimapAction.ID,
title: nls.localize({ key: 'miShowMinimap', comment: ['&& denotes a mnemonic'] }, "Show &&Minimap"),
toggled: ContextKeyExpr.equals('config.editor.minimap.enabled', true)
},
order: 2
});
*/

View File

@@ -14,7 +14,7 @@ import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/wor
export class ToggleRenderControlCharacterAction extends Action {
public static readonly ID = 'editor.action.toggleRenderControlCharacter';
public static readonly LABEL = nls.localize('toggleRenderControlCharacters', "View: Toggle Control Characters");
public static readonly LABEL = nls.localize('toggleRenderControlCharacters', "Toggle Control Characters");
constructor(
id: string,
@@ -31,16 +31,16 @@ 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');
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRenderControlCharacterAction, ToggleRenderControlCharacterAction.ID, ToggleRenderControlCharacterAction.LABEL), 'View: Toggle Control Characters', nls.localize('view', "View"));
// {{SQL CARBON EDIT}} - Disable unused menu item
// MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
// group: '5_editor',
// command: {
// id: ToggleRenderControlCharacterAction.ID,
// title: nls.localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Toggle &&Control Characters"),
// toggled: ContextKeyExpr.equals('config.editor.renderControlCharacters', true)
// },
// order: 4
// });
// {{SQL CARBON EDIT}} - End
/* {{SQL CARBON EDIT}} - Disable unused menu item
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
group: '5_editor',
command: {
id: ToggleRenderControlCharacterAction.ID,
title: nls.localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Render &&Control Characters"),
toggled: ContextKeyExpr.equals('config.editor.renderControlCharacters', true)
},
order: 5
});
*/

View File

@@ -14,7 +14,7 @@ import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/wor
export class ToggleRenderWhitespaceAction extends Action {
public static readonly ID = 'editor.action.toggleRenderWhitespace';
public static readonly LABEL = nls.localize('toggleRenderWhitespace', "View: Toggle Render Whitespace");
public static readonly LABEL = nls.localize('toggleRenderWhitespace', "Toggle Render Whitespace");
constructor(
id: string,
@@ -39,16 +39,16 @@ 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');
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRenderWhitespaceAction, ToggleRenderWhitespaceAction.ID, ToggleRenderWhitespaceAction.LABEL), 'View: Toggle Render Whitespace', nls.localize('view', "View"));
// {{SQL CARBON EDIT}} - Disable unused menu item
// MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
// group: '5_editor',
// command: {
// id: ToggleRenderWhitespaceAction.ID,
// title: nls.localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "Toggle &&Render Whitespace"),
// toggled: ContextKeyExpr.notEquals('config.editor.renderWhitespace', 'none')
// },
// order: 3
// });
// {{SQL CARBON EDIT}} - End
/* {{SQL CARBON EDIT}} - Disable unused menu item
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
group: '5_editor',
command: {
id: ToggleRenderWhitespaceAction.ID,
title: nls.localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "&&Render Whitespace"),
toggled: ContextKeyExpr.notEquals('config.editor.renderWhitespace', 'none')
},
order: 4
});
*/

View File

@@ -1,70 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ITextModel } from 'vs/editor/common/model';
import { onUnexpectedExternalError } from 'vs/base/common/errors';
import { mergeSort } from 'vs/base/common/arrays';
import { Event } from 'vs/base/common/event';
import { CancellationToken } from 'vs/base/common/cancellation';
import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry';
import { ProviderResult } from 'vs/editor/common/modes';
import { IRange } from 'vs/editor/common/core/range';
export interface ICodeInsetSymbol {
id: string;
range: IRange;
height?: number;
}
export interface CodeInsetProvider {
onDidChange?: Event<this>;
provideCodeInsets(model: ITextModel, token: CancellationToken): ProviderResult<ICodeInsetSymbol[]>;
resolveCodeInset(model: ITextModel, codeInset: ICodeInsetSymbol, token: CancellationToken): ProviderResult<ICodeInsetSymbol>;
}
export const CodeInsetProviderRegistry = new LanguageFeatureRegistry<CodeInsetProvider>();
export interface ICodeInsetData {
symbol: ICodeInsetSymbol;
provider: CodeInsetProvider;
resolved?: boolean;
}
export function getCodeInsetData(model: ITextModel, token: CancellationToken): Promise<ICodeInsetData[]> {
const symbols: ICodeInsetData[] = [];
const providers = CodeInsetProviderRegistry.ordered(model);
const promises = providers.map(provider =>
Promise.resolve(provider.provideCodeInsets(model, token)).then(result => {
if (Array.isArray(result)) {
for (let symbol of result) {
symbols.push({ symbol, provider });
}
}
}).catch(onUnexpectedExternalError));
return Promise.all(promises).then(() => {
return mergeSort(symbols, (a, b) => {
// sort by lineNumber, provider-rank, and column
if (a.symbol.range.startLineNumber < b.symbol.range.startLineNumber) {
return -1;
} else if (a.symbol.range.startLineNumber > b.symbol.range.startLineNumber) {
return 1;
} else if (providers.indexOf(a.provider) < providers.indexOf(b.provider)) {
return -1;
} else if (providers.indexOf(a.provider) > providers.indexOf(b.provider)) {
return 1;
} else if (a.symbol.range.startColumn < b.symbol.range.startColumn) {
return -1;
} else if (a.symbol.range.startColumn > b.symbol.range.startColumn) {
return 1;
} else {
return 0;
}
});
});
}

View File

@@ -1,353 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CancelablePromise, createCancelablePromise, RunOnceScheduler } from 'vs/base/common/async';
import { onUnexpectedError } from 'vs/base/common/errors';
import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { StableEditorScrollState } from 'vs/editor/browser/core/editorState';
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { IModelDecorationsChangeAccessor } from 'vs/editor/common/model';
import { CodeInsetProviderRegistry, getCodeInsetData, ICodeInsetData } from '../common/codeInset';
import { CodeInsetWidget, CodeInsetHelper } from './codeInsetWidget';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
// import { localize } from 'vs/nls';
export class CodeInsetController implements editorCommon.IEditorContribution {
static get(editor: editorBrowser.ICodeEditor): CodeInsetController {
return editor.getContribution(CodeInsetController.ID);
}
private static readonly ID: string = 'css.editor.codeInset';
private _isEnabled: boolean;
private _globalToDispose: IDisposable[];
private _localToDispose: IDisposable[];
private _insetWidgets: CodeInsetWidget[];
private _pendingWebviews = new Map<string, (element: WebviewElement) => any>();
private _currentFindCodeInsetSymbolsPromise: CancelablePromise<ICodeInsetData[]> | null;
private _modelChangeCounter: number;
private _currentResolveCodeInsetSymbolsPromise: CancelablePromise<any> | null;
private _detectVisibleInsets: RunOnceScheduler;
constructor(
private _editor: editorBrowser.ICodeEditor,
@IConfigurationService private readonly _configService: IConfigurationService,
) {
this._isEnabled = this._configService.getValue<boolean>('editor.codeInsets');
this._globalToDispose = [];
this._localToDispose = [];
this._insetWidgets = [];
this._currentFindCodeInsetSymbolsPromise = null;
this._modelChangeCounter = 0;
this._globalToDispose.push(this._editor.onDidChangeModel(() => this._onModelChange()));
this._globalToDispose.push(this._editor.onDidChangeModelLanguage(() => this._onModelChange()));
this._globalToDispose.push(this._configService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('editor.codeInsets')) {
let prevIsEnabled = this._isEnabled;
this._isEnabled = this._configService.getValue<boolean>('editor.codeInsets');
if (prevIsEnabled !== this._isEnabled) {
this._onModelChange();
}
}
}));
this._globalToDispose.push(CodeInsetProviderRegistry.onDidChange(this._onModelChange, this));
this._onModelChange();
}
dispose(): void {
this._localDispose();
this._globalToDispose = dispose(this._globalToDispose);
}
acceptWebview(symbolId: string, webviewElement: WebviewElement): boolean {
const pendingWebview = this._pendingWebviews.get(symbolId);
if (pendingWebview) {
pendingWebview(webviewElement);
this._pendingWebviews.delete(symbolId);
return true;
}
return false;
}
private _localDispose(): void {
if (this._currentFindCodeInsetSymbolsPromise) {
this._currentFindCodeInsetSymbolsPromise.cancel();
this._currentFindCodeInsetSymbolsPromise = null;
this._modelChangeCounter++;
}
if (this._currentResolveCodeInsetSymbolsPromise) {
this._currentResolveCodeInsetSymbolsPromise.cancel();
this._currentResolveCodeInsetSymbolsPromise = null;
}
this._localToDispose = dispose(this._localToDispose);
}
getId(): string {
return CodeInsetController.ID;
}
private _onModelChange(): void {
this._localDispose();
const model = this._editor.getModel();
if (!model || !this._isEnabled || !CodeInsetProviderRegistry.has(model)) {
return;
}
for (const provider of CodeInsetProviderRegistry.all(model)) {
if (typeof provider.onDidChange === 'function') {
let registration = provider.onDidChange(() => scheduler.schedule());
this._localToDispose.push(registration);
}
}
this._detectVisibleInsets = new RunOnceScheduler(() => {
this._onViewportChanged();
}, 500);
const scheduler = new RunOnceScheduler(() => {
const counterValue = ++this._modelChangeCounter;
if (this._currentFindCodeInsetSymbolsPromise) {
this._currentFindCodeInsetSymbolsPromise.cancel();
}
this._currentFindCodeInsetSymbolsPromise = createCancelablePromise(token => getCodeInsetData(model, token));
this._currentFindCodeInsetSymbolsPromise.then(codeInsetData => {
if (counterValue === this._modelChangeCounter) { // only the last one wins
this._renderCodeInsetSymbols(codeInsetData);
this._detectVisibleInsets.schedule();
}
}, onUnexpectedError);
}, 250);
this._localToDispose.push(scheduler);
this._localToDispose.push(this._detectVisibleInsets);
this._localToDispose.push(this._editor.onDidChangeModelContent(() => {
this._editor.changeDecorations(changeAccessor => {
this._editor.changeViewZones(viewAccessor => {
let toDispose: CodeInsetWidget[] = [];
let lastInsetLineNumber: number = -1;
this._insetWidgets.forEach(inset => {
if (!inset.isValid() || lastInsetLineNumber === inset.getLineNumber()) {
// invalid -> Inset collapsed, attach range doesn't exist anymore
// line_number -> insets should never be on the same line
toDispose.push(inset);
}
else {
inset.reposition(viewAccessor);
lastInsetLineNumber = inset.getLineNumber();
}
});
let helper = new CodeInsetHelper();
toDispose.forEach((l) => {
l.dispose(helper, viewAccessor);
this._insetWidgets.splice(this._insetWidgets.indexOf(l), 1);
});
helper.commit(changeAccessor);
});
});
// Compute new `visible` code insets
this._detectVisibleInsets.schedule();
// Ask for all references again
scheduler.schedule();
}));
this._localToDispose.push(this._editor.onDidScrollChange(e => {
if (e.scrollTopChanged && this._insetWidgets.length > 0) {
this._detectVisibleInsets.schedule();
}
}));
this._localToDispose.push(this._editor.onDidLayoutChange(() => {
this._detectVisibleInsets.schedule();
}));
this._localToDispose.push(toDisposable(() => {
if (this._editor.getModel()) {
const scrollState = StableEditorScrollState.capture(this._editor);
this._editor.changeDecorations((changeAccessor) => {
this._editor.changeViewZones((accessor) => {
this._disposeAllInsets(changeAccessor, accessor);
});
});
scrollState.restore(this._editor);
} else {
// No accessors available
this._disposeAllInsets(null, null);
}
}));
scheduler.schedule();
}
private _disposeAllInsets(decChangeAccessor: IModelDecorationsChangeAccessor | null, viewZoneChangeAccessor: editorBrowser.IViewZoneChangeAccessor | null): void {
let helper = new CodeInsetHelper();
this._insetWidgets.forEach((Inset) => Inset.dispose(helper, viewZoneChangeAccessor));
if (decChangeAccessor) {
helper.commit(decChangeAccessor);
}
this._insetWidgets = [];
}
private _renderCodeInsetSymbols(symbols: ICodeInsetData[]): void {
if (!this._editor.hasModel()) {
return;
}
let maxLineNumber = this._editor.getModel().getLineCount();
let groups: ICodeInsetData[][] = [];
let lastGroup: ICodeInsetData[] | undefined;
for (let symbol of symbols) {
let line = symbol.symbol.range.startLineNumber;
if (line < 1 || line > maxLineNumber) {
// invalid code Inset
continue;
} else if (lastGroup && lastGroup[lastGroup.length - 1].symbol.range.startLineNumber === line) {
// on same line as previous
lastGroup.push(symbol);
} else {
// on later line as previous
lastGroup = [symbol];
groups.push(lastGroup);
}
}
const scrollState = StableEditorScrollState.capture(this._editor);
this._editor.changeDecorations(changeAccessor => {
this._editor.changeViewZones(accessor => {
let codeInsetIndex = 0, groupsIndex = 0, helper = new CodeInsetHelper();
while (groupsIndex < groups.length && codeInsetIndex < this._insetWidgets.length) {
let symbolsLineNumber = groups[groupsIndex][0].symbol.range.startLineNumber;
let codeInsetLineNumber = this._insetWidgets[codeInsetIndex].getLineNumber();
if (codeInsetLineNumber < symbolsLineNumber) {
this._insetWidgets[codeInsetIndex].dispose(helper, accessor);
this._insetWidgets.splice(codeInsetIndex, 1);
} else if (codeInsetLineNumber === symbolsLineNumber) {
this._insetWidgets[codeInsetIndex].updateCodeInsetSymbols(groups[groupsIndex], helper);
groupsIndex++;
codeInsetIndex++;
} else {
this._insetWidgets.splice(
codeInsetIndex,
0,
new CodeInsetWidget(groups[groupsIndex], this._editor, helper)
);
codeInsetIndex++;
groupsIndex++;
}
}
// Delete extra code insets
while (codeInsetIndex < this._insetWidgets.length) {
this._insetWidgets[codeInsetIndex].dispose(helper, accessor);
this._insetWidgets.splice(codeInsetIndex, 1);
}
// Create extra symbols
while (groupsIndex < groups.length) {
this._insetWidgets.push(new CodeInsetWidget(
groups[groupsIndex],
this._editor, helper
));
groupsIndex++;
}
helper.commit(changeAccessor);
});
});
scrollState.restore(this._editor);
}
private _onViewportChanged(): void {
if (this._currentResolveCodeInsetSymbolsPromise) {
this._currentResolveCodeInsetSymbolsPromise.cancel();
this._currentResolveCodeInsetSymbolsPromise = null;
}
const model = this._editor.getModel();
if (!model) {
return;
}
const allWidgetRequests: ICodeInsetData[][] = [];
const insetWidgets: CodeInsetWidget[] = [];
this._insetWidgets.forEach(inset => {
const widgetRequests = inset.computeIfNecessary(model);
if (widgetRequests) {
allWidgetRequests.push(widgetRequests);
insetWidgets.push(inset);
}
});
if (allWidgetRequests.length === 0) {
return;
}
this._currentResolveCodeInsetSymbolsPromise = createCancelablePromise(token => {
const allPromises = allWidgetRequests.map((widgetRequests, r) => {
const widgetPromises = widgetRequests.map(request => {
if (request.resolved) {
return Promise.resolve(undefined);
}
let a = new Promise(resolve => {
this._pendingWebviews.set(request.symbol.id, element => {
request.resolved = true;
insetWidgets[r].adoptWebview(element);
resolve();
});
});
let b = request.provider.resolveCodeInset(model, request.symbol, token);
return Promise.all([a, b]);
});
return Promise.all(widgetPromises);
});
return Promise.all(allPromises);
});
this._currentResolveCodeInsetSymbolsPromise.then(() => {
this._currentResolveCodeInsetSymbolsPromise = null;
}).catch(err => {
this._currentResolveCodeInsetSymbolsPromise = null;
onUnexpectedError(err);
});
}
}
registerEditorContribution(CodeInsetController);
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).registerConfiguration({
id: 'editor',
properties: {
// ['editor.codeInsets']: {
// description: localize('editor.codeInsets', "Enable/disable editor code insets"),
// type: 'boolean',
// default: false
// }
}
});

View File

@@ -1,8 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .code-inset {
z-index: 10;
}

View File

@@ -1,193 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./codeInsetWidget';
import { Range } from 'vs/editor/common/core/range';
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
import { ICodeInsetData } from '../common/codeInset';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { IModelDeltaDecoration, IModelDecorationsChangeAccessor, ITextModel } from 'vs/editor/common/model';
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
export interface IDecorationIdCallback {
(decorationId: string): void;
}
export class CodeInsetHelper {
private _removeDecorations: string[];
private _addDecorations: IModelDeltaDecoration[];
private _addDecorationsCallbacks: IDecorationIdCallback[];
constructor() {
this._removeDecorations = [];
this._addDecorations = [];
this._addDecorationsCallbacks = [];
}
addDecoration(decoration: IModelDeltaDecoration, callback: IDecorationIdCallback): void {
this._addDecorations.push(decoration);
this._addDecorationsCallbacks.push(callback);
}
removeDecoration(decorationId: string): void {
this._removeDecorations.push(decorationId);
}
commit(changeAccessor: IModelDecorationsChangeAccessor): void {
let resultingDecorations = changeAccessor.deltaDecorations(this._removeDecorations, this._addDecorations);
for (let i = 0, len = resultingDecorations.length; i < len; i++) {
this._addDecorationsCallbacks[i](resultingDecorations[i]);
}
}
}
export class CodeInsetWidget {
private readonly _editor: editorBrowser.ICodeEditor;
private _webview: WebviewElement;
private _viewZone: editorBrowser.IViewZone;
private _viewZoneId?: number = undefined;
private _decorationIds: string[];
private _data: ICodeInsetData[];
private _range: Range;
constructor(
data: ICodeInsetData[], // all the insets on the same line (often just one)
editor: editorBrowser.ICodeEditor,
helper: CodeInsetHelper
) {
this._editor = editor;
this._data = data;
this._decorationIds = new Array<string>(this._data.length);
this._data.forEach((codeInsetData, i) => {
helper.addDecoration({
range: codeInsetData.symbol.range,
options: ModelDecorationOptions.EMPTY
}, id => this._decorationIds[i] = id);
// the range contains all insets on this line
if (!this._range) {
this._range = Range.lift(codeInsetData.symbol.range);
} else {
this._range = Range.plusRange(this._range, codeInsetData.symbol.range);
}
});
}
public dispose(helper: CodeInsetHelper, viewZoneChangeAccessor: editorBrowser.IViewZoneChangeAccessor | null): void {
while (this._decorationIds.length) {
const decoration = this._decorationIds.pop();
if (decoration) {
helper.removeDecoration(decoration);
}
}
if (viewZoneChangeAccessor) {
if (typeof this._viewZoneId !== 'undefined') {
viewZoneChangeAccessor.removeZone(this._viewZoneId);
}
this._viewZone = undefined!;
}
if (this._webview) {
this._webview.dispose();
}
}
public isValid(): boolean {
return this._editor.hasModel() && this._decorationIds.some((id, i) => {
const range = this._editor.getModel()!.getDecorationRange(id);
const symbol = this._data[i].symbol;
return !!range && Range.isEmpty(symbol.range) === range.isEmpty();
});
}
public updateCodeInsetSymbols(data: ICodeInsetData[], helper: CodeInsetHelper): void {
while (this._decorationIds.length) {
const decoration = this._decorationIds.pop();
if (decoration) {
helper.removeDecoration(decoration);
}
}
this._data = data;
this._decorationIds = new Array<string>(this._data.length);
this._data.forEach((codeInsetData, i) => {
helper.addDecoration({
range: codeInsetData.symbol.range,
options: ModelDecorationOptions.EMPTY
}, id => this._decorationIds[i] = id);
});
}
public computeIfNecessary(model: ITextModel): ICodeInsetData[] {
// Read editor current state
for (let i = 0; i < this._decorationIds.length; i++) {
const range = model.getDecorationRange(this._decorationIds[i]);
if (range) {
this._data[i].symbol.range = range;
}
}
return this._data;
}
public getLineNumber(): number {
if (this._editor.hasModel()) {
const range = this._editor.getModel().getDecorationRange(this._decorationIds[0]);
if (range) {
return range.startLineNumber;
}
}
return -1;
}
public adoptWebview(webview: WebviewElement): void {
const lineNumber = this._range.endLineNumber;
this._editor.changeViewZones(accessor => {
if (this._viewZoneId) {
accessor.removeZone(this._viewZoneId);
this._webview.dispose();
}
const div = document.createElement('div');
div.className = 'code-inset';
webview.mountTo(div);
webview.onMessage((e: { type: string, payload: any }) => {
// The webview contents can use a "size-info" message to report its size.
if (e && e.type === 'size-info') {
const margin = e.payload.height > 0 ? 5 : 0;
this._viewZone.heightInPx = e.payload.height + margin;
this._editor.changeViewZones(accessor => {
if (this._viewZoneId) {
accessor.layoutZone(this._viewZoneId);
}
});
}
});
this._viewZone = {
afterLineNumber: lineNumber,
heightInPx: 50,
domNode: div
};
this._viewZoneId = accessor.addZone(this._viewZone);
this._webview = webview;
});
}
public reposition(viewZoneChangeAccessor: editorBrowser.IViewZoneChangeAccessor): void {
if (this.isValid() && this._editor.hasModel()) {
const range = this._editor.getModel().getDecorationRange(this._decorationIds[0]);
if (range) {
this._viewZone.afterLineNumber = range.endLineNumber;
}
if (this._viewZoneId) {
viewZoneChangeAccessor.layoutZone(this._viewZoneId);
}
}
}
}

View File

@@ -6,41 +6,57 @@
import * as DOM from 'vs/base/browser/dom';
import { Button } from 'vs/base/browser/ui/button/button';
import { IAction } from 'vs/base/common/actions';
import { Disposable, dispose } from 'vs/base/common/lifecycle';
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { IMenu } from 'vs/platform/actions/common/actions';
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
export class CommentFormActions extends Disposable {
export class CommentFormActions implements IDisposable {
private _buttonElements: HTMLElement[] = [];
private readonly _toDispose = new DisposableStore();
private _actions: IAction[];
constructor(
private container: HTMLElement,
private actionHandler: (action: IAction) => void,
private themeService: IThemeService
) {
super();
}
) { }
setActions(menu: IMenu) {
dispose(this._toDispose);
this._toDispose.clear();
this._buttonElements.forEach(b => DOM.removeNode(b));
const groups = menu.getActions({ shouldForwardArgs: true });
for (const group of groups) {
const [, actions] = group;
this._actions = actions;
actions.forEach(action => {
const button = new Button(this.container);
this._buttonElements.push(button.element);
this._toDispose.push(button);
this._toDispose.push(attachButtonStyler(button, this.themeService));
this._toDispose.push(button.onDidClick(() => this.actionHandler(action)));
this._toDispose.add(button);
this._toDispose.add(attachButtonStyler(button, this.themeService));
this._toDispose.add(button.onDidClick(() => this.actionHandler(action)));
button.enabled = action.enabled;
button.label = action.label;
});
}
}
triggerDefaultAction() {
if (this._actions.length) {
let lastAction = this._actions[0];
if (lastAction.enabled) {
this.actionHandler(lastAction);
}
}
}
dispose() {
this._toDispose.dispose();
}
}

View File

@@ -9,8 +9,8 @@ import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'
import { IAction } from 'vs/base/common/actions';
import { MainThreadCommentController } from 'vs/workbench/api/browser/mainThreadComments';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { Comment, CommentThread2 } from 'vs/editor/common/modes';
import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { Comment, CommentThread } from 'vs/editor/common/modes';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
export class CommentMenus implements IDisposable {
constructor(
@@ -24,11 +24,11 @@ export class CommentMenus implements IDisposable {
commentControllerKey.set(controller.contextValue);
}
getCommentThreadTitleActions(commentThread: CommentThread2, contextKeyService: IContextKeyService): IMenu {
getCommentThreadTitleActions(commentThread: CommentThread, contextKeyService: IContextKeyService): IMenu {
return this.getMenu(MenuId.CommentThreadTitle, contextKeyService);
}
getCommentThreadActions(commentThread: CommentThread2, contextKeyService: IContextKeyService): IMenu {
getCommentThreadActions(commentThread: CommentThread, contextKeyService: IContextKeyService): IMenu {
return this.getMenu(MenuId.CommentThreadActions, contextKeyService);
}
@@ -47,7 +47,7 @@ export class CommentMenus implements IDisposable {
const secondary: IAction[] = [];
const result = { primary, secondary };
fillInContextMenuActions(menu, { shouldForwardArgs: true }, result, this.contextMenuService, g => true);
createAndFillInContextMenuActions(menu, { shouldForwardArgs: true }, result, this.contextMenuService, g => /^inline/.test(g));
return menu;
}

View File

@@ -6,8 +6,7 @@
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import * as modes from 'vs/editor/common/modes';
import { ActionsOrientation, ActionViewItem, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Button } from 'vs/base/browser/ui/button/button';
import { ActionsOrientation, ActionViewItem, ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action, IActionRunner, IAction } from 'vs/base/common/actions';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
@@ -16,34 +15,25 @@ 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 { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { inputValidationErrorBorder } from 'vs/platform/theme/common/colorRegistry';
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ICommentService } from 'vs/workbench/contrib/comments/browser/commentService';
import { SimpleCommentEditor } from 'vs/workbench/contrib/comments/browser/simpleCommentEditor';
import { Selection } from 'vs/editor/common/core/selection';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { Emitter, Event } from 'vs/base/common/event';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { assign } from 'vs/base/common/objects';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { ToggleReactionsAction, ReactionAction, ReactionActionViewItem } from './reactionsAction';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget';
import { MenuItemAction } from 'vs/platform/actions/common/actions';
import { MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { CommentFormActions } from 'vs/workbench/contrib/comments/browser/commentFormActions';
const UPDATE_COMMENT_LABEL = nls.localize('label.updateComment', "Update comment");
const UPDATE_IN_PROGRESS_LABEL = nls.localize('label.updatingComment', "Updating comment...");
export class CommentNode extends Disposable {
private _domNode: HTMLElement;
private _body: HTMLElement;
@@ -59,13 +49,10 @@ export class CommentNode extends Disposable {
private _commentEditor: SimpleCommentEditor | null;
private _commentEditorDisposables: IDisposable[] = [];
private _commentEditorModel: ITextModel;
private _updateCommentButton: Button;
private _errorEditingContainer: HTMLElement;
private _isPendingLabel: HTMLElement;
private _contextKeyService: IContextKeyService;
private _commentContextValue: IContextKey<string>;
private _deleteAction: Action;
protected actionRunner?: IActionRunner;
protected toolbar: ToolBar;
private _commentFormActions: CommentFormActions;
@@ -79,7 +66,7 @@ export class CommentNode extends Disposable {
public isEditing: boolean;
constructor(
private commentThread: modes.CommentThread | modes.CommentThread2,
private commentThread: modes.CommentThread,
public comment: modes.Comment,
private owner: string,
private resource: URI,
@@ -89,10 +76,8 @@ export class CommentNode extends Disposable {
@IThemeService private themeService: IThemeService,
@IInstantiationService private instantiationService: IInstantiationService,
@ICommentService private commentService: ICommentService,
@ICommandService private commandService: ICommandService,
@IModelService private modelService: IModelService,
@IModeService private modeService: IModeService,
@IDialogService private dialogService: IDialogService,
@IKeybindingService private keybindingService: IKeybindingService,
@INotificationService private notificationService: INotificationService,
@IContextMenuService private contextMenuService: IContextMenuService,
@@ -119,7 +104,7 @@ export class CommentNode extends Disposable {
this._md = this.markdownRenderer.render(comment.body).element;
this._body.appendChild(this._md);
if (this.comment.commentReactions && this.comment.commentReactions.length) {
if (this.comment.commentReactions && this.comment.commentReactions.length && this.comment.commentReactions.filter(reaction => !!reaction.count).length) {
this.createReactionsContainer(this._commentDetailsContainer);
}
@@ -141,8 +126,6 @@ export class CommentNode extends Disposable {
if (this.comment.label) {
this._isPendingLabel.innerText = this.comment.label;
} else if (this.comment.isDraft) {
this._isPendingLabel.innerText = 'Pending';
} else {
this._isPendingLabel.innerText = '';
}
@@ -153,39 +136,35 @@ export class CommentNode extends Disposable {
private createActionsToolbar() {
const actions: IAction[] = [];
const secondaryActions: IAction[] = [];
let reactionGroup = this.commentService.getReactionGroup(this.owner);
if (reactionGroup && reactionGroup.length) {
let commentThread = this.commentThread as modes.CommentThread2;
if (commentThread.commentThreadHandle !== undefined) {
let toggleReactionAction = this.createReactionPicker2();
actions.push(toggleReactionAction);
} else {
let toggleReactionAction = this.createReactionPicker();
actions.push(toggleReactionAction);
}
}
let hasReactionHandler = this.commentService.hasReactionHandler(this.owner);
if (this.comment.canEdit || this.comment.editCommand) {
this._editAction = this.createEditAction(this._commentDetailsContainer);
actions.push(this._editAction);
}
if (this.comment.canDelete || this.comment.deleteCommand) {
this._deleteAction = this.createDeleteAction();
actions.push(this._deleteAction);
if (hasReactionHandler) {
let toggleReactionAction = this.createReactionPicker2(this.comment.commentReactions || []);
actions.push(toggleReactionAction);
}
let commentMenus = this.commentService.getCommentMenus(this.owner);
const menu = commentMenus.getCommentTitleActions(this.comment, this._contextKeyService);
this._toDispose.push(menu);
this._toDispose.push(menu.onDidChange(e => {
const contributedActions = menu.getActions({ shouldForwardArgs: true }).reduce((r, [, actions]) => [...r, ...actions], <MenuItemAction[]>[]);
this.toolbar.setActions(contributedActions);
this._register(menu);
this._register(menu.onDidChange(e => {
const primary: IAction[] = [];
const secondary: IAction[] = [];
const result = { primary, secondary };
fillInActions(contributedActions, result, false, g => /^inline/.test(g));
this.toolbar.setActions(primary, secondary);
}));
const contributedActions = menu.getActions({ shouldForwardArgs: true }).reduce((r, [, actions]) => [...r, ...actions], <MenuItemAction[]>[]);
actions.push(...contributedActions);
const contributedActions = menu.getActions({ shouldForwardArgs: true });
{
const primary: IAction[] = [];
const secondary: IAction[] = [];
const result = { primary, secondary };
fillInActions(contributedActions, result, false, g => /^inline/.test(g));
actions.push(...primary);
secondaryActions.push(...secondary);
}
if (actions.length) {
this.toolbar = new ToolBar(this._actionsToolbarContainer, this.contextMenuService, {
@@ -216,8 +195,8 @@ export class CommentNode extends Disposable {
};
this.registerActionBarListeners(this._actionsToolbarContainer);
this.toolbar.setActions(actions, [])();
this._toDispose.push(this.toolbar);
this.toolbar.setActions(actions, secondaryActions)();
this._register(this.toolbar);
}
}
@@ -241,7 +220,7 @@ export class CommentNode extends Disposable {
}
}
private createReactionPicker2(): ToggleReactionsAction {
private createReactionPicker2(reactionGroup: modes.CommentReaction[]): ToggleReactionsAction {
let toggleReactionActionViewItem: DropdownMenuActionViewItem;
let toggleReactionAction = this._register(new ToggleReactionsAction(() => {
if (toggleReactionActionViewItem) {
@@ -250,12 +229,11 @@ export class CommentNode extends Disposable {
}, nls.localize('commentToggleReaction', "Toggle Reaction")));
let reactionMenuActions: Action[] = [];
let reactionGroup = this.commentService.getReactionGroup(this.owner);
if (reactionGroup && reactionGroup.length) {
reactionMenuActions = reactionGroup.map((reaction) => {
return new Action(`reaction.command.${reaction.label}`, `${reaction.label}`, '', true, async () => {
try {
await this.commentService.toggleReaction(this.owner, this.resource, this.commentThread as modes.CommentThread2, this.comment, reaction);
await this.commentService.toggleReaction(this.owner, this.resource, this.commentThread, this.comment, reaction);
} catch (e) {
const error = e.message
? nls.localize('commentToggleReactionError', "Toggling the comment reaction failed: {0}.", e.message)
@@ -287,52 +265,6 @@ export class CommentNode extends Disposable {
return toggleReactionAction;
}
private createReactionPicker(): ToggleReactionsAction {
let toggleReactionActionViewItem: DropdownMenuActionViewItem;
let toggleReactionAction = this._register(new ToggleReactionsAction(() => {
if (toggleReactionActionViewItem) {
toggleReactionActionViewItem.show();
}
}, nls.localize('commentAddReaction', "Add Reaction")));
let reactionMenuActions: Action[] = [];
let reactionGroup = this.commentService.getReactionGroup(this.owner);
if (reactionGroup && reactionGroup.length) {
reactionMenuActions = reactionGroup.map((reaction) => {
return new Action(`reaction.command.${reaction.label}`, `${reaction.label}`, '', true, async () => {
try {
await this.commentService.addReaction(this.owner, this.resource, this.comment, reaction);
} catch (e) {
const error = e.message
? nls.localize('commentAddReactionError', "Deleting the comment reaction failed: {0}.", e.message)
: nls.localize('commentAddReactionDefaultError', "Deleting the comment reaction failed");
this.notificationService.error(error);
}
});
});
}
toggleReactionAction.menuActions = reactionMenuActions;
toggleReactionActionViewItem = new DropdownMenuActionViewItem(
toggleReactionAction,
(<ToggleReactionsAction>toggleReactionAction).menuActions,
this.contextMenuService,
action => {
if (action.id === ToggleReactionsAction.ID) {
return toggleReactionActionViewItem;
}
return this.actionViewItemProvider(action as Action);
},
this.actionRunner!,
undefined,
'toolbar-toggle-pickReactions',
() => { return AnchorAlignment.RIGHT; }
);
return toggleReactionAction;
}
private createReactionsContainer(commentDetailsContainer: HTMLElement): void {
this._reactionActionsContainer = dom.append(commentDetailsContainer, dom.$('div.comment-reactions'));
this._reactionsActionBar = new ActionBar(this._reactionActionsContainer, {
@@ -354,21 +286,13 @@ export class CommentNode extends Disposable {
return this.actionViewItemProvider(action as Action);
}
});
this._toDispose.push(this._reactionsActionBar);
this._register(this._reactionsActionBar);
this.comment.commentReactions!.map(reaction => {
let action = new ReactionAction(`reaction.${reaction.label}`, `${reaction.label}`, reaction.hasReacted && reaction.canEdit ? 'active' : '', reaction.canEdit, async () => {
let hasReactionHandler = this.commentService.hasReactionHandler(this.owner);
this.comment.commentReactions!.filter(reaction => !!reaction.count).map(reaction => {
let action = new ReactionAction(`reaction.${reaction.label}`, `${reaction.label}`, reaction.hasReacted && (reaction.canEdit || hasReactionHandler) ? 'active' : '', (reaction.canEdit || hasReactionHandler), async () => {
try {
let commentThread = this.commentThread as modes.CommentThread2;
if (commentThread.commentThreadHandle !== undefined) {
await this.commentService.toggleReaction(this.owner, this.resource, this.commentThread as modes.CommentThread2, this.comment, reaction);
} else {
if (reaction.hasReacted) {
await this.commentService.deleteReaction(this.owner, this.resource, this.comment, reaction);
} else {
await this.commentService.addReaction(this.owner, this.resource, this.comment, reaction);
}
}
await this.commentService.toggleReaction(this.owner, this.resource, this.commentThread, this.comment, reaction);
} catch (e) {
let error: string;
@@ -390,14 +314,13 @@ export class CommentNode extends Disposable {
}
});
let reactionGroup = this.commentService.getReactionGroup(this.owner);
if (reactionGroup && reactionGroup.length) {
let commentThread = this.commentThread as modes.CommentThread2;
if (commentThread.commentThreadHandle !== undefined) {
let toggleReactionAction = this.createReactionPicker2();
this._reactionsActionBar.push(toggleReactionAction, { label: false, icon: true });
} else {
let toggleReactionAction = this.createReactionPicker();
if (hasReactionHandler) {
let toggleReactionAction = this.createReactionPicker2(this.comment.commentReactions || []);
this._reactionsActionBar.push(toggleReactionAction, { label: false, icon: true });
} else {
let reactionGroup = this.commentService.getReactionGroup(this.owner);
if (reactionGroup && reactionGroup.length) {
let toggleReactionAction = this.createReactionPicker2(reactionGroup || []);
this._reactionsActionBar.push(toggleReactionAction, { label: false, icon: true });
}
}
@@ -407,7 +330,7 @@ export class CommentNode extends Disposable {
const container = dom.append(this._commentEditContainer, dom.$('.edit-textarea'));
this._commentEditor = this.instantiationService.createInstance(SimpleCommentEditor, container, SimpleCommentEditor.getEditorOptions(), this.parentEditor, this.parentThread);
const resource = URI.parse(`comment:commentinput-${this.comment.commentId}-${Date.now()}.md`);
this._commentEditorModel = this.modelService.createModel('', this.modeService.createByFilepathOrFirstLine(resource.path), resource, false);
this._commentEditorModel = this.modelService.createModel('', this.modeService.createByFilepathOrFirstLine(resource), resource, false);
this._commentEditor.setModel(this._commentEditorModel);
this._commentEditor.setValue(this.comment.body.value);
@@ -418,34 +341,35 @@ export class CommentNode extends Disposable {
const lastColumn = this._commentEditorModel.getLineContent(lastLine).length + 1;
this._commentEditor.setSelection(new Selection(lastLine, lastColumn, lastLine, lastColumn));
let commentThread = this.commentThread as modes.CommentThread2;
if (commentThread.commentThreadHandle !== undefined) {
let commentThread = this.commentThread;
commentThread.input = {
uri: this._commentEditor.getModel()!.uri,
value: this.comment.body.value
};
this.commentService.setActiveCommentThread(commentThread);
this._commentEditorDisposables.push(this._commentEditor.onDidFocusEditorWidget(() => {
commentThread.input = {
uri: this._commentEditor.getModel()!.uri,
uri: this._commentEditor!.getModel()!.uri,
value: this.comment.body.value
};
this.commentService.setActiveCommentThread(commentThread);
}));
this._commentEditorDisposables.push(this._commentEditor.onDidFocusEditorWidget(() => {
commentThread.input = {
uri: this._commentEditor!.getModel()!.uri,
value: this.comment.body.value
};
}));
this._commentEditorDisposables.push(this._commentEditor.onDidChangeModelContent(e => {
if (commentThread.input && this._commentEditor && this._commentEditor.getModel()!.uri === commentThread.input.uri) {
let newVal = this._commentEditor.getValue();
if (newVal !== commentThread.input.value) {
let input = commentThread.input;
input.value = newVal;
commentThread.input = input;
}
this._commentEditorDisposables.push(this._commentEditor.onDidChangeModelContent(e => {
if (commentThread.input && this._commentEditor && this._commentEditor.getModel()!.uri === commentThread.input.uri) {
let newVal = this._commentEditor.getValue();
if (newVal !== commentThread.input.value) {
let input = commentThread.input;
input.value = newVal;
commentThread.input = input;
this.commentService.setActiveCommentThread(commentThread);
}
}));
}
}
}));
this._toDispose.push(this._commentEditor);
this._toDispose.push(this._commentEditorModel);
this._register(this._commentEditor);
this._register(this._commentEditorModel);
}
private removeCommentEditor() {
@@ -469,83 +393,6 @@ export class CommentNode extends Disposable {
this._commentEditContainer.remove();
}
async editComment(): Promise<void> {
if (!this._commentEditor) {
throw new Error('No comment editor');
}
this._updateCommentButton.enabled = false;
this._updateCommentButton.label = UPDATE_IN_PROGRESS_LABEL;
try {
const newBody = this._commentEditor.getValue();
if (this.comment.editCommand) {
let commentThread = this.commentThread as modes.CommentThread2;
commentThread.input = {
uri: this._commentEditor.getModel()!.uri,
value: newBody
};
let commandId = this.comment.editCommand.id;
let args = this.comment.editCommand.arguments || [];
await this.commandService.executeCommand(commandId, ...args);
} else {
await this.commentService.editComment(this.owner, this.resource, this.comment, newBody);
}
this._updateCommentButton.enabled = true;
this._updateCommentButton.label = UPDATE_COMMENT_LABEL;
this._commentEditor.getDomNode()!.style.outline = '';
this.removeCommentEditor();
const editedComment = assign({}, this.comment, { body: new MarkdownString(newBody) });
this.update(editedComment);
} catch (e) {
this._updateCommentButton.enabled = true;
this._updateCommentButton.label = UPDATE_COMMENT_LABEL;
this._commentEditor.getDomNode()!.style.outline = `1px solid ${this.themeService.getTheme().getColor(inputValidationErrorBorder)}`;
this._errorEditingContainer.textContent = e.message
? nls.localize('commentEditError', "Updating the comment failed: {0}.", e.message)
: nls.localize('commentEditDefaultError', "Updating the comment failed.");
this._errorEditingContainer.classList.remove('hidden');
this._commentEditor.focus();
}
}
private createDeleteAction(): Action {
return new Action('comment.delete', nls.localize('label.delete', "Delete"), 'octicon octicon-x', true, () => {
return this.dialogService.confirm({
message: nls.localize('confirmDelete', "Delete comment?"),
type: 'question',
primaryButton: nls.localize('label.delete', "Delete")
}).then(async result => {
if (result.confirmed) {
try {
if (this.comment.deleteCommand) {
let commandId = this.comment.deleteCommand.id;
let args = this.comment.deleteCommand.arguments || [];
await this.commandService.executeCommand(commandId, ...args);
} else {
const didDelete = await this.commentService.deleteComment(this.owner, this.resource, this.comment);
if (didDelete) {
this._onDidDelete.fire(this);
} else {
throw Error();
}
}
} catch (e) {
const error = e.message
? nls.localize('commentDeletionError', "Deleting the comment failed: {0}.", e.message)
: nls.localize('commentDeletionDefaultError', "Deleting the comment failed");
this.notificationService.error(error);
}
}
});
});
}
public switchToEditMode() {
if (this.isEditing) {
return;
@@ -555,14 +402,13 @@ export class CommentNode extends Disposable {
this._body.classList.add('hidden');
this._commentEditContainer = dom.append(this._commentDetailsContainer, dom.$('.edit-container'));
this.createCommentEditor();
this._errorEditingContainer = dom.append(this._commentEditContainer, dom.$('.validation-error.hidden'));
const formActions = dom.append(this._commentEditContainer, dom.$('.form-actions'));
const menus = this.commentService.getCommentMenus(this.owner);
const menu = menus.getCommentActions(this.comment, this._contextKeyService);
this._toDispose.push(menu);
this._toDispose.push(menu.onDidChange(() => {
this._register(menu);
this._register(menu.onDidChange(() => {
this._commentFormActions.setActions(menu);
}));
@@ -582,69 +428,20 @@ export class CommentNode extends Disposable {
this._commentFormActions.setActions(menu);
}
private createEditAction(commentDetailsContainer: HTMLElement): Action {
return new Action('comment.edit', nls.localize('label.edit', "Edit"), 'octicon octicon-pencil', true, () => {
return this.editCommentAction(commentDetailsContainer);
});
}
private editCommentAction(commentDetailsContainer: HTMLElement) {
this.isEditing = true;
this._body.classList.add('hidden');
this._commentEditContainer = dom.append(commentDetailsContainer, dom.$('.edit-container'));
this.createCommentEditor();
this._errorEditingContainer = dom.append(this._commentEditContainer, dom.$('.validation-error.hidden'));
const formActions = dom.append(this._commentEditContainer, dom.$('.form-actions'));
const cancelEditButton = new Button(formActions);
cancelEditButton.label = nls.localize('label.cancel', "Cancel");
this._toDispose.push(attachButtonStyler(cancelEditButton, this.themeService));
this._toDispose.push(cancelEditButton.onDidClick(_ => {
this.removeCommentEditor();
}));
this._updateCommentButton = new Button(formActions);
this._updateCommentButton.label = UPDATE_COMMENT_LABEL;
this._toDispose.push(attachButtonStyler(this._updateCommentButton, this.themeService));
this._toDispose.push(this._updateCommentButton.onDidClick(_ => {
this.editComment();
}));
this._commentEditorDisposables.push(this._commentEditor!.onDidChangeModelContent(_ => {
this._updateCommentButton.enabled = !!this._commentEditor!.getValue();
}));
this._editAction.enabled = false;
return Promise.resolve();
}
private registerActionBarListeners(actionsContainer: HTMLElement): void {
this._toDispose.push(dom.addDisposableListener(this._domNode, 'mouseenter', () => {
this._register(dom.addDisposableListener(this._domNode, 'mouseenter', () => {
actionsContainer.classList.remove('hidden');
}));
this._toDispose.push(dom.addDisposableListener(this._domNode, 'focus', () => {
this._register(dom.addDisposableListener(this._domNode, 'focus', () => {
actionsContainer.classList.remove('hidden');
}));
this._toDispose.push(dom.addDisposableListener(this._domNode, 'mouseleave', () => {
this._register(dom.addDisposableListener(this._domNode, 'mouseleave', () => {
if (!this._domNode.contains(document.activeElement)) {
actionsContainer.classList.add('hidden');
}
}));
this._toDispose.push(dom.addDisposableListener(this._domNode, 'focusout', (e: FocusEvent) => {
if (!this._domNode.contains((<HTMLElement>e.relatedTarget))) {
actionsContainer.classList.add('hidden');
if (this._commentEditor && this._commentEditor.getValue() === this.comment.body.value) {
this.removeCommentEditor();
}
}
}));
}
update(newComment: modes.Comment) {
@@ -663,19 +460,10 @@ export class CommentNode extends Disposable {
}
}
const shouldUpdateActions = newComment.editCommand !== this.comment.editCommand || newComment.deleteCommand !== this.comment.deleteCommand;
this.comment = newComment;
if (shouldUpdateActions) {
dom.clearNode(this._actionsToolbarContainer);
this.createActionsToolbar();
}
if (newComment.label) {
this._isPendingLabel.innerText = newComment.label;
} else if (newComment.isDraft) {
this._isPendingLabel.innerText = 'Pending';
} else {
this._isPendingLabel.innerText = '';
}
@@ -689,7 +477,7 @@ export class CommentNode extends Disposable {
this._reactionsActionBar.clear();
}
if (this.comment.commentReactions && this.comment.commentReactions.length) {
if (this.comment.commentReactions && this.comment.commentReactions.some(reaction => !!reaction.count)) {
this.createReactionsContainer(this._commentDetailsContainer);
}
@@ -709,8 +497,27 @@ export class CommentNode extends Disposable {
}, 3000);
}
}
dispose() {
this._toDispose.forEach(disposeable => disposeable.dispose());
}
}
function fillInActions(groups: [string, Array<MenuItemAction | SubmenuItemAction>][], target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, useAlternativeActions: boolean, isPrimaryGroup: (group: string) => boolean = group => group === 'navigation'): void {
for (let tuple of groups) {
let [group, actions] = tuple;
if (useAlternativeActions) {
actions = actions.map(a => (a instanceof MenuItemAction) && !!a.alt ? a.alt : a);
}
if (isPrimaryGroup(group)) {
const to = Array.isArray<IAction>(target) ? target : target.primary;
to.unshift(...actions);
} else {
const to = Array.isArray<IAction>(target) ? target : target.secondary;
if (to.length > 0) {
to.push(new Separator());
}
to.push(...actions);
}
}
}

View File

@@ -3,13 +3,12 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CommentThread, DocumentCommentProvider, CommentThreadChangedEvent, CommentInfo, Comment, CommentReaction, CommentingRanges, CommentThread2 } from 'vs/editor/common/modes';
import { CommentThreadChangedEvent, CommentInfo, Comment, CommentReaction, CommentingRanges, CommentThread } from 'vs/editor/common/modes';
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Event, Emitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { Range, IRange } from 'vs/editor/common/core/range';
import { keys } from 'vs/base/common/map';
import { CancellationToken } from 'vs/base/common/cancellation';
import { assign } from 'vs/base/common/objects';
import { ICommentThreadChangedEvent } from 'vs/workbench/contrib/comments/common/commentModel';
@@ -38,37 +37,27 @@ export interface ICommentService {
readonly onDidSetResourceCommentInfos: Event<IResourceCommentThreadEvent>;
readonly onDidSetAllCommentThreads: Event<IWorkspaceCommentThreadsEvent>;
readonly onDidUpdateCommentThreads: Event<ICommentThreadChangedEvent>;
readonly onDidChangeActiveCommentThread: Event<CommentThread | null>;
readonly onDidChangeActiveCommentingRange: Event<{ range: Range, commentingRangesInfo: CommentingRanges }>;
readonly onDidSetDataProvider: Event<void>;
readonly onDidDeleteDataProvider: Event<string>;
setDocumentComments(resource: URI, commentInfos: ICommentInfo[]): void;
setWorkspaceComments(owner: string, commentsByResource: CommentThread[] | CommentThread2[]): void;
setWorkspaceComments(owner: string, commentsByResource: CommentThread[]): void;
removeWorkspaceComments(owner: string): void;
registerCommentController(owner: string, commentControl: MainThreadCommentController): void;
unregisterCommentController(owner: string): void;
getCommentController(owner: string): MainThreadCommentController | undefined;
createCommentThreadTemplate(owner: string, resource: URI, range: Range): void;
updateCommentThreadTemplate(owner: string, threadHandle: number, range: Range): Promise<void>;
getCommentMenus(owner: string): CommentMenus;
registerDataProvider(owner: string, commentProvider: DocumentCommentProvider): void;
unregisterDataProvider(owner: string): void;
updateComments(ownerId: string, event: CommentThreadChangedEvent): void;
disposeCommentThread(ownerId: string, threadId: string): void;
createNewCommentThread(owner: string, resource: URI, range: Range, text: string): Promise<CommentThread | null>;
replyToCommentThread(owner: string, resource: URI, range: Range, thread: CommentThread, text: string): Promise<CommentThread | null>;
editComment(owner: string, resource: URI, comment: Comment, text: string): Promise<void>;
deleteComment(owner: string, resource: URI, comment: Comment): Promise<boolean>;
getComments(resource: URI): Promise<(ICommentInfo | null)[]>;
getCommentingRanges(resource: URI): Promise<IRange[]>;
startDraft(owner: string, resource: URI): void;
deleteDraft(owner: string, resource: URI): void;
finishDraft(owner: string, resource: URI): void;
getStartDraftLabel(owner: string): string | undefined;
getDeleteDraftLabel(owner: string): string | undefined;
getFinishDraftLabel(owner: string): string | undefined;
addReaction(owner: string, resource: URI, comment: Comment, reaction: CommentReaction): Promise<void>;
deleteReaction(owner: string, resource: URI, comment: Comment, reaction: CommentReaction): Promise<void>;
getReactionGroup(owner: string): CommentReaction[] | undefined;
toggleReaction(owner: string, resource: URI, thread: CommentThread2, comment: Comment, reaction: CommentReaction): Promise<void>;
hasReactionHandler(owner: string): boolean;
toggleReaction(owner: string, resource: URI, thread: CommentThread, comment: Comment, reaction: CommentReaction): Promise<void>;
setActiveCommentThread(commentThread: CommentThread | null): void;
}
export class CommentService extends Disposable implements ICommentService {
@@ -89,6 +78,9 @@ export class CommentService extends Disposable implements ICommentService {
private readonly _onDidUpdateCommentThreads: Emitter<ICommentThreadChangedEvent> = this._register(new Emitter<ICommentThreadChangedEvent>());
readonly onDidUpdateCommentThreads: Event<ICommentThreadChangedEvent> = this._onDidUpdateCommentThreads.event;
private readonly _onDidChangeActiveCommentThread = this._register(new Emitter<CommentThread | null>());
readonly onDidChangeActiveCommentThread = this._onDidChangeActiveCommentThread.event;
private readonly _onDidChangeActiveCommentingRange: Emitter<{
range: Range, commentingRangesInfo:
CommentingRanges
@@ -98,8 +90,6 @@ export class CommentService extends Disposable implements ICommentService {
}>());
readonly onDidChangeActiveCommentingRange: Event<{ range: Range, commentingRangesInfo: CommentingRanges }> = this._onDidChangeActiveCommentingRange.event;
private _commentProviders = new Map<string, DocumentCommentProvider>();
private _commentControls = new Map<string, MainThreadCommentController>();
private _commentMenus = new Map<string, CommentMenus>();
@@ -109,6 +99,10 @@ export class CommentService extends Disposable implements ICommentService {
super();
}
setActiveCommentThread(commentThread: CommentThread | null) {
this._onDidChangeActiveCommentThread.fire(commentThread);
}
setDocumentComments(resource: URI, commentInfos: ICommentInfo[]): void {
this._onDidSetResourceCommentInfos.fire({ resource, commentInfos });
}
@@ -145,6 +139,16 @@ export class CommentService extends Disposable implements ICommentService {
commentController.createCommentThreadTemplate(resource, range);
}
async updateCommentThreadTemplate(owner: string, threadHandle: number, range: Range) {
const commentController = this._commentControls.get(owner);
if (!commentController) {
return;
}
await commentController.updateCommentThreadTemplate(threadHandle, range);
}
disposeCommentThread(owner: string, threadId: string) {
let controller = this.getCommentController(owner);
if (controller) {
@@ -164,112 +168,12 @@ export class CommentService extends Disposable implements ICommentService {
return menu;
}
registerDataProvider(owner: string, commentProvider: DocumentCommentProvider): void {
this._commentProviders.set(owner, commentProvider);
this._onDidSetDataProvider.fire();
}
unregisterDataProvider(owner: string): void {
this._commentProviders.delete(owner);
this._onDidDeleteDataProvider.fire(owner);
}
updateComments(ownerId: string, event: CommentThreadChangedEvent): void {
const evt: ICommentThreadChangedEvent = assign({}, event, { owner: ownerId });
this._onDidUpdateCommentThreads.fire(evt);
}
async createNewCommentThread(owner: string, resource: URI, range: Range, text: string): Promise<CommentThread | null> {
const commentProvider = this._commentProviders.get(owner);
if (commentProvider) {
return await commentProvider.createNewCommentThread(resource, range, text, CancellationToken.None);
}
return null;
}
async replyToCommentThread(owner: string, resource: URI, range: Range, thread: CommentThread, text: string): Promise<CommentThread | null> {
const commentProvider = this._commentProviders.get(owner);
if (commentProvider) {
return await commentProvider.replyToCommentThread(resource, range, thread, text, CancellationToken.None);
}
return null;
}
editComment(owner: string, resource: URI, comment: Comment, text: string): Promise<void> {
const commentProvider = this._commentProviders.get(owner);
if (commentProvider) {
return commentProvider.editComment(resource, comment, text, CancellationToken.None);
}
return Promise.resolve(undefined);
}
deleteComment(owner: string, resource: URI, comment: Comment): Promise<boolean> {
const commentProvider = this._commentProviders.get(owner);
if (commentProvider) {
return commentProvider.deleteComment(resource, comment, CancellationToken.None).then(() => true);
}
return Promise.resolve(false);
}
async startDraft(owner: string, resource: URI): Promise<void> {
const commentProvider = this._commentProviders.get(owner);
if (commentProvider && commentProvider.startDraft) {
return commentProvider.startDraft(resource, CancellationToken.None);
} else {
throw new Error('Not supported');
}
}
async deleteDraft(owner: string, resource: URI): Promise<void> {
const commentProvider = this._commentProviders.get(owner);
if (commentProvider && commentProvider.deleteDraft) {
return commentProvider.deleteDraft(resource, CancellationToken.None);
} else {
throw new Error('Not supported');
}
}
async finishDraft(owner: string, resource: URI): Promise<void> {
const commentProvider = this._commentProviders.get(owner);
if (commentProvider && commentProvider.finishDraft) {
return commentProvider.finishDraft(resource, CancellationToken.None);
} else {
throw new Error('Not supported');
}
}
async addReaction(owner: string, resource: URI, comment: Comment, reaction: CommentReaction): Promise<void> {
const commentProvider = this._commentProviders.get(owner);
if (commentProvider && commentProvider.addReaction) {
return commentProvider.addReaction(resource, comment, reaction, CancellationToken.None);
} else {
throw new Error('Not supported');
}
}
async deleteReaction(owner: string, resource: URI, comment: Comment, reaction: CommentReaction): Promise<void> {
const commentProvider = this._commentProviders.get(owner);
if (commentProvider && commentProvider.deleteReaction) {
return commentProvider.deleteReaction(resource, comment, reaction, CancellationToken.None);
} else {
throw new Error('Not supported');
}
}
async toggleReaction(owner: string, resource: URI, thread: CommentThread2, comment: Comment, reaction: CommentReaction): Promise<void> {
async toggleReaction(owner: string, resource: URI, thread: CommentThread, comment: Comment, reaction: CommentReaction): Promise<void> {
const commentController = this._commentControls.get(owner);
if (commentController) {
@@ -295,57 +199,17 @@ export class CommentService extends Disposable implements ICommentService {
return undefined;
}
getStartDraftLabel(owner: string): string | undefined {
const commentProvider = this._commentProviders.get(owner);
hasReactionHandler(owner: string): boolean {
const commentProvider = this._commentControls.get(owner);
if (commentProvider) {
return commentProvider.startDraftLabel;
return !!commentProvider.features.reactionHandler;
}
return undefined;
}
getDeleteDraftLabel(owner: string): string | undefined {
const commentProvider = this._commentProviders.get(owner);
if (commentProvider) {
return commentProvider.deleteDraftLabel;
}
return undefined;
}
getFinishDraftLabel(owner: string): string | undefined {
const commentProvider = this._commentProviders.get(owner);
if (commentProvider) {
return commentProvider.finishDraftLabel;
}
return undefined;
return false;
}
async getComments(resource: URI): Promise<(ICommentInfo | null)[]> {
const result: Promise<ICommentInfo | null>[] = [];
for (const owner of keys(this._commentProviders)) {
const provider = this._commentProviders.get(owner);
if (provider && provider.provideDocumentComments) {
result.push(provider.provideDocumentComments(resource, CancellationToken.None).then(commentInfo => {
if (commentInfo) {
return <ICommentInfo>{
owner: owner,
threads: commentInfo.threads,
commentingRanges: commentInfo.commentingRanges,
reply: commentInfo.reply,
draftMode: commentInfo.draftMode
};
} else {
return null;
}
}));
}
}
let commentControlResult: Promise<ICommentInfo | null>[] = [];
this._commentControls.forEach(control => {
@@ -356,7 +220,7 @@ export class CommentService extends Disposable implements ICommentService {
}));
});
return Promise.all([...result, ...commentControlResult]);
return Promise.all(commentControlResult);
}
async getCommentingRanges(resource: URI): Promise<IRange[]> {

View File

@@ -3,53 +3,50 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import { ActionBar, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { Button } from 'vs/base/browser/ui/button/button';
import { Action, IAction } from 'vs/base/common/actions';
import * as arrays from 'vs/base/common/arrays';
import { Color } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import * as strings from 'vs/base/common/strings';
import { withNullAsUndefined } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
import { IPosition } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
import { ITextModel } from 'vs/editor/common/model';
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 { ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget';
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService';
import { CommentGlyphWidget } from 'vs/workbench/contrib/comments/browser/commentGlyphWidget';
import * as nls from 'vs/nls';
import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenu, MenuItemAction } 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';
import { IModelService } from 'vs/editor/common/services/modelService';
import { SimpleCommentEditor } from './simpleCommentEditor';
import { URI } from 'vs/base/common/uri';
import { transparent, editorForeground, textLinkActiveForeground, textLinkForeground, focusBorder, textBlockQuoteBackground, textBlockQuoteBorder, contrastBorder, inputValidationErrorBorder, inputValidationErrorBackground, inputValidationErrorForeground } from 'vs/platform/theme/common/colorRegistry';
import { IModeService } from 'vs/editor/common/services/modeService';
import { ICommentService } from 'vs/workbench/contrib/comments/browser/commentService';
import { Range, IRange } from 'vs/editor/common/core/range';
import { IPosition } from 'vs/editor/common/core/position';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer';
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
import { CommentNode } from 'vs/workbench/contrib/comments/browser/commentNode';
import { ITextModel } from 'vs/editor/common/model';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { generateUuid } from 'vs/base/common/uuid';
import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget';
import { withNullAsUndefined } from 'vs/base/common/types';
import { CommentMenus } from 'vs/workbench/contrib/comments/browser/commentMenus';
import { MenuItemAction, IMenu } from 'vs/platform/actions/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/commentContextKeys';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { contrastBorder, editorForeground, focusBorder, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, textBlockQuoteBackground, textBlockQuoteBorder, textLinkActiveForeground, textLinkForeground, transparent } from 'vs/platform/theme/common/colorRegistry';
import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService';
import { CommentFormActions } from 'vs/workbench/contrib/comments/browser/commentFormActions';
import { CommentGlyphWidget } from 'vs/workbench/contrib/comments/browser/commentGlyphWidget';
import { CommentMenus } from 'vs/workbench/contrib/comments/browser/commentMenus';
import { CommentNode } from 'vs/workbench/contrib/comments/browser/commentNode';
import { ICommentService } from 'vs/workbench/contrib/comments/browser/commentService';
import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/commentContextKeys';
import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget';
import { SimpleCommentEditor } from './simpleCommentEditor';
export const COMMENTEDITOR_DECORATION_KEY = 'commenteditordecoration';
const COLLAPSE_ACTION_CLASS = 'expand-review-action octicon octicon-chevron-up';
const COLLAPSE_ACTION_CLASS = 'expand-review-action';
const COMMENT_SCHEME = 'comment';
@@ -73,7 +70,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
private _collapseAction: Action;
private _commentGlyph?: CommentGlyphWidget;
private _submitActionsDisposables: IDisposable[];
private _globalToDispose: IDisposable[];
private readonly _globalToDispose = new DisposableStore();
private _commentThreadDisposables: IDisposable[] = [];
private _markdownRenderer: MarkdownRenderer;
private _styleElement: HTMLStyleElement;
@@ -89,28 +86,22 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
return this._owner;
}
public get commentThread(): modes.CommentThread {
return this._commentThread as modes.CommentThread;
return this._commentThread;
}
public get extensionId(): string | undefined {
return this._commentThread.extensionId;
}
public get draftMode(): modes.DraftMode | undefined {
return this._draftMode;
}
private _commentMenus: CommentMenus;
constructor(
editor: ICodeEditor,
private _owner: string,
private _commentThread: modes.CommentThread | modes.CommentThread2,
private _commentThread: modes.CommentThread,
private _pendingComment: string,
private _draftMode: modes.DraftMode | undefined,
@IInstantiationService private instantiationService: IInstantiationService,
@IModeService private modeService: IModeService,
@ICommandService private commandService: ICommandService,
@IModelService private modelService: IModelService,
@IThemeService private themeService: IThemeService,
@ICommentService private commentService: ICommentService,
@@ -127,8 +118,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this._commentThreadContextValue = contextKeyService.createKey('commentThread', _commentThread.contextValue);
this._resizeObserver = null;
this._isExpanded = _commentThread.collapsibleState ? _commentThread.collapsibleState === modes.CommentThreadCollapsibleState.Expanded : undefined;
this._globalToDispose = [];
this._isExpanded = _commentThread.collapsibleState === modes.CommentThreadCollapsibleState.Expanded;
this._commentThreadDisposables = [];
this._submitActionsDisposables = [];
this._formActions = null;
@@ -136,15 +126,15 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this.create();
this._styleElement = dom.createStyleSheet(this.domNode);
this._globalToDispose.push(this.themeService.onThemeChange(this._applyTheme, this));
this._globalToDispose.push(this.editor.onDidChangeConfiguration(e => {
this._globalToDispose.add(this.themeService.onThemeChange(this._applyTheme, this));
this._globalToDispose.add(this.editor.onDidChangeConfiguration(e => {
if (e.fontInfo) {
this._applyTheme(this.themeService.getTheme());
}
}));
this._applyTheme(this.themeService.getTheme());
this._markdownRenderer = new MarkdownRenderer(editor, this.modeService, this.openerService);
this._markdownRenderer = this._globalToDispose.add(new MarkdownRenderer(editor, this.modeService, this.openerService));
this._parentEditor = editor;
}
@@ -211,6 +201,10 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this._bodyElement = <HTMLDivElement>dom.$('.body');
container.appendChild(this._bodyElement);
dom.addDisposableListener(this._bodyElement, dom.EventType.FOCUS_IN, e => {
this.commentService.setActiveCommentThread(this._commentThread);
});
}
protected _fillHead(container: HTMLElement): void {
@@ -232,21 +226,17 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
}
});
this._disposables.push(this._actionbarWidget);
this._disposables.add(this._actionbarWidget);
this._collapseAction = new Action('review.expand', nls.localize('label.collapse', "Collapse"), COLLAPSE_ACTION_CLASS, true, () => this.collapse());
if ((this._commentThread as modes.CommentThread2).commentThreadHandle !== undefined) {
const menu = this._commentMenus.getCommentThreadTitleActions(this._commentThread as modes.CommentThread2, this._contextKeyService);
this.setActionBarActions(menu);
const menu = this._commentMenus.getCommentThreadTitleActions(this._commentThread, this._contextKeyService);
this.setActionBarActions(menu);
this._disposables.push(menu);
this._disposables.push(menu.onDidChange(e => {
this.setActionBarActions(menu);
}));
} else {
this._actionbarWidget.push([this._collapseAction], { label: false, icon: true });
}
this._disposables.add(menu);
this._disposables.add(menu.onDidChange(e => {
this.setActionBarActions(menu);
}));
this._actionbarWidget.context = this._commentThread;
}
@@ -259,19 +249,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
public collapse(): Promise<void> {
if (this._commentThread.comments && this._commentThread.comments.length === 0) {
if ((this._commentThread as modes.CommentThread2).commentThreadHandle === undefined) {
this.dispose();
return Promise.resolve();
} else {
const deleteCommand = (this._commentThread as modes.CommentThread2).deleteCommand;
if (deleteCommand) {
return this.commandService.executeCommand(deleteCommand.id, ...(deleteCommand.arguments || []));
} else if (this._commentEditor.getValue() === '') {
this.commentService.disposeCommentThread(this._owner, this._commentThread.threadId!);
this.dispose();
return Promise.resolve();
}
}
this.dispose();
return Promise.resolve();
}
this.hide();
@@ -288,7 +267,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
toggleExpand(lineNumber: number) {
if (this._isExpanded) {
this.hide();
if (this._commentThread === null || this._commentThread.threadId === null) {
if (!this._commentThread.comments || !this._commentThread.comments.length) {
this.dispose();
}
} else {
@@ -296,7 +275,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
}
}
async update(commentThread: modes.CommentThread | modes.CommentThread2) {
async update(commentThread: modes.CommentThread) {
const oldCommentsLen = this._commentElements.length;
const newCommentsLen = commentThread.comments ? commentThread.comments.length : 0;
this._threadIsEmpty.set(!newCommentsLen);
@@ -351,7 +330,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
if (this._formActions && this._commentEditor.hasModel()) {
dom.clearNode(this._formActions);
const model = this._commentEditor.getModel();
this.createCommentWidgetActions2(this._formActions, model);
this.createCommentWidgetActions(this._formActions, model);
}
// Move comment glyph widget and show position if the line has changed.
@@ -376,13 +355,10 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this.show({ lineNumber, column: 1 }, 2);
}
// The collapsible state is not initialized yet.
if (this._isExpanded === undefined) {
if (this._commentThread.collapsibleState === modes.CommentThreadCollapsibleState.Expanded) {
this.show({ lineNumber, column: 1 }, 2);
} else {
this.hide();
}
if (this._commentThread.collapsibleState === modes.CommentThreadCollapsibleState.Expanded) {
this.show({ lineNumber, column: 1 }, 2);
} else {
this.hide();
}
if (this._commentThread.contextValue) {
@@ -392,18 +368,6 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
}
}
updateDraftMode(draftMode: modes.DraftMode | undefined) {
if (this._draftMode !== draftMode) {
this._draftMode = draftMode;
if (this._formActions && this._commentEditor.hasModel()) {
const model = this._commentEditor.getModel();
dom.clearNode(this._formActions);
this.createCommentWidgetActions(this._formActions, model);
}
}
}
protected _onWidth(widthInPixel: number): void {
this._commentEditor.layout({ height: 5 * 18, width: widthInPixel - 54 /* margin 20px * 10 + scrollbar 14px*/ });
}
@@ -415,8 +379,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
display(lineNumber: number) {
this._commentGlyph = new CommentGlyphWidget(this.editor, lineNumber);
this._disposables.push(this.editor.onMouseDown(e => this.onEditorMouseDown(e)));
this._disposables.push(this.editor.onMouseUp(e => this.onEditorMouseUp(e)));
this._disposables.add(this.editor.onMouseDown(e => this.onEditorMouseDown(e)));
this._disposables.add(this.editor.onMouseUp(e => this.onEditorMouseUp(e)));
let headHeight = Math.ceil(this.editor.getConfiguration().lineHeight * 1.2);
this._headElement.style.height = `${headHeight}px`;
@@ -453,18 +417,16 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
resource = resource.with({ authority: commentController.id });
}
const model = this.modelService.createModel(this._pendingComment || '', this.modeService.createByFilepathOrFirstLine(resource.path), resource, false);
this._disposables.push(model);
const model = this.modelService.createModel(this._pendingComment || '', this.modeService.createByFilepathOrFirstLine(resource), resource, false);
this._disposables.add(model);
this._commentEditor.setModel(model);
this._disposables.push(this._commentEditor);
this._disposables.push(this._commentEditor.getModel()!.onDidChangeContent(() => {
this._disposables.add(this._commentEditor);
this._disposables.add(this._commentEditor.getModel()!.onDidChangeContent(() => {
this.setCommentEditorDecorations();
this._commentEditorIsEmpty.set(!this._commentEditor.getValue());
}));
if ((this._commentThread as modes.CommentThread2).commentThreadHandle !== undefined) {
this.createTextModelListener();
}
this.createTextModelListener();
this.setCommentEditorDecorations();
@@ -480,12 +442,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this._error = dom.append(this._commentForm, dom.$('.validation-error.hidden'));
this._formActions = dom.append(this._commentForm, dom.$('.form-actions'));
if ((this._commentThread as modes.CommentThread2).commentThreadHandle !== undefined) {
this.createCommentWidgetActions2(this._formActions, model);
this.createCommentWidgetActionsListener(this._formActions, model);
} else {
this.createCommentWidgetActions(this._formActions, model);
}
this.createCommentWidgetActions(this._formActions, model);
this.createCommentWidgetActionsListener();
this._resizeObserver = new MutationObserver(this._refresh.bind(this));
@@ -502,7 +460,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
// If there are no existing comments, place focus on the text area. This must be done after show, which also moves focus.
// if this._commentThread.comments is undefined, it doesn't finish initialization yet, so we don't focus the editor immediately.
if ((this._commentThread as modes.CommentThread).reply && this._commentThread.comments && !this._commentThread.comments.length) {
if (this._commentThread.comments && !this._commentThread.comments.length) {
this._commentEditor.focus();
} else if (this._commentEditor.getModel()!.getValueLength() > 0) {
this.expandReplyArea();
@@ -511,25 +469,25 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
private createTextModelListener() {
this._commentThreadDisposables.push(this._commentEditor.onDidFocusEditorWidget(() => {
let commentThread = this._commentThread as modes.CommentThread2;
commentThread.input = {
this._commentThread.input = {
uri: this._commentEditor.getModel()!.uri,
value: this._commentEditor.getValue()
};
this.commentService.setActiveCommentThread(this._commentThread);
}));
this._commentThreadDisposables.push(this._commentEditor.getModel()!.onDidChangeContent(() => {
let modelContent = this._commentEditor.getValue();
let thread = (this._commentThread as modes.CommentThread2);
if (thread.input && thread.input.uri === this._commentEditor.getModel()!.uri && thread.input.value !== modelContent) {
let newInput: modes.CommentInput = thread.input;
if (this._commentThread.input && this._commentThread.input.uri === this._commentEditor.getModel()!.uri && this._commentThread.input.value !== modelContent) {
let newInput: modes.CommentInput = this._commentThread.input;
newInput.value = modelContent;
thread.input = newInput;
this._commentThread.input = newInput;
}
this.commentService.setActiveCommentThread(this._commentThread);
}));
this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeInput(input => {
let thread = (this._commentThread as modes.CommentThread2);
this._commentThreadDisposables.push(this._commentThread.onDidChangeInput(input => {
let thread = this._commentThread;
if (thread.input && thread.input.uri !== this._commentEditor.getModel()!.uri) {
return;
@@ -553,31 +511,17 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
}
}));
this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeComments(async _ => {
this._commentThreadDisposables.push(this._commentThread.onDidChangeComments(async _ => {
await this.update(this._commentThread);
}));
this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeLabel(_ => {
this._commentThreadDisposables.push(this._commentThread.onDidChangeLabel(_ => {
this.createThreadLabel();
}));
}
private createCommentWidgetActionsListener(container: HTMLElement, model: ITextModel) {
this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeAcceptInputCommand(_ => {
if (container) {
dom.clearNode(container);
this.createCommentWidgetActions2(container, model);
}
}));
this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeAdditionalCommands(_ => {
if (container) {
dom.clearNode(container);
this.createCommentWidgetActions2(container, model);
}
}));
this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeRange(range => {
private createCommentWidgetActionsListener() {
this._commentThreadDisposables.push(this._commentThread.onDidChangeRange(range => {
// Move comment glyph widget and show position if the line has changed.
const lineNumber = this._commentThread.range.startLineNumber;
let shouldMoveWidget = false;
@@ -593,7 +537,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
}
}));
this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeCollasibleState(state => {
this._commentThreadDisposables.push(this._commentThread.onDidChangeCollasibleState(state => {
if (state === modes.CommentThreadCollapsibleState.Expanded && !this._isExpanded) {
const lineNumber = this._commentThread.range.startLineNumber;
@@ -608,162 +552,31 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
}));
}
private handleError(e: Error) {
this._error.textContent = e.message;
this._commentEditor.getDomNode()!.style.outline = `1px solid ${this.themeService.getTheme().getColor(inputValidationErrorBorder)}`;
dom.removeClass(this._error, 'hidden');
}
private getActiveComment(): CommentNode | ReviewZoneWidget {
return this._commentElements.filter(node => node.isEditing)[0] || this;
}
private createCommentWidgetActions(container: HTMLElement, model: ITextModel) {
dispose(this._submitActionsDisposables);
const button = new Button(container);
this._submitActionsDisposables.push(attachButtonStyler(button, this.themeService));
button.label = 'Add comment';
button.enabled = model.getValueLength() > 0;
this._submitActionsDisposables.push(this._commentEditor.onDidChangeModelContent(_ => {
if (this._commentEditor.getValue()) {
button.enabled = true;
} else {
button.enabled = false;
}
}));
button.onDidClick(async () => {
this.createComment();
});
if (this._draftMode === modes.DraftMode.NotSupported) {
return;
}
switch (this._draftMode) {
case modes.DraftMode.InDraft:
const deleteDraftLabel = this.commentService.getDeleteDraftLabel(this._owner);
if (deleteDraftLabel) {
const deletedraftButton = new Button(container);
this._submitActionsDisposables.push(attachButtonStyler(deletedraftButton, this.themeService));
deletedraftButton.label = deleteDraftLabel;
deletedraftButton.enabled = true;
this._disposables.push(deletedraftButton.onDidClick(async () => {
try {
await this.commentService.deleteDraft(this._owner, this.editor.getModel()!.uri);
} catch (e) {
this.handleError(e);
}
}));
}
const submitDraftLabel = this.commentService.getFinishDraftLabel(this._owner);
if (submitDraftLabel) {
const submitdraftButton = new Button(container);
this._submitActionsDisposables.push(attachButtonStyler(submitdraftButton, this.themeService));
submitdraftButton.label = this.commentService.getFinishDraftLabel(this._owner)!;
submitdraftButton.enabled = true;
submitdraftButton.onDidClick(async () => {
try {
if (this._commentEditor.getValue()) {
await this.createComment();
}
await this.commentService.finishDraft(this._owner, this.editor.getModel()!.uri);
} catch (e) {
this.handleError(e);
}
});
}
break;
case modes.DraftMode.NotInDraft:
const startDraftLabel = this.commentService.getStartDraftLabel(this._owner);
if (startDraftLabel) {
const draftButton = new Button(container);
this._disposables.push(attachButtonStyler(draftButton, this.themeService));
draftButton.label = this.commentService.getStartDraftLabel(this._owner)!;
draftButton.enabled = model.getValueLength() > 0;
this._submitActionsDisposables.push(this._commentEditor.onDidChangeModelContent(_ => {
if (this._commentEditor.getValue()) {
draftButton.enabled = true;
} else {
draftButton.enabled = false;
}
}));
this._disposables.push(draftButton.onDidClick(async () => {
try {
await this.commentService.startDraft(this._owner, this.editor.getModel()!.uri);
await this.createComment();
} catch (e) {
this.handleError(e);
}
}));
}
break;
}
}
/**
* Command based actions.
*/
private createCommentWidgetActions2(container: HTMLElement, model: ITextModel) {
let commentThread = this._commentThread as modes.CommentThread2;
const { acceptInputCommand, additionalCommands } = commentThread;
if (acceptInputCommand) {
const button = new Button(container);
this._disposables.push(attachButtonStyler(button, this.themeService));
button.label = acceptInputCommand.title;
this._disposables.push(button.onDidClick(async () => {
commentThread.input = {
uri: this._commentEditor.getModel()!.uri,
value: this._commentEditor.getValue()
};
await this.commandService.executeCommand(acceptInputCommand.id, ...(acceptInputCommand.arguments || []));
}));
button.enabled = model.getValueLength() > 0;
this._disposables.push(this._commentEditor.onDidChangeModelContent(_ => {
if (this._commentEditor.getValue()) {
button.enabled = true;
} else {
button.enabled = false;
}
}));
}
if (additionalCommands) {
additionalCommands.reverse().forEach(command => {
const button = new Button(container);
this._disposables.push(attachButtonStyler(button, this.themeService));
button.label = command.title;
this._disposables.push(button.onDidClick(async () => {
commentThread.input = {
uri: this._commentEditor.getModel()!.uri,
value: this._commentEditor.getValue()
};
await this.commandService.executeCommand(command.id, ...(command.arguments || []));
}));
});
}
private createCommentWidgetActions(container: HTMLElement, model: ITextModel) {
const commentThread = this._commentThread;
const menu = this._commentMenus.getCommentThreadActions(commentThread, this._contextKeyService);
this._disposables.push(menu);
this._disposables.push(menu.onDidChange(() => {
this._disposables.add(menu);
this._disposables.add(menu.onDidChange(() => {
this._commentFormActions.setActions(menu);
}));
this._commentFormActions = new CommentFormActions(container, (action: IAction) => {
this._commentFormActions = new CommentFormActions(container, async (action: IAction) => {
if (!commentThread.comments || !commentThread.comments.length) {
let newPosition = this.getPosition();
if (newPosition) {
this.commentService.updateCommentThreadTemplate(this.owner, commentThread.commentThreadHandle, new Range(newPosition.lineNumber, 1, newPosition.lineNumber, 1));
}
}
action.run({
thread: this._commentThread,
text: this._commentEditor.getValue(),
@@ -786,8 +599,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this,
this._markdownRenderer);
this._disposables.push(newCommentNode);
this._disposables.push(newCommentNode.onDidDelete(deletedNode => {
this._disposables.add(newCommentNode);
this._disposables.add(newCommentNode.onDidDelete(deletedNode => {
const deletedNodeId = deletedNode.comment.commentId;
const deletedElementIndex = arrays.firstIndex(this._commentElements, commentNode => commentNode.comment.commentId === deletedNodeId);
if (deletedElementIndex > -1) {
@@ -813,94 +626,15 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
async submitComment(): Promise<void> {
const activeComment = this.getActiveComment();
if (activeComment instanceof ReviewZoneWidget) {
if ((this._commentThread as modes.CommentThread2).commentThreadHandle !== undefined) {
let commentThread = this._commentThread as modes.CommentThread2;
if (commentThread.acceptInputCommand) {
commentThread.input = {
uri: this._commentEditor.getModel()!.uri,
value: this._commentEditor.getValue()
};
let commandId = commentThread.acceptInputCommand.id;
let args = commentThread.acceptInputCommand.arguments || [];
await this.commandService.executeCommand(commandId, ...args);
return;
}
} else {
this.createComment();
if (this._commentFormActions) {
this._commentFormActions.triggerDefaultAction();
}
}
if (activeComment instanceof CommentNode) {
activeComment.editComment();
}
}
async createComment(): Promise<void> {
try {
if (this._commentEditor.getModel()!.getValueLength() === 0) {
return;
}
if (!this._commentGlyph) {
return;
}
let newCommentThread;
const lineNumber = this._commentGlyph.getPosition().position!.lineNumber;
const isReply = this._commentThread.threadId !== null;
if (isReply) {
newCommentThread = await this.commentService.replyToCommentThread(
this._owner,
this.editor.getModel()!.uri,
new Range(lineNumber, 1, lineNumber, 1),
this._commentThread,
this._commentEditor.getValue()
);
} else {
newCommentThread = await this.commentService.createNewCommentThread(
this._owner,
this.editor.getModel()!.uri,
new Range(lineNumber, 1, lineNumber, 1),
this._commentEditor.getValue()
);
if (newCommentThread) {
this.createReplyButton();
}
}
if (newCommentThread) {
this._commentEditor.setValue('');
this._pendingComment = '';
if (dom.hasClass(this._commentForm, 'expand')) {
dom.removeClass(this._commentForm, 'expand');
}
this._commentEditor.getDomNode()!.style.outline = '';
this._error.textContent = '';
dom.addClass(this._error, 'hidden');
this.update(newCommentThread);
if (!isReply) {
this._onDidCreateThread.fire(this);
}
}
} catch (e) {
this._error.textContent = e.message
? nls.localize('commentCreationError', "Adding a comment failed: {0}.", e.message)
: nls.localize('commentCreationDefaultError', "Adding a comment failed. Please try again or report an issue with the extension if the problem persists.");
this._commentEditor.getDomNode()!.style.outline = `1px solid ${this.themeService.getTheme().getColor(inputValidationErrorBorder)}`;
dom.removeClass(this._error, 'hidden');
}
}
private createThreadLabel() {
let label: string | undefined;
if ((this._commentThread as modes.CommentThread2).commentThreadHandle !== undefined) {
label = (this._commentThread as modes.CommentThread2).label;
}
label = this._commentThread.label;
if (label === undefined) {
if (this._commentThread.comments && this._commentThread.comments.length) {
@@ -937,15 +671,12 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
private createReplyButton() {
this._reviewThreadReplyButton = <HTMLButtonElement>dom.append(this._commentForm, dom.$('button.review-thread-reply-button'));
if ((this._commentThread as modes.CommentThread2).commentThreadHandle !== undefined) {
// this._reviewThreadReplyButton.title = (this._commentThread as modes.CommentThread2).acceptInputCommands.title;
} else {
this._reviewThreadReplyButton.title = nls.localize('reply', "Reply...");
}
this._reviewThreadReplyButton.title = nls.localize('reply', "Reply...");
this._reviewThreadReplyButton.textContent = nls.localize('reply', "Reply...");
// bind click/escape actions for reviewThreadReplyButton and textArea
this._disposables.push(dom.addDisposableListener(this._reviewThreadReplyButton, 'click', _ => this.expandReplyArea()));
this._disposables.push(dom.addDisposableListener(this._reviewThreadReplyButton, 'focus', _ => this.expandReplyArea()));
this._disposables.add(dom.addDisposableListener(this._reviewThreadReplyButton, 'click', _ => this.expandReplyArea()));
this._disposables.add(dom.addDisposableListener(this._reviewThreadReplyButton, 'focus', _ => this.expandReplyArea()));
this._commentEditor.onDidBlurEditorWidget(() => {
if (this._commentEditor.getModel()!.getValueLength() === 0 && dom.hasClass(this._commentForm, 'expand')) {
@@ -963,6 +694,13 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
const frameThickness = Math.round(lineHeight / 9) * 2;
const computedLinesNumber = Math.ceil((headHeight + dimensions.height + arrowHeight + frameThickness + 8 /** margin bottom to avoid margin collapse */) / lineHeight);
let currentPosition = this.getPosition();
if (this._viewZone && currentPosition && currentPosition.lineNumber !== this._viewZone.afterLineNumber) {
this._viewZone.afterLineNumber = currentPosition.lineNumber;
}
this._relayout(computedLinesNumber);
}
}
@@ -1150,7 +888,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this._commentGlyph = undefined;
}
this._globalToDispose.forEach(global => global.dispose());
this._globalToDispose.dispose();
this._commentThreadDisposables.forEach(global => global.dispose());
this._submitActionsDisposables.forEach(local => local.dispose());
this._onDidClose.fire(undefined);

View File

@@ -3,40 +3,39 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/review';
import * as nls from 'vs/nls';
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
import { $ } from 'vs/base/browser/dom';
import { findFirstInSorted, coalesce } from 'vs/base/common/arrays';
import { Action, IAction } from 'vs/base/common/actions';
import { coalesce, findFirstInSorted } from 'vs/base/common/arrays';
import { CancelablePromise, createCancelablePromise, Delayer } from 'vs/base/common/async';
import { onUnexpectedError } from 'vs/base/common/errors';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ICodeEditor, IEditorMouseEvent, IViewZone, MouseTargetType, isDiffEditor, isCodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
import { registerEditorContribution, EditorAction, registerEditorAction } from 'vs/editor/browser/editorExtensions';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import 'vs/css!./media/review';
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
import { IActiveCodeEditor, ICodeEditor, IEditorMouseEvent, isCodeEditor, isDiffEditor, IViewZone, MouseTargetType } from 'vs/editor/browser/editorBrowser';
import { EditorAction, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { IEditorContribution, IModelChangedEvent } from 'vs/editor/common/editorCommon';
import { IRange, Range } from 'vs/editor/common/core/range';
import { IEditorContribution, IModelChangedEvent } from 'vs/editor/common/editorCommon';
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 { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import * as nls from 'vs/nls';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
import { editorForeground } from 'vs/platform/theme/common/colorRegistry';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { ReviewZoneWidget, COMMENTEDITOR_DECORATION_KEY } from 'vs/workbench/contrib/comments/browser/commentThreadWidget';
import { ICommentService, ICommentInfo } from 'vs/workbench/contrib/comments/browser/commentService';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { IModelDecorationOptions } from 'vs/editor/common/model';
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { CancelablePromise, createCancelablePromise, Delayer } from 'vs/base/common/async';
import { STATUS_BAR_ITEM_ACTIVE_BACKGROUND, STATUS_BAR_ITEM_HOVER_BACKGROUND } from 'vs/workbench/common/theme';
import { overviewRulerCommentingRangeForeground } from 'vs/workbench/contrib/comments/browser/commentGlyphWidget';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { STATUS_BAR_ITEM_HOVER_BACKGROUND, STATUS_BAR_ITEM_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ICommentInfo, ICommentService } from 'vs/workbench/contrib/comments/browser/commentService';
import { COMMENTEDITOR_DECORATION_KEY, ReviewZoneWidget } from 'vs/workbench/contrib/comments/browser/commentThreadWidget';
import { ctxCommentEditorFocused, SimpleCommentEditor } from 'vs/workbench/contrib/comments/browser/simpleCommentEditor';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IAction, Action } from 'vs/base/common/actions';
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
import { IQuickInputService, QuickPickInput, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
export const ID = 'editor.contrib.review';
@@ -64,7 +63,7 @@ class CommentingRangeDecoration {
return this._decorationId;
}
constructor(private _editor: ICodeEditor, private _ownerId: string, private _extensionId: string | undefined, private _label: string | undefined, private _range: IRange, private _reply: modes.Command | undefined, commentingOptions: ModelDecorationOptions, private commentingRangesInfo?: modes.CommentingRanges) {
constructor(private _editor: ICodeEditor, private _ownerId: string, private _extensionId: string | undefined, private _label: string | undefined, private _range: IRange, commentingOptions: ModelDecorationOptions, private commentingRangesInfo: modes.CommentingRanges) {
const startLineNumber = _range.startLineNumber;
const endLineNumber = _range.endLineNumber;
let commentingRangeDecorations = [{
@@ -81,11 +80,10 @@ class CommentingRangeDecoration {
}
}
public getCommentAction(): { replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined } {
public getCommentAction(): { ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges } {
return {
extensionId: this._extensionId,
label: this._label,
replyCommand: this._reply,
ownerId: this._ownerId,
commentingRangesInfo: this.commentingRangesInfo
};
@@ -122,15 +120,9 @@ class CommentingRangeDecorator {
let commentingRangeDecorations: CommentingRangeDecoration[] = [];
for (const info of commentInfos) {
if (Array.isArray(info.commentingRanges)) {
info.commentingRanges.forEach(range => {
commentingRangeDecorations.push(new CommentingRangeDecoration(editor, info.owner, info.extensionId, info.label, range, info.reply, this.decorationOptions));
});
} else {
(info.commentingRanges ? info.commentingRanges.ranges : []).forEach(range => {
commentingRangeDecorations.push(new CommentingRangeDecoration(editor, info.owner, info.extensionId, info.label, range, undefined, this.decorationOptions, info.commentingRanges as modes.CommentingRanges));
});
}
info.commentingRanges.ranges.forEach(range => {
commentingRangeDecorations.push(new CommentingRangeDecoration(editor, info.owner, info.extensionId, info.label, range, this.decorationOptions, info.commentingRanges));
});
}
let oldDecorations = this.commentingRangeDecorations.map(decoration => decoration.id);
@@ -161,7 +153,6 @@ export class ReviewController implements IEditorContribution {
private globalToDispose: IDisposable[];
private localToDispose: IDisposable[];
private editor: ICodeEditor;
private _newCommentWidget?: ReviewZoneWidget;
private _commentWidgets: ReviewZoneWidget[];
private _commentInfos: ICommentInfo[];
private _commentingRangeDecorator: CommentingRangeDecorator;
@@ -172,13 +163,11 @@ export class ReviewController implements IEditorContribution {
private _emptyThreadsToAddQueue: [number, IEditorMouseEvent | undefined][] = [];
private _computeCommentingRangePromise: CancelablePromise<ICommentInfo[]> | null;
private _computeCommentingRangeScheduler: Delayer<Array<ICommentInfo | null>> | null;
private _pendingCommentCache: { [key: number]: { [key: string]: string } };
private _pendingNewCommentCache: { [key: string]: { lineNumber: number, replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, pendingComment: string, draftMode: modes.DraftMode | undefined } };
private _pendingCommentCache: { [key: string]: { [key: string]: string } };
constructor(
editor: ICodeEditor,
@ICommentService private readonly commentService: ICommentService,
@INotificationService private readonly notificationService: INotificationService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICodeEditorService private readonly codeEditorService: ICodeEditorService,
@IContextMenuService readonly contextMenuService: IContextMenuService,
@@ -190,18 +179,11 @@ export class ReviewController implements IEditorContribution {
this._commentInfos = [];
this._commentWidgets = [];
this._pendingCommentCache = {};
this._pendingNewCommentCache = {};
this._computePromise = null;
this._commentingRangeDecorator = new CommentingRangeDecorator();
this.globalToDispose.push(this.commentService.onDidDeleteDataProvider(ownerId => {
// Remove new comment widget and glyph, refresh comments
if (this._newCommentWidget && this._newCommentWidget.owner === ownerId) {
this._newCommentWidget.dispose();
this._newCommentWidget = undefined;
}
delete this._pendingCommentCache[ownerId];
this.beginCompute();
}));
@@ -342,49 +324,14 @@ export class ReviewController implements IEditorContribution {
this._commentWidgets.forEach(widget => widget.dispose());
if (this._newCommentWidget) {
this._newCommentWidget.dispose();
this._newCommentWidget = undefined;
}
this.editor = null!; // Strict null override — nulling out in dispose
}
public onModelChanged(e: IModelChangedEvent): void {
this.localToDispose = dispose(this.localToDispose);
if (this._newCommentWidget) {
let pendingNewComment = this._newCommentWidget.getPendingComment();
if (e.oldModelUrl) {
if (pendingNewComment) {
// we can't fetch zone widget's position as the model is already gone
const position = this._newCommentWidget.getPosition();
if (position) {
this._pendingNewCommentCache[e.oldModelUrl.toString()] = {
lineNumber: position.lineNumber,
ownerId: this._newCommentWidget.owner,
extensionId: this._newCommentWidget.extensionId,
replyCommand: this._newCommentWidget.commentThread.reply,
pendingComment: pendingNewComment,
draftMode: this._newCommentWidget.draftMode
};
}
} else {
// clear cache if it is empty
delete this._pendingNewCommentCache[e.oldModelUrl.toString()];
}
}
this._newCommentWidget.dispose();
this._newCommentWidget = undefined;
}
this.removeCommentWidgetsAndStoreCache();
if (e.newModelUrl && this._pendingNewCommentCache[e.newModelUrl.toString()]) {
let newCommentCache = this._pendingNewCommentCache[e.newModelUrl.toString()];
this.addComment(newCommentCache.lineNumber, newCommentCache.replyCommand, newCommentCache.ownerId, newCommentCache.extensionId, newCommentCache.draftMode, newCommentCache.pendingComment);
}
this.localToDispose.push(this.editor.onMouseDown(e => this.onEditorMouseDown(e)));
this.localToDispose.push(this.editor.onMouseUp(e => this.onEditorMouseUp(e)));
@@ -400,12 +347,16 @@ export class ReviewController implements IEditorContribution {
this.localToDispose.push(this.editor.onDidChangeModelContent(async () => {
this.beginComputeCommentingRanges();
}));
this.localToDispose.push(this.commentService.onDidUpdateCommentThreads(e => {
this.localToDispose.push(this.commentService.onDidUpdateCommentThreads(async e => {
const editorURI = this.editor && this.editor.hasModel() && this.editor.getModel().uri;
if (!editorURI) {
return;
}
if (this._computePromise) {
await this._computePromise;
}
let commentInfo = this._commentInfos.filter(info => info.owner === e.owner);
if (!commentInfo || !commentInfo.length) {
return;
@@ -414,13 +365,6 @@ export class ReviewController implements IEditorContribution {
let added = e.added.filter(thread => thread.resource && thread.resource.toString() === editorURI.toString());
let removed = e.removed.filter(thread => thread.resource && thread.resource.toString() === editorURI.toString());
let changed = e.changed.filter(thread => thread.resource && thread.resource.toString() === editorURI.toString());
let draftMode = e.draftMode;
commentInfo.forEach(info => info.draftMode = draftMode);
this._commentWidgets.filter(ZoneWidget => ZoneWidget.owner === e.owner).forEach(widget => widget.updateDraftMode(draftMode));
if (this._newCommentWidget && this._newCommentWidget.owner === e.owner) {
this._newCommentWidget.updateDraftMode(draftMode);
}
removed.forEach(thread => {
let matchedZones = this._commentWidgets.filter(zoneWidget => zoneWidget.owner === e.owner && zoneWidget.commentThread.threadId === thread.threadId && zoneWidget.commentThread.threadId !== '');
@@ -452,8 +396,8 @@ export class ReviewController implements IEditorContribution {
return;
}
const pendingCommentText = this._pendingCommentCache[e.owner] && this._pendingCommentCache[e.owner][thread.threadId];
this.displayCommentThread(e.owner, thread, pendingCommentText, draftMode);
const pendingCommentText = this._pendingCommentCache[e.owner] && this._pendingCommentCache[e.owner][thread.threadId!];
this.displayCommentThread(e.owner, thread, pendingCommentText);
this._commentInfos.filter(info => info.owner === e.owner)[0].threads.push(thread);
});
@@ -462,56 +406,12 @@ export class ReviewController implements IEditorContribution {
this.beginCompute();
}
private displayCommentThread(owner: string, thread: modes.CommentThread | modes.CommentThread2, pendingComment: string | null, draftMode: modes.DraftMode | undefined): void {
const zoneWidget = this.instantiationService.createInstance(ReviewZoneWidget, this.editor, owner, thread, pendingComment, draftMode);
private displayCommentThread(owner: string, thread: modes.CommentThread, pendingComment: string | null): void {
const zoneWidget = this.instantiationService.createInstance(ReviewZoneWidget, this.editor, owner, thread, pendingComment);
zoneWidget.display(thread.range.startLineNumber);
this._commentWidgets.push(zoneWidget);
}
private addComment(lineNumber: number, replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, draftMode: modes.DraftMode | undefined, pendingComment: string | null) {
if (this._newCommentWidget) {
this.notificationService.warn(`Please submit the comment at line ${this._newCommentWidget.position ? this._newCommentWidget.position.lineNumber : -1} before creating a new one.`);
return;
}
// add new comment
this._newCommentWidget = this.instantiationService.createInstance(ReviewZoneWidget, this.editor, ownerId, {
extensionId: extensionId,
threadId: null,
resource: null,
comments: [],
range: {
startLineNumber: lineNumber,
startColumn: 0,
endLineNumber: lineNumber,
endColumn: 0
},
reply: replyCommand,
collapsibleState: modes.CommentThreadCollapsibleState.Expanded,
}, pendingComment, draftMode);
this.localToDispose.push(this._newCommentWidget!.onDidClose(e => {
this.clearNewCommentWidget();
}));
this.localToDispose.push(this._newCommentWidget!.onDidCreateThread(commentWidget => {
const thread = commentWidget.commentThread;
this._commentWidgets.push(commentWidget);
this._commentInfos.filter(info => info.owner === commentWidget.owner)[0].threads.push(thread);
this.clearNewCommentWidget();
}));
this._newCommentWidget!.display(lineNumber);
}
private clearNewCommentWidget() {
this._newCommentWidget = undefined;
if (this.editor && this.editor.hasModel()) {
delete this._pendingNewCommentCache[this.editor.getModel().uri.toString()];
}
}
private onEditorMouseDown(e: IEditorMouseEvent): void {
this.mouseDownInfo = null;
@@ -623,22 +523,22 @@ export class ReviewController implements IEditorContribution {
const commentInfos = newCommentInfos.filter(info => info.ownerId === pick.id);
if (commentInfos.length) {
const { replyCommand, ownerId, extensionId, commentingRangesInfo } = commentInfos[0];
this.addCommentAtLine2(lineNumber, replyCommand, ownerId, extensionId, commentingRangesInfo);
const { ownerId } = commentInfos[0];
this.addCommentAtLine2(lineNumber, ownerId);
}
}).then(() => {
this._addInProgress = false;
});
}
} else {
const { replyCommand, ownerId, extensionId, commentingRangesInfo } = newCommentInfos[0]!;
this.addCommentAtLine2(lineNumber, replyCommand, ownerId, extensionId, commentingRangesInfo);
const { ownerId } = newCommentInfos[0]!;
this.addCommentAtLine2(lineNumber, ownerId);
}
return Promise.resolve();
}
private getCommentProvidersQuickPicks(commentInfos: { replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined }[]) {
private getCommentProvidersQuickPicks(commentInfos: { ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined }[]) {
const picks: QuickPickInput[] = commentInfos.map((commentInfo) => {
const { ownerId, extensionId, label } = commentInfo;
@@ -651,11 +551,11 @@ export class ReviewController implements IEditorContribution {
return picks;
}
private getContextMenuActions(commentInfos: { replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined }[], lineNumber: number): (IAction | ContextSubMenu)[] {
private getContextMenuActions(commentInfos: { ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges }[], lineNumber: number): (IAction | ContextSubMenu)[] {
const actions: (IAction | ContextSubMenu)[] = [];
commentInfos.forEach(commentInfo => {
const { replyCommand, ownerId, extensionId, label, commentingRangesInfo } = commentInfo;
const { ownerId, extensionId, label } = commentInfo;
actions.push(new Action(
'addCommentThread',
@@ -663,7 +563,7 @@ export class ReviewController implements IEditorContribution {
undefined,
true,
() => {
this.addCommentAtLine2(lineNumber, replyCommand, ownerId, extensionId, commentingRangesInfo);
this.addCommentAtLine2(lineNumber, ownerId);
return Promise.resolve();
}
));
@@ -671,37 +571,11 @@ export class ReviewController implements IEditorContribution {
return actions;
}
public addCommentAtLine2(lineNumber: number, replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined) {
if (commentingRangesInfo) {
let range = new Range(lineNumber, 1, lineNumber, 1);
if (commentingRangesInfo.newCommentThreadCallback) {
return commentingRangesInfo.newCommentThreadCallback(this.editor.getModel()!.uri, range)
.then(_ => {
this.processNextThreadToAdd();
})
.catch(e => {
this.notificationService.error(nls.localize('commentThreadAddFailure', "Adding a new comment thread failed: {0}.", e.message));
this.processNextThreadToAdd();
});
} else {
// latest api, no comments creation callback
this.commentService.createCommentThreadTemplate(ownerId, this.editor.getModel()!.uri, range);
this.processNextThreadToAdd();
return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check
}
} else {
const commentInfo = this._commentInfos.filter(info => info.owner === ownerId);
if (!commentInfo || !commentInfo.length) {
this._addInProgress = false;
return Promise.resolve();
}
const draftMode = commentInfo[0].draftMode;
this.addComment(lineNumber, replyCommand, ownerId, extensionId, draftMode, null);
this._addInProgress = false;
}
return Promise.resolve();
public addCommentAtLine2(lineNumber: number, ownerId: string) {
const range = new Range(lineNumber, 1, lineNumber, 1);
this.commentService.createCommentThreadTemplate(ownerId, this.editor.getModel()!.uri, range);
this.processNextThreadToAdd();
return;
}
private setComments(commentInfos: ICommentInfo[]): void {
@@ -750,30 +624,21 @@ export class ReviewController implements IEditorContribution {
info.threads.forEach(thread => {
let pendingComment: string | null = null;
if (providerCacheStore) {
pendingComment = providerCacheStore[thread.threadId];
pendingComment = providerCacheStore[thread.threadId!];
}
if (pendingComment) {
thread.collapsibleState = modes.CommentThreadCollapsibleState.Expanded;
}
this.displayCommentThread(info.owner, thread, pendingComment, info.draftMode);
this.displayCommentThread(info.owner, thread, pendingComment);
});
});
const commentingRanges: IRange[] = [];
this._commentInfos.forEach(info => {
commentingRanges.push(...(Array.isArray(info.commentingRanges) ? info.commentingRanges : info.commentingRanges ? info.commentingRanges.ranges : []));
});
this._commentingRangeDecorator.update(this.editor, this._commentInfos);
}
public closeWidget(): void {
if (this._newCommentWidget) {
this._newCommentWidget.dispose();
this._newCommentWidget = undefined;
}
if (this._commentWidgets) {
this._commentWidgets.forEach(widget => widget.hide());
}
@@ -793,10 +658,10 @@ export class ReviewController implements IEditorContribution {
this._pendingCommentCache[zone.owner] = {};
}
this._pendingCommentCache[zone.owner][zone.commentThread.threadId] = pendingComment;
this._pendingCommentCache[zone.owner][zone.commentThread.threadId!] = pendingComment;
} else {
if (providerCacheStore) {
delete providerCacheStore[zone.commentThread.threadId];
delete providerCacheStore[zone.commentThread.threadId!];
}
}

View File

@@ -8,7 +8,7 @@ import * as dom from 'vs/base/browser/dom';
import { IAction } from 'vs/base/common/actions';
import { Event } from 'vs/base/common/event';
import { CollapseAllAction, DefaultAccessibilityProvider, DefaultController, DefaultDragAndDrop } from 'vs/base/parts/tree/browser/treeDefaults';
import { isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TreeResourceNavigator, WorkbenchTree } from 'vs/platform/list/browser/listService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@@ -19,7 +19,7 @@ import { ReviewController } from 'vs/workbench/contrib/comments/browser/comments
import { CommentsDataFilter, CommentsDataSource, CommentsModelRenderer } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer';
import { ICommentService, IWorkspaceCommentThreadsEvent } from 'vs/workbench/contrib/comments/browser/commentService';
import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { textLinkForeground, textLinkActiveForeground, focusBorder, textPreformatForeground } from 'vs/platform/theme/common/colorRegistry';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IStorageService } from 'vs/platform/storage/common/storage';
@@ -42,7 +42,6 @@ export class CommentsPanel extends Panel {
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICommentService private readonly commentService: ICommentService,
@IEditorService private readonly editorService: IEditorService,
@ICommandService private readonly commandService: ICommandService,
@IOpenerService private readonly openerService: IOpenerService,
@ITelemetryService telemetryService: ITelemetryService,
@IThemeService themeService: IThemeService,
@@ -189,55 +188,22 @@ export class CommentsPanel extends Panel {
const threadToReveal = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].threadId : element.threadId;
const commentToReveal = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].comment : element.comment;
if (commentToReveal.selectCommand) {
this.commandService.executeCommand(commentToReveal.selectCommand.id, ...(commentToReveal.selectCommand.arguments || [])).then(_ => {
let activeWidget = this.editorService.activeTextEditorWidget;
if (isDiffEditor(activeWidget)) {
const originalEditorWidget = activeWidget.getOriginalEditor();
const modifiedEditorWidget = activeWidget.getModifiedEditor();
let controller;
if (originalEditorWidget.getModel()!.uri.toString() === element.resource.toString()) {
controller = ReviewController.get(originalEditorWidget);
} else if (modifiedEditorWidget.getModel()!.uri.toString() === element.resource.toString()) {
controller = ReviewController.get(modifiedEditorWidget);
}
if (controller) {
controller.revealCommentThread(threadToReveal, commentToReveal.commentId, true);
}
} else {
let activeEditor = this.editorService.activeEditor;
let currentActiveResource = activeEditor ? activeEditor.getResource() : undefined;
if (currentActiveResource && currentActiveResource.toString() === element.resource.toString()) {
const control = this.editorService.activeTextEditorWidget;
if (threadToReveal && isCodeEditor(control)) {
const controller = ReviewController.get(control);
controller.revealCommentThread(threadToReveal, commentToReveal.commentId, true);
}
}
this.editorService.openEditor({
resource: element.resource,
options: {
pinned: pinned,
preserveFocus: preserveFocus,
selection: range
}
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP).then(editor => {
if (editor) {
const control = editor.getControl();
if (threadToReveal && isCodeEditor(control)) {
const controller = ReviewController.get(control);
controller.revealCommentThread(threadToReveal, commentToReveal.commentId, true);
}
return true;
});
} else {
this.editorService.openEditor({
resource: element.resource,
options: {
pinned: pinned,
preserveFocus: preserveFocus,
selection: range
}
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP).then(editor => {
if (editor) {
const control = editor.getControl();
if (threadToReveal && isCodeEditor(control)) {
const controller = ReviewController.get(control);
controller.revealCommentThread(threadToReveal, commentToReveal.commentId, true);
}
}
});
}
}
});
return true;
}

View File

@@ -7,7 +7,7 @@ import * as dom from 'vs/base/browser/dom';
import * as nls from 'vs/nls';
import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Disposable } from 'vs/base/common/lifecycle';
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { IDataSource, IFilter, IRenderer as ITreeRenderer, ITree } from 'vs/base/parts/tree/browser/tree';
import { IOpenerService } from 'vs/platform/opener/common/opener';
@@ -62,7 +62,7 @@ interface ICommentThreadTemplateData {
icon: HTMLImageElement;
userName: HTMLSpanElement;
commentText: HTMLElement;
disposables: Disposable[];
disposables: IDisposable[];
}
export class CommentsModelRenderer implements ITreeRenderer {
@@ -144,6 +144,8 @@ export class CommentsModelRenderer implements ITreeRenderer {
private renderCommentElement(tree: ITree, element: CommentNode, templateData: ICommentThreadTemplateData) {
templateData.userName.textContent = element.comment.userName;
templateData.commentText.innerHTML = '';
const disposables = new DisposableStore();
templateData.disposables.push(disposables);
const renderedComment = renderMarkdown(element.comment.body, {
inline: true,
actionHandler: {
@@ -155,7 +157,7 @@ export class CommentsModelRenderer implements ITreeRenderer {
// ignore
}
},
disposeables: templateData.disposables
disposeables: disposables
}
});

View File

@@ -0,0 +1,3 @@
<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 6.04048L3.02022 11.0203L2.31311 10.3132L7.64645 4.97982L8.35355 4.97982L13.6869 10.3132L12.9798 11.0203L8 6.04048Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 288 B

View File

@@ -0,0 +1,3 @@
<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 6.04048L3.02022 11.0203L2.31311 10.3132L7.64645 4.97982L8.35355 4.97982L13.6869 10.3132L12.9798 11.0203L8 6.04048Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 286 B

View File

@@ -0,0 +1,3 @@
<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 6.04048L3.02022 11.0203L2.31311 10.3132L7.64645 4.97982L8.35355 4.97982L13.6869 10.3132L12.9798 11.0203L8 6.04048Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 288 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" version="1.1" aria-hidden="true" height="16" width="16"><path fill="#C5C5C5" fill-rule="evenodd" d="M14 1H2c-.55 0-1 .45-1 1v8c0 .55.45 1 1 1h2v3.5L7.5 11H14c.55 0 1-.45 1-1V2c0-.55-.45-1-1-1zm0 9H7l-2 2v-2H2V2h12v8z"></path></svg>

Before

Width:  |  Height:  |  Size: 293 B

View File

@@ -0,0 +1,3 @@
<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 8.70714L11.6464 12.3536L12.3536 11.6465L8.70711 8.00004L12.3536 4.35359L11.6464 3.64648L8 7.29293L4.35355 3.64648L3.64645 4.35359L7.29289 8.00004L3.64645 11.6465L4.35355 12.3536L8 8.70714Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 362 B

View File

@@ -0,0 +1,3 @@
<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 8.70714L11.6464 12.3536L12.3536 11.6465L8.70711 8.00004L12.3536 4.35359L11.6464 3.64648L8 7.29293L4.35355 3.64648L3.64645 4.35359L7.29289 8.00004L3.64645 11.6465L4.35355 12.3536L8 8.70714Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 362 B

View File

@@ -0,0 +1,3 @@
<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 8.70714L11.6464 12.3536L12.3536 11.6465L8.70711 8.00004L12.3536 4.35359L11.6464 3.64648L8 7.29293L4.35355 3.64648L3.64645 4.35359L7.29289 8.00004L3.64645 11.6465L4.35355 12.3536L8 8.70714Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 362 B

View File

@@ -0,0 +1,4 @@
<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.40706 15L1 13.5929L3.35721 9.46781L3.52339 9.25025L11.7736 1L13.2321 1L15 2.76791V4.22636L6.74975 12.4766L6.53219 12.6428L2.40706 15ZM2.40706 13.5929L6.02053 11.7474L14.2708 3.49714L12.5029 1.72923L4.25262 9.97947L2.40706 13.5929Z" fill="#C5C5C5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.64645 12.3536L3.64645 10.3536L4.35355 9.64648L6.35355 11.6465L5.64645 12.3536Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 553 B

View File

@@ -0,0 +1,4 @@
<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.40706 15L1 13.5929L3.35721 9.46781L3.52339 9.25025L11.7736 1L13.2321 1L15 2.76791V4.22636L6.74975 12.4766L6.53219 12.6428L2.40706 15ZM2.40706 13.5929L6.02053 11.7474L14.2708 3.49714L12.5029 1.72923L4.25262 9.97947L2.40706 13.5929Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.64645 12.3536L3.64645 10.3536L4.35355 9.64648L6.35355 11.6465L5.64645 12.3536Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 549 B

View File

@@ -0,0 +1,4 @@
<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.40706 15L1 13.5929L3.35721 9.46781L3.52339 9.25025L11.7736 1L13.2321 1L15 2.76791V4.22636L6.74975 12.4766L6.53219 12.6428L2.40706 15ZM2.40706 13.5929L6.02053 11.7474L14.2708 3.49714L12.5029 1.72923L4.25262 9.97947L2.40706 13.5929Z" fill="#424242"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.64645 12.3536L3.64645 10.3536L4.35355 9.64648L6.35355 11.6465L5.64645 12.3536Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 553 B

View File

@@ -1,4 +1,3 @@
<svg width="26" height="16" viewBox="0 0 26 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 8.25008H4.08333V11.1667H2.91667V8.25008H0V7.08341H2.91667V4.16675H4.08333V7.08341H7V8.25008V8.25008Z" fill="#C8C8C8"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M18 0C13.58 0 10 3.58 10 8C10 12.42 13.58 16 18 16C22.42 16 26 12.42 26 8C26 3.58 22.42 0 18 0V0ZM22.81 12.81C22.18 13.44 21.45 13.92 20.64 14.26C19.81 14.62 18.92 14.79 18 14.79C17.08 14.79 16.19 14.62 15.36 14.26C14.55 13.92 13.81 13.43 13.19 12.81C12.57 12.19 12.08 11.45 11.74 10.64C11.38 9.81 11.21 8.92 11.21 8C11.21 7.08 11.38 6.19 11.74 5.36C12.08 4.55 12.57 3.81 13.19 3.19C13.81 2.57 14.55 2.08 15.36 1.74C16.19 1.38 17.08 1.21 18 1.21C18.92 1.21 19.81 1.38 20.64 1.74C21.45 2.08 22.19 2.57 22.81 3.19C23.43 3.81 23.92 4.55 24.26 5.36C24.62 6.19 24.79 7.08 24.79 8C24.79 8.92 24.62 9.81 24.26 10.64C23.92 11.45 23.43 12.19 22.81 12.81V12.81ZM14 6.8V6.21C14 5.55 14.53 5.02 15.2 5.02H15.79C16.45 5.02 16.98 5.55 16.98 6.21V6.8C16.98 7.47 16.45 8 15.79 8H15.2C14.53 8 14 7.47 14 6.8V6.8ZM19 6.8V6.21C19 5.55 19.53 5.02 20.2 5.02H20.79C21.45 5.02 21.98 5.55 21.98 6.21V6.8C21.98 7.47 21.45 8 20.79 8H20.2C19.53 8 19 7.47 19 6.8V6.8ZM23 10C22.28 11.88 20.09 13 18 13C15.91 13 13.72 11.87 13 10C12.86 9.61 13.23 9 13.66 9H22.25C22.66 9 23.14 9.61 23 10V10Z" fill="#C8C8C8"/>
</svg>
<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="M13 0H12V3H9V4H12V7H13V4H16V3H13V0ZM5 8C5 8.55229 4.55228 9 4 9C3.44772 9 3 8.55229 3 8C3 7.44772 3.44772 7 4 7C4.55228 7 5 7.44772 5 8ZM9 9C9.55229 9 10 8.55229 10 8C10 7.44772 9.55229 7 9 7C8.44771 7 8 7.44772 8 8C8 8.55229 8.44771 9 9 9ZM8.67198 10.7388C8.24133 11.4922 7.42996 12 6.5 12C5.6403 12 4.88195 11.566 4.43204 10.9052L3.56421 11.4063C4.18842 12.3656 5.27013 13 6.5 13C7.80007 13 8.93458 12.2911 9.53815 11.2389L8.67198 10.7388ZM8 3.17393C7.51848 3.06019 7.01627 3 6.5 3C2.91015 3 0 5.91015 0 9.5C0 13.0899 2.91015 16 6.5 16C10.0899 16 13 13.0899 13 9.5C13 8.98373 12.9398 8.48152 12.8261 8H11.793C11.9278 8.47683 12 8.97999 12 9.5C12 12.5376 9.53757 15 6.5 15C3.46243 15 1 12.5376 1 9.5C1 6.46243 3.46243 4 6.5 4C7.02001 4 7.52317 4.07217 8 4.20703V3.17393Z" fill="#C5C5C5"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 942 B

View File

@@ -1,4 +1,3 @@
<svg width="26" height="16" viewBox="0 0 26 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 8.25008H4.08333V11.1667H2.91667V8.25008H0V7.08341H2.91667V4.16675H4.08333V7.08341H7V8.25008V8.25008Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M18 0C13.58 0 10 3.58 10 8C10 12.42 13.58 16 18 16C22.42 16 26 12.42 26 8C26 3.58 22.42 0 18 0V0ZM22.81 12.81C22.18 13.44 21.45 13.92 20.64 14.26C19.81 14.62 18.92 14.79 18 14.79C17.08 14.79 16.19 14.62 15.36 14.26C14.55 13.92 13.81 13.43 13.19 12.81C12.57 12.19 12.08 11.45 11.74 10.64C11.38 9.81 11.21 8.92 11.21 8C11.21 7.08 11.38 6.19 11.74 5.36C12.08 4.55 12.57 3.81 13.19 3.19C13.81 2.57 14.55 2.08 15.36 1.74C16.19 1.38 17.08 1.21 18 1.21C18.92 1.21 19.81 1.38 20.64 1.74C21.45 2.08 22.19 2.57 22.81 3.19C23.43 3.81 23.92 4.55 24.26 5.36C24.62 6.19 24.79 7.08 24.79 8C24.79 8.92 24.62 9.81 24.26 10.64C23.92 11.45 23.43 12.19 22.81 12.81V12.81ZM14 6.8V6.21C14 5.55 14.53 5.02 15.2 5.02H15.79C16.45 5.02 16.98 5.55 16.98 6.21V6.8C16.98 7.47 16.45 8 15.79 8H15.2C14.53 8 14 7.47 14 6.8V6.8ZM19 6.8V6.21C19 5.55 19.53 5.02 20.2 5.02H20.79C21.45 5.02 21.98 5.55 21.98 6.21V6.8C21.98 7.47 21.45 8 20.79 8H20.2C19.53 8 19 7.47 19 6.8V6.8ZM23 10C22.28 11.88 20.09 13 18 13C15.91 13 13.72 11.87 13 10C12.86 9.61 13.23 9 13.66 9H22.25C22.66 9 23.14 9.61 23 10V10Z" fill="white"/>
<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="M13 0H12V3H9V4H12V7H13V4H16V3H13V0ZM5 8C5 8.55229 4.55228 9 4 9C3.44772 9 3 8.55229 3 8C3 7.44772 3.44772 7 4 7C4.55228 7 5 7.44772 5 8ZM9 9C9.55229 9 10 8.55229 10 8C10 7.44772 9.55229 7 9 7C8.44771 7 8 7.44772 8 8C8 8.55229 8.44771 9 9 9ZM8.67198 10.7388C8.24133 11.4922 7.42996 12 6.5 12C5.6403 12 4.88195 11.566 4.43204 10.9052L3.56421 11.4063C4.18842 12.3656 5.27013 13 6.5 13C7.80007 13 8.93458 12.2911 9.53815 11.2389L8.67198 10.7388ZM8 3.17393C7.51848 3.06019 7.01627 3 6.5 3C2.91015 3 0 5.91015 0 9.5C0 13.0899 2.91015 16 6.5 16C10.0899 16 13 13.0899 13 9.5C13 8.98373 12.9398 8.48152 12.8261 8H11.793C11.9278 8.47683 12 8.97999 12 9.5C12 12.5376 9.53757 15 6.5 15C3.46243 15 1 12.5376 1 9.5C1 6.46243 3.46243 4 6.5 4C7.02001 4 7.52317 4.07217 8 4.20703V3.17393Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 940 B

View File

@@ -0,0 +1,3 @@
<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="M13 0H12V3H9V4H12V7H13V4H16V3H13V0ZM5 8C5 8.55229 4.55228 9 4 9C3.44772 9 3 8.55229 3 8C3 7.44772 3.44772 7 4 7C4.55228 7 5 7.44772 5 8ZM9 9C9.55229 9 10 8.55229 10 8C10 7.44772 9.55229 7 9 7C8.44771 7 8 7.44772 8 8C8 8.55229 8.44771 9 9 9ZM8.67198 10.7388C8.24133 11.4922 7.42996 12 6.5 12C5.6403 12 4.88195 11.566 4.43204 10.9052L3.56421 11.4063C4.18842 12.3656 5.27013 13 6.5 13C7.80007 13 8.93458 12.2911 9.53815 11.2389L8.67198 10.7388ZM8 3.17393C7.51848 3.06019 7.01627 3 6.5 3C2.91015 3 0 5.91015 0 9.5C0 13.0899 2.91015 16 6.5 16C10.0899 16 13 13.0899 13 9.5C13 8.98373 12.9398 8.48152 12.8261 8H11.793C11.9278 8.47683 12 8.97999 12 9.5C12 12.5376 9.53757 15 6.5 15C3.46243 15 1 12.5376 1 9.5C1 6.46243 3.46243 4 6.5 4C7.02001 4 7.52317 4.07217 8 4.20703V3.17393Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 942 B

View File

@@ -1,4 +0,0 @@
<svg width="26" height="16" viewBox="0 0 26 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 8.25008H4.08333V11.1667H2.91667V8.25008H0V7.08341H2.91667V4.16675H4.08333V7.08341H7V8.25008V8.25008Z" fill="#4B4B4B"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M18 0C13.58 0 10 3.58 10 8C10 12.42 13.58 16 18 16C22.42 16 26 12.42 26 8C26 3.58 22.42 0 18 0V0ZM22.81 12.81C22.18 13.44 21.45 13.92 20.64 14.26C19.81 14.62 18.92 14.79 18 14.79C17.08 14.79 16.19 14.62 15.36 14.26C14.55 13.92 13.81 13.43 13.19 12.81C12.57 12.19 12.08 11.45 11.74 10.64C11.38 9.81 11.21 8.92 11.21 8C11.21 7.08 11.38 6.19 11.74 5.36C12.08 4.55 12.57 3.81 13.19 3.19C13.81 2.57 14.55 2.08 15.36 1.74C16.19 1.38 17.08 1.21 18 1.21C18.92 1.21 19.81 1.38 20.64 1.74C21.45 2.08 22.19 2.57 22.81 3.19C23.43 3.81 23.92 4.55 24.26 5.36C24.62 6.19 24.79 7.08 24.79 8C24.79 8.92 24.62 9.81 24.26 10.64C23.92 11.45 23.43 12.19 22.81 12.81V12.81ZM14 6.8V6.21C14 5.55 14.53 5.02 15.2 5.02H15.79C16.45 5.02 16.98 5.55 16.98 6.21V6.8C16.98 7.47 16.45 8 15.79 8H15.2C14.53 8 14 7.47 14 6.8V6.8ZM19 6.8V6.21C19 5.55 19.53 5.02 20.2 5.02H20.79C21.45 5.02 21.98 5.55 21.98 6.21V6.8C21.98 7.47 21.45 8 20.79 8H20.2C19.53 8 19 7.47 19 6.8V6.8ZM23 10C22.28 11.88 20.09 13 18 13C15.91 13 13.72 11.87 13 10C12.86 9.61 13.23 9 13.66 9H22.25C22.66 9 23.14 9.61 23 10V10Z" fill="#4B4B4B"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -3,28 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .margin-view-overlays .review {
background-image: url('comment.svg');
cursor: pointer;
background-repeat: no-repeat;
background-position: center center;
}
.monaco-editor .comment-hint {
height: 20px;
width: 20px;
padding-left: 2px;
background: url('comment.svg') center center no-repeat;
}
.monaco-editor .comment-hint.commenting-disabled {
opacity: 0.5;
}
.monaco-editor .comment-hint:hover {
cursor: pointer;
}
.monaco-editor .review-widget {
width: 100%;
position: absolute;
@@ -93,7 +71,6 @@
border-style: none;
}
.monaco-editor .review-widget .body .comment-reactions .monaco-text-button {
margin: 0 7px 0 0;
width: 30px;
@@ -175,9 +152,49 @@
display: inline-block;
}
.monaco-editor .review-widget .head .review-actions > .monaco-action-bar .icon.expand-review-action {
background-image: url("./close-light.svg");
background-size: 16px;
}
.monaco-editor.vs-dark .review-widget .head .review-actions > .monaco-action-bar .icon.expand-review-action {
background-image: url("./close-dark.svg");
}
.monaco-editor.hc-black .review-widget .head .review-actions > .monaco-action-bar .icon.expand-review-action {
background-image: url("./close-hc.svg");
}
.monaco-editor .review-widget .body .review-comment .comment-title .icon.edit {
background-image: url("./edit-light.svg");
background-size: 16px;
}
.monaco-editor.vs-dark .review-widget .body .review-comment .comment-title .icon.edit {
background-image: url("./edit-dark.svg");
}
.monaco-editor.hc-black .review-widget .body .review-comment .comment-title .icon.edit {
background-image: url("./edit-hc.svg");
}
.monaco-editor .review-widget .body .review-comment .comment-title .icon.delete {
background-image: url("./delete-light.svg");
background-size: 16px;
}
.monaco-editor.vs-dark .review-widget .body .review-comment .comment-title .icon.delete {
background-image: url("./delete-dark.svg");
}
.monaco-editor.hc-black .review-widget .body .review-comment .comment-title .icon.delete {
background-image: url("./delete-hc.svg");
}
.monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-reactions .action-item a.action-label.toolbar-toggle-pickReactions {
display: none;
background-image: url(./reaction.svg);
background-image: url("./reaction-light.svg");
background-size: 16px;
width: 26px;
height: 16px;
background-repeat: no-repeat;
@@ -188,20 +205,21 @@
.monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-reactions:hover .action-item a.action-label.toolbar-toggle-pickReactions {
display: inline-block;
background-size: 16px;
}
.monaco-editor.vs-dark .review-widget .body .review-comment .review-comment-contents .comment-reactions .action-item a.action-label.toolbar-toggle-pickReactions {
background-image: url(./reaction-dark.svg);
background-image: url("./reaction-dark.svg");
}
.monaco-editor.hc-black .review-widget .body .review-comment .review-comment-contents .comment-reactions .action-item a.action-label.toolbar-toggle-pickReactions {
background-image: url(./reaction-hc.svg);
background-image: url("./reaction-hc.svg");
}
.monaco-editor .review-widget .body .review-comment .comment-title .action-label {
display: block;
height: 18px;
line-height: 18px;
height: 16px;
line-height: 16px;
min-width: 28px;
background-size: 16px;
background-position: center center;
@@ -209,23 +227,23 @@
}
.monaco-editor .review-widget .body .review-comment .comment-title .action-label.toolbar-toggle-pickReactions {
background-image: url(./reaction.svg);
width: 18px;
height: 18px;
background-size: 100% auto;
background-image: url("./reaction-light.svg");
width: 16px;
height: 16px;
background-size: 16px;
background-position: center;
background-repeat: no-repeat;
}
.monaco-editor.vs-dark .review-widget .body .review-comment .comment-title .action-label.toolbar-toggle-pickReactions {
background-image: url(./reaction-dark.svg);
background-image: url("./reaction-dark.svg");
}
.monaco-editor.hc-black .review-widget .body .review-comment .comment-title .action-label.toolbar-toggle-pickReactions {
background-image: url(./reaction-hc.svg);
background-image: url("./reaction-hc.svg");
}
.monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-reactions .action-item a.action-label{
.monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-reactions .action-item a.action-label {
border: 1px solid transparent;
}
@@ -252,7 +270,7 @@
}
.monaco-editor .review-widget .body .comment-body p:last-child,
.monaco-editor .review-widget .body.comment-body ul:last-child {
.monaco-editor .review-widget .body.comment-body ul:last-child {
margin-bottom: 0;
}
@@ -260,11 +278,11 @@
padding-left: 20px;
}
.monaco-editor .review-widget .body .comment-body li>p {
.monaco-editor .review-widget .body .comment-body li > p {
margin-bottom: 0;
}
.monaco-editor .review-widget .body .comment-body li>ul {
.monaco-editor .review-widget .body .comment-body li > ul {
margin-top: 0;
}
@@ -290,11 +308,11 @@
overflow: hidden;
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;
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;
@@ -406,20 +424,20 @@
padding-right: 2px;
}
.monaco-editor .review-widget .head .review-actions>.monaco-action-bar {
.monaco-editor .review-widget .head .review-actions > .monaco-action-bar {
display: inline-block;
}
.monaco-editor .review-widget .head .review-actions>.monaco-action-bar,
.monaco-editor .review-widget .head .review-actions>.monaco-action-bar>.actions-container {
.monaco-editor .review-widget .head .review-actions > .monaco-action-bar,
.monaco-editor .review-widget .head .review-actions > .monaco-action-bar > .actions-container {
height: 100%;
}
.monaco-editor .review-widget .head .review-actions>.monaco-action-bar .action-item {
.monaco-editor .review-widget .head .review-actions > .monaco-action-bar .action-item {
margin-left: 4px;
}
.monaco-editor .review-widget .head .review-actions>.monaco-action-bar .action-label {
.monaco-editor .review-widget .head .review-actions > .monaco-action-bar .action-label {
width: 16px;
height: 100%;
margin: 0;
@@ -428,15 +446,15 @@
background-position: center center;
}
.monaco-editor .review-widget .head .review-actions>.monaco-action-bar .action-label.octicon {
.monaco-editor .review-widget .head .review-actions > .monaco-action-bar .action-label.octicon {
margin: 0;
}
.monaco-editor .review-widget .head .review-actions .action-label.icon.close-review-action {
background: url('close.svg') center center no-repeat;
background: url("./close.svg") center center no-repeat;
}
.monaco-editor .review-widget>.body {
.monaco-editor .review-widget > .body {
border-top: 1px solid;
position: relative;
}
@@ -450,14 +468,14 @@
.monaco-editor .comment-range-glyph:before {
position: absolute;
content: '';
content: "";
height: 100%;
width: 0;
left: -2px;
transition: width 80ms linear, left 80ms linear;
}
.monaco-editor .margin-view-overlays>div:hover>.comment-range-glyph.comment-diff-added:before,
.monaco-editor .margin-view-overlays > div:hover > .comment-range-glyph.comment-diff-added:before,
.monaco-editor .comment-range-glyph.comment-thread:before {
position: absolute;
height: 100%;
@@ -472,8 +490,8 @@
justify-content: center;
}
.monaco-editor .margin-view-overlays>div:hover>.comment-range-glyph.comment-diff-added:before {
content: '+';
.monaco-editor .margin-view-overlays > div:hover > .comment-range-glyph.comment-diff-added:before {
content: "+";
}
.monaco-editor .comment-range-glyph.comment-thread {
@@ -481,7 +499,7 @@
}
.monaco-editor .comment-range-glyph.comment-thread:before {
content: '◆';
content: "◆";
font-size: 10px;
line-height: 100%;
z-index: 20;

View File

@@ -98,7 +98,7 @@ export class CommentsModel {
const index = firstIndex(matchingResourceData.commentThreads, (commentThread) => commentThread.threadId === thread.threadId);
if (index >= 0) {
matchingResourceData.commentThreads[index] = ResourceWithCommentThreads.createCommentNode(URI.parse(matchingResourceData.id), thread);
} else {
} else if (thread.comments && thread.comments.length) {
matchingResourceData.commentThreads.push(ResourceWithCommentThreads.createCommentNode(URI.parse(matchingResourceData.id), thread));
}
});

View File

@@ -221,4 +221,4 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
disposeTemplate(templateData: IExpressionTemplateData): void {
dispose(templateData.toDispose);
}
}
}

View File

@@ -13,7 +13,7 @@ import { Position, IPosition } from 'vs/editor/common/core/position';
import { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/zoneWidget';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IDebugService, IBreakpoint, BreakpointWidgetContext as Context, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, DEBUG_SCHEME, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, CONTEXT_IN_BREAKPOINT_WIDGET } from 'vs/workbench/contrib/debug/common/debug';
import { IDebugService, IBreakpoint, BreakpointWidgetContext as Context, CONTEXT_BREAKPOINT_WIDGET_VISIBLE, DEBUG_SCHEME, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, CONTEXT_IN_BREAKPOINT_WIDGET, IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug';
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -34,6 +34,7 @@ import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
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';
const $ = dom.$;
const IPrivateBreakpointWidgetService = createDecorator<IPrivateBreakpointWidgetService>('privateBreakopintWidgetService');
@@ -184,13 +185,13 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi
}
if (this.breakpoint) {
this.debugService.updateBreakpoints(this.breakpoint.uri, {
[this.breakpoint.getId()]: {
condition,
hitCondition,
logMessage
}
}, false);
const data = new Map<string, IBreakpointUpdateData>();
data.set(this.breakpoint.getId(), {
condition,
hitCondition,
logMessage
});
this.debugService.updateBreakpoints(this.breakpoint.uri, data, false).then(undefined, onUnexpectedError);
} else {
const model = this.editor.getModel();
if (model) {

View File

@@ -61,7 +61,7 @@ export class BreakpointsView extends ViewletPanel {
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('breakpointsSection', "Breakpoints Section") }, keybindingService, contextMenuService, configurationService);
this.minimumBodySize = this.maximumBodySize = this.getExpandedBodySize();
this.disposables.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange()));
this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange()));
}
public renderBody(container: HTMLElement): void {
@@ -76,14 +76,20 @@ export class BreakpointsView extends ViewletPanel {
], {
identityProvider: { getId: (element: IEnablement) => element.getId() },
multipleSelectionSupport: false,
keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IEnablement) => e }
keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IEnablement) => e },
ariaProvider: {
getSetSize: (_: IEnablement, index: number, listLength: number) => listLength,
getPosInSet: (_: IEnablement, index: number) => index,
getRole: (breakpoint: IEnablement) => 'checkbox',
isChecked: (breakpoint: IEnablement) => breakpoint.enabled
}
}) as WorkbenchList<IEnablement>;
CONTEXT_BREAKPOINTS_FOCUSED.bindTo(this.list.contextKeyService);
this.list.onContextMenu(this.onListContextMenu, this, this.disposables);
this._register(this.list.onContextMenu(this.onListContextMenu, this));
this.disposables.push(this.list.onDidOpen(e => {
this._register(this.list.onDidOpen(e => {
let isSingleClick = false;
let isDoubleClick = false;
let isMiddleClick = false;
@@ -120,7 +126,7 @@ export class BreakpointsView extends ViewletPanel {
this.list.splice(0, this.list.length, this.elements);
this.disposables.push(this.onDidChangeBodyVisibility(visible => {
this._register(this.onDidChangeBodyVisibility(visible => {
if (visible && this.needsRefresh) {
this.onBreakpointsChange();
}
@@ -557,7 +563,6 @@ export function openBreakpointSource(breakpoint: IBreakpoint, sideBySide: boolea
options: {
preserveFocus,
selection,
revealIfVisible: true,
revealIfOpened: true,
revealInCenterIfOutsideViewport: true,
pinned: !preserveFocus

View File

@@ -21,7 +21,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c
import { IViewletPanelOptions, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet';
import { ILabelService } from 'vs/platform/label/common/label';
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
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';
@@ -29,6 +29,7 @@ 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';
import { dispose } from 'vs/base/common/lifecycle';
const $ = dom.$;
@@ -63,7 +64,7 @@ export class CallStackView extends ViewletPanel {
this.callStackItemType = CONTEXT_CALLSTACK_ITEM_TYPE.bindTo(contextKeyService);
this.contributedContextMenu = menuService.createMenu(MenuId.DebugCallStackContext, contextKeyService);
this.disposables.push(this.contributedContextMenu);
this._register(this.contributedContextMenu);
// Create scheduler to prevent unnecessary flashing of tree when reacting to changes
this.onCallStackChangeScheduler = new RunOnceScheduler(() => {
@@ -149,8 +150,8 @@ export class CallStackView extends ViewletPanel {
this.tree.setInput(this.debugService.getModel()).then(undefined, onUnexpectedError);
const callstackNavigator = new TreeResourceNavigator2(this.tree);
this.disposables.push(callstackNavigator);
this.disposables.push(callstackNavigator.onDidOpenResource(e => {
this._register(callstackNavigator);
this._register(callstackNavigator.onDidOpenResource(e => {
if (this.ignoreSelectionChangedEvent) {
return;
}
@@ -189,7 +190,7 @@ export class CallStackView extends ViewletPanel {
}
}));
this.disposables.push(this.debugService.getModel().onDidChangeCallStack(() => {
this._register(this.debugService.getModel().onDidChangeCallStack(() => {
if (!this.isBodyVisible()) {
this.needsRefresh = true;
return;
@@ -200,7 +201,7 @@ export class CallStackView extends ViewletPanel {
}
}));
const onCallStackChange = Event.any<any>(this.debugService.getViewModel().onDidFocusStackFrame, this.debugService.getViewModel().onDidFocusSession);
this.disposables.push(onCallStackChange(() => {
this._register(onCallStackChange(() => {
if (this.ignoreFocusStackFrameEvent) {
return;
}
@@ -211,20 +212,20 @@ export class CallStackView extends ViewletPanel {
this.updateTreeSelection();
}));
this.disposables.push(this.tree.onContextMenu(e => this.onContextMenu(e)));
this._register(this.tree.onContextMenu(e => this.onContextMenu(e)));
// Schedule the update of the call stack tree if the viewlet is opened after a session started #14684
if (this.debugService.state === State.Stopped) {
this.onCallStackChangeScheduler.schedule(0);
}
this.disposables.push(this.onDidChangeBodyVisibility(visible => {
this._register(this.onDidChangeBodyVisibility(visible => {
if (visible && this.needsRefresh) {
this.onCallStackChangeScheduler.schedule();
}
}));
this.disposables.push(this.debugService.onDidNewSession(s => {
this._register(this.debugService.onDidNewSession(s => {
if (s.parentSession) {
// Auto expand sessions that have sub sessions
this.parentSessionToExpand.add(s.parentSession);
@@ -296,14 +297,14 @@ export class CallStackView extends ViewletPanel {
this.callStackItemType.reset();
}
const actions: IAction[] = [];
const actionsDisposable = createAndFillInContextMenuActions(this.contributedContextMenu, { arg: this.getContextForContributedActions(element), shouldForwardArgs: true }, actions, this.contextMenuService);
this.contextMenuService.showContextMenu({
getAnchor: () => e.anchor,
getActions: () => {
const actions: IAction[] = [];
fillInContextMenuActions(this.contributedContextMenu, { arg: this.getContextForContributedActions(element), shouldForwardArgs: true }, actions, this.contextMenuService);
return actions;
},
getActionsContext: () => element
getActions: () => actions,
getActionsContext: () => element,
onHide: () => dispose(actionsDisposable)
});
}

View File

@@ -15,23 +15,21 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionRegistryExtensions } from 'vs/workbench/common/actions';
import { ShowViewletAction, Extensions as ViewletExtensions, ViewletRegistry, ViewletDescriptor } from 'vs/workbench/browser/viewlet';
import { TogglePanelAction, Extensions as PanelExtensions, PanelRegistry, PanelDescriptor } from 'vs/workbench/browser/panel';
import { StatusbarItemDescriptor, IStatusbarRegistry, Extensions as StatusExtensions } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { BreakpointsView } from 'vs/workbench/contrib/debug/browser/breakpointsView';
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_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,
} from 'vs/workbench/contrib/debug/common/debug';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { DebugEditorModelManager } from 'vs/workbench/contrib/debug/browser/debugEditorModelManager';
import { StartAction, AddFunctionBreakpointAction, ConfigureAction, DisableAllBreakpointsAction, EnableAllBreakpointsAction, RemoveAllBreakpointsAction, RunAction, ReapplyBreakpointsAction, SelectAndStartAction } from 'vs/workbench/contrib/debug/browser/debugActions';
import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar';
import * as service from 'vs/workbench/contrib/debug/electron-browser/debugService';
import * as service from 'vs/workbench/contrib/debug/browser/debugService';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, REVERSE_CONTINUE_ID, STEP_BACK_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID } from 'vs/workbench/contrib/debug/browser/debugCommands';
import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, REVERSE_CONTINUE_ID, STEP_BACK_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID } from 'vs/workbench/contrib/debug/browser/debugCommands';
import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen';
import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider';
import { IViewsRegistry, Extensions as ViewExtensions } from 'vs/workbench/common/views';
@@ -40,12 +38,12 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { URI } from 'vs/base/common/uri';
import { DebugViewlet } from 'vs/workbench/contrib/debug/browser/debugViewlet';
import { DebugQuickOpenHandler } from 'vs/workbench/contrib/debug/browser/debugQuickOpen';
import { DebugStatus } from 'vs/workbench/contrib/debug/browser/debugStatus';
import { DebugStatusContribution } from 'vs/workbench/contrib/debug/browser/debugStatus';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { launchSchemaId } from 'vs/workbench/services/configuration/common/configuration';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { LoadedScriptsView } from 'vs/workbench/contrib/debug/browser/loadedScriptsView';
import { TOGGLE_LOG_POINT_ID, TOGGLE_CONDITIONAL_BREAKPOINT_ID, TOGGLE_BREAKPOINT_ID } from 'vs/workbench/contrib/debug/browser/debugEditorActions';
import { TOGGLE_LOG_POINT_ID, TOGGLE_CONDITIONAL_BREAKPOINT_ID, TOGGLE_BREAKPOINT_ID, RunToCursorAction } from 'vs/workbench/contrib/debug/browser/debugEditorActions';
import { WatchExpressionsView } from 'vs/workbench/contrib/debug/browser/watchExpressionsView';
import { VariablesView } from 'vs/workbench/contrib/debug/browser/variablesView';
import { ClearReplAction, Repl } from 'vs/workbench/contrib/debug/browser/repl';
@@ -106,7 +104,6 @@ Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(new PanelDescri
30,
OpenDebugPanelAction.ID
));
Registry.as<PanelRegistry>(PanelExtensions.Panels).setDefaultPanelId(REPL_ID);
// Register default debug views
const viewsRegistry = Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry);
@@ -169,6 +166,10 @@ registerDebugCommandPaletteItem(DISCONNECT_ID, disconnectLabel, CONTEXT_IN_DEBUG
registerDebugCommandPaletteItem(STOP_ID, stopLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated());
registerDebugCommandPaletteItem(CONTINUE_ID, continueLabel, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'));
registerDebugCommandPaletteItem(FOCUS_REPL_ID, nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugFocusConsole' }, 'Focus on Debug Console View'));
registerDebugCommandPaletteItem(JUMP_TO_CURSOR_ID, nls.localize('jumpToCursor', "Jump to Cursor"), ContextKeyExpr.and(CONTEXT_JUMP_TO_CURSOR_SUPPORTED));
registerDebugCommandPaletteItem(RunToCursorAction.ID, RunToCursorAction.LABEL, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')));
registerDebugCommandPaletteItem(TOGGLE_INLINE_BREAKPOINT_ID, nls.localize('inlineBreakpoint', "Inline Breakpoint"));
// Register Quick Open
(Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler(
@@ -249,6 +250,11 @@ configurationRegistry.registerConfiguration({
description: nls.localize('debug.console.lineHeight', "Controls the line height in pixels in the debug console. Use 0 to compute the line height from the font size."),
default: 0
},
'debug.console.wordWrap': {
type: 'boolean',
description: nls.localize('debug.console.wordWrap', "Controls if the lines should wrap in the debug console."),
default: true
},
'launch': {
type: 'object',
description: nls.localize({ comment: ['This is the description for a setting'], key: 'launch' }, "Global debug launch configuration. Should be used as an alternative to 'launch.json' that is shared across workspaces."),
@@ -259,8 +265,7 @@ configurationRegistry.registerConfiguration({
});
// Register Debug Status
const statusBar = Registry.as<IStatusbarRegistry>(StatusExtensions.Statusbar);
statusBar.registerStatusbarItem(new StatusbarItemDescriptor(DebugStatus, StatusbarAlignment.LEFT, 30 /* Low Priority */));
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugStatusContribution, LifecyclePhase.Eventually);
// Debug toolbar
@@ -273,8 +278,8 @@ const registerDebugToolBarItem = (id: string, title: string, icon: string, order
id,
title,
iconLocation: {
light: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}-inverse.svg`))
light: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}-light.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}-dark.svg`))
},
precondition
}
@@ -537,7 +542,9 @@ if (isMacintosh) {
const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr, icon: string) => {
MenuRegistry.appendMenuItem(MenuId.TouchBarContext, {
command: {
id, title, iconLocation: { dark: URI.parse(require.toUrl(`vs/workbench/contrib/debug/electron-browser/media/${icon}`)) }
id,
title,
iconLocation: { dark: URI.parse(require.toUrl(`vs/workbench/contrib/debug/browser/media/${icon}`)) }
},
when,
group: '9_debug',
@@ -549,9 +556,9 @@ if (isMacintosh) {
registerTouchBarEntry(RunAction.ID, RunAction.LABEL, 1, CONTEXT_IN_DEBUG_MODE.toNegated(), 'continue-without-debugging-tb.png');
registerTouchBarEntry(CONTINUE_ID, continueLabel, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'continue-tb.png');
registerTouchBarEntry(PAUSE_ID, pauseLabel, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), 'pause-tb.png');
registerTouchBarEntry(STEP_OVER_ID, stepOverLabel, 2, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepover-tb.png');
registerTouchBarEntry(STEP_INTO_ID, stepIntoLabel, 3, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepinto-tb.png');
registerTouchBarEntry(STEP_OUT_ID, stepOutLabel, 4, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepout-tb.png');
registerTouchBarEntry(STEP_OVER_ID, stepOverLabel, 2, CONTEXT_IN_DEBUG_MODE, 'stepover-tb.png');
registerTouchBarEntry(STEP_INTO_ID, stepIntoLabel, 3, CONTEXT_IN_DEBUG_MODE, 'stepinto-tb.png');
registerTouchBarEntry(STEP_OUT_ID, stepOutLabel, 4, CONTEXT_IN_DEBUG_MODE, 'stepout-tb.png');
registerTouchBarEntry(RESTART_SESSION_ID, restartLabel, 5, CONTEXT_IN_DEBUG_MODE, 'restart-tb.png');
registerTouchBarEntry(STOP_ID, stopLabel, 6, CONTEXT_IN_DEBUG_MODE, 'stop-tb.png');
}

View File

@@ -5,12 +5,14 @@
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
import { RGBA, Color } from 'vs/base/common/color';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ansiColorIdentifiers } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
/**
* @param text The content to stylize.
* @returns An {@link HTMLSpanElement} that contains the potentially stylized text.
*/
export function handleANSIOutput(text: string, linkDetector: LinkDetector): HTMLSpanElement {
export function handleANSIOutput(text: string, linkDetector: LinkDetector, themeService: IThemeService): HTMLSpanElement {
const root: HTMLSpanElement = document.createElement('span');
const textLength: number = text.length;
@@ -105,23 +107,20 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector): HTML
/**
* Change the foreground or background color by clearing the current color
* and adding the new one.
* @param newClass If string or number, new class will be
* `code-(foreground or background)-newClass`. If `undefined`, no new class
* will be added.
* @param colorType If `'foreground'`, will change the foreground color, if
* `'background'`, will change the background color.
* @param customColor If provided, this custom color will be used instead of
* a class-defined color.
* @param color Color to change to. If `undefined` or not provided,
* will clear current color without adding a new one.
*/
function changeColor(newClass: string | number | undefined, colorType: 'foreground' | 'background', customColor?: RGBA): void {
styleNames = styleNames.filter(style => !style.match(new RegExp(`^code-${colorType}-(\\d+|custom)$`)));
if (newClass) {
styleNames.push(`code-${colorType}-${newClass}`);
}
function changeColor(colorType: 'foreground' | 'background', color?: RGBA | undefined): void {
if (colorType === 'foreground') {
customFgColor = customColor;
} else {
customBgColor = customColor;
customFgColor = color;
} else if (colorType === 'background') {
customBgColor = color;
}
styleNames = styleNames.filter(style => style !== `code-${colorType}-colored`);
if (color !== undefined) {
styleNames.push(`code-${colorType}-colored`);
}
}
@@ -137,22 +136,37 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector): HTML
*/
function setBasicFormatters(styleCodes: number[]): void {
for (let code of styleCodes) {
if (code === 0) {
styleNames = [];
} else if (code === 1) {
styleNames.push('code-bold');
} else if (code === 3) {
styleNames.push('code-italic');
} else if (code === 4) {
styleNames.push('code-underline');
} else if ((code >= 30 && code <= 37) || (code >= 90 && code <= 97)) {
changeColor(code, 'foreground');
} else if ((code >= 40 && code <= 47) || (code >= 100 && code <= 107)) {
changeColor(code, 'background');
} else if (code === 39) {
changeColor(undefined, 'foreground');
} else if (code === 49) {
changeColor(undefined, 'background');
switch (code) {
case 0: {
styleNames = [];
customFgColor = undefined;
customBgColor = undefined;
break;
}
case 1: {
styleNames.push('code-bold');
break;
}
case 3: {
styleNames.push('code-italic');
break;
}
case 4: {
styleNames.push('code-underline');
break;
}
case 39: {
changeColor('foreground', undefined);
break;
}
case 49: {
changeColor('background', undefined);
break;
}
default: {
setBasicColor(code);
break;
}
}
}
}
@@ -171,7 +185,7 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector): HTML
styleCodes[3] >= 0 && styleCodes[3] <= 255 &&
styleCodes[4] >= 0 && styleCodes[4] <= 255) {
const customColor = new RGBA(styleCodes[2], styleCodes[3], styleCodes[4]);
changeColor('custom', colorType, customColor);
changeColor(colorType, customColor);
}
}
@@ -188,7 +202,7 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector): HTML
const color = calcANSI8bitColor(colorNumber);
if (color) {
changeColor('custom', colorType, color);
changeColor(colorType, color);
} else if (colorNumber >= 0 && colorNumber <= 15) {
// Need to map to one of the four basic color ranges (30-37, 90-97, 40-47, 100-107)
colorNumber += 30;
@@ -199,7 +213,43 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector): HTML
if (colorType === 'background') {
colorNumber += 10;
}
changeColor(colorNumber, colorType);
setBasicColor(colorNumber);
}
}
/**
* Calculate and set styling for basic bright and dark ANSI color codes. Uses
* theme colors if available. Automatically distinguishes between foreground
* and background colors; does not support color-clearing codes 39 and 49.
* @param styleCode Integer color code on one of the following ranges:
* [30-37, 90-97, 40-47, 100-107]. If not on one of these ranges, will do
* nothing.
*/
function setBasicColor(styleCode: number): void {
const theme = themeService.getTheme();
let colorType: 'foreground' | 'background' | undefined;
let colorIndex: number | undefined;
if (styleCode >= 30 && styleCode <= 37) {
colorIndex = styleCode - 30;
colorType = 'foreground';
} else if (styleCode >= 90 && styleCode <= 97) {
colorIndex = (styleCode - 90) + 8; // High-intensity (bright)
colorType = 'foreground';
} else if (styleCode >= 40 && styleCode <= 47) {
colorIndex = styleCode - 40;
colorType = 'background';
} else if (styleCode >= 100 && styleCode <= 107) {
colorIndex = (styleCode - 100) + 8; // High-intensity (bright)
colorType = 'background';
}
if (colorIndex !== undefined && colorType) {
const colorName = ansiColorIdentifiers[colorIndex];
const color = theme.getColor(colorName);
if (color) {
changeColor(colorType, color.rgba);
}
}
}
}

View File

@@ -199,9 +199,9 @@ export class FocusSessionActionViewItem extends SelectActionViewItem {
) {
super(null, action, [], -1, contextViewService, { ariaLabel: nls.localize('debugSession', 'Debug Session') });
this.toDispose.push(attachSelectBoxStyler(this.selectBox, themeService));
this._register(attachSelectBoxStyler(this.selectBox, themeService));
this.toDispose.push(this.debugService.getViewModel().onDidFocusSession(() => {
this._register(this.debugService.getViewModel().onDidFocusSession(() => {
const session = this.debugService.getViewModel().focusedSession;
if (session) {
const index = this.getSessions().indexOf(session);
@@ -209,8 +209,8 @@ export class FocusSessionActionViewItem extends SelectActionViewItem {
}
}));
this.toDispose.push(this.debugService.onDidNewSession(() => this.update()));
this.toDispose.push(this.debugService.onDidEndSession(() => this.update()));
this._register(this.debugService.onDidNewSession(() => this.update()));
this._register(this.debugService.onDidEndSession(() => this.update()));
this.update();
}

View File

@@ -323,6 +323,7 @@ export class AddWatchExpressionAction extends AbstractDebugAction {
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
super(id, label, 'debug-action add-watch-expression', debugService, keybindingService);
this.toDispose.push(this.debugService.getModel().onDidChangeWatchExpressions(() => this.updateEnablement()));
this.toDispose.push(this.debugService.getViewModel().onDidSelectExpression(() => this.updateEnablement()));
}
public run(): Promise<any> {
@@ -331,7 +332,8 @@ export class AddWatchExpressionAction extends AbstractDebugAction {
}
protected isEnabled(state: State): boolean {
return super.isEnabled(state) && this.debugService.getModel().getWatchExpressions().every(we => !!we.name);
const focusedExpression = this.debugService.getViewModel().getSelectedExpression();
return super.isEnabled(state) && this.debugService.getModel().getWatchExpressions().every(we => !!we.name && we !== focusedExpression);
}
}
@@ -396,11 +398,11 @@ export class CopyValueAction extends Action {
if (this.value instanceof Variable && stackFrame && session && this.value.evaluateName) {
return session.evaluate(this.value.evaluateName, stackFrame.frameId, this.context).then(result => {
this.clipboardService.writeText(result.body.result);
return this.clipboardService.writeText(result.body.result);
}, err => this.clipboardService.writeText(this.value.value));
}
this.clipboardService.writeText(this.value);
return Promise.resolve(undefined);
return this.clipboardService.writeText(this.value);
}
}

View File

@@ -9,7 +9,7 @@ import { List } from 'vs/base/browser/ui/list/listWidget';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IListService } from 'vs/platform/list/browser/listService';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IDebugService, IEnablement, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_VARIABLES_FOCUSED, EDITOR_CONTRIBUTION_ID, IDebugEditorContribution, CONTEXT_IN_DEBUG_MODE, CONTEXT_EXPRESSION_SELECTED, CONTEXT_BREAKPOINT_SELECTED, IConfig, IStackFrame, IThread, IDebugSession, CONTEXT_DEBUG_STATE, REPL_ID, IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug';
import { IDebugService, IEnablement, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_VARIABLES_FOCUSED, EDITOR_CONTRIBUTION_ID, IDebugEditorContribution, CONTEXT_IN_DEBUG_MODE, CONTEXT_EXPRESSION_SELECTED, CONTEXT_BREAKPOINT_SELECTED, IConfig, IStackFrame, IThread, IDebugSession, CONTEXT_DEBUG_STATE, REPL_ID, IDebugConfiguration, CONTEXT_JUMP_TO_CURSOR_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug';
import { Expression, Variable, Breakpoint, FunctionBreakpoint, Thread } from 'vs/workbench/contrib/debug/common/debugModel';
import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
@@ -31,6 +31,7 @@ import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { startDebugging } from 'vs/workbench/contrib/debug/common/debugUtils';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
export const ADD_CONFIGURATION_ID = 'debug.addConfiguration';
export const TOGGLE_INLINE_BREAKPOINT_ID = 'editor.debug.action.toggleInlineBreakpoint';
@@ -48,11 +49,17 @@ export const STOP_ID = 'workbench.action.debug.stop';
export const RESTART_FRAME_ID = 'workbench.action.debug.restartFrame';
export const CONTINUE_ID = 'workbench.action.debug.continue';
export const FOCUS_REPL_ID = 'workbench.debug.action.focusRepl';
export const JUMP_TO_CURSOR_ID = 'debug.jumpToCursor';
function getThreadAndRun(accessor: ServicesAccessor, thread: IThread | undefined, run: (thread: IThread) => Promise<void>, ): void {
const debugService = accessor.get(IDebugService);
if (!(thread instanceof Thread)) {
thread = debugService.getViewModel().focusedThread;
if (!thread) {
const focusedSession = debugService.getViewModel().focusedSession;
const threads = focusedSession ? focusedSession.getAllThreads() : undefined;
thread = threads && threads.length ? threads[0] : undefined;
}
}
if (thread) {
@@ -64,11 +71,11 @@ export function registerCommands(): void {
CommandsRegistry.registerCommand({
id: COPY_STACK_TRACE_ID,
handler: (accessor: ServicesAccessor, _: string, frame: IStackFrame) => {
handler: async (accessor: ServicesAccessor, _: string, frame: IStackFrame) => {
const textResourcePropertiesService = accessor.get(ITextResourcePropertiesService);
const clipboardService = accessor.get(IClipboardService);
const eol = textResourcePropertiesService.getEOL(frame.source.uri);
clipboardService.writeText(frame.thread.getCallStack().map(sf => sf.toString()).join(eol));
await clipboardService.writeText(frame.thread.getCallStack().map(sf => sf.toString()).join(eol));
}
});
@@ -93,6 +100,55 @@ export function registerCommands(): void {
}
});
CommandsRegistry.registerCommand({
id: JUMP_TO_CURSOR_ID,
handler: async (accessor: ServicesAccessor) => {
const debugService = accessor.get(IDebugService);
const stackFrame = debugService.getViewModel().focusedStackFrame;
const editorService = accessor.get(IEditorService);
const activeEditor = editorService.activeTextEditorWidget;
const notificationService = accessor.get(INotificationService);
const quickInputService = accessor.get(IQuickInputService);
if (stackFrame && isCodeEditor(activeEditor) && activeEditor.hasModel()) {
const position = activeEditor.getPosition();
const resource = activeEditor.getModel().uri;
const source = stackFrame.thread.session.getSourceForUri(resource);
if (source) {
const response = await stackFrame.thread.session.gotoTargets(source.raw, position.lineNumber, position.column);
const targets = response.body.targets;
if (targets.length) {
let id = targets[0].id;
if (targets.length > 1) {
const picks = targets.map(t => ({ label: t.label, _id: t.id }));
const pick = await quickInputService.pick(picks, { placeHolder: nls.localize('chooseLocation', "Choose the specific location") });
if (!pick) {
return;
}
id = pick._id;
}
return await stackFrame.thread.session.goto(stackFrame.thread.threadId, id).catch(e => notificationService.warn(e));
}
}
}
return notificationService.warn(nls.localize('noExecutableCode', "No executable code is associated at the current cursor position."));
}
});
MenuRegistry.appendMenuItem(MenuId.EditorContext, {
command: {
id: JUMP_TO_CURSOR_ID,
title: nls.localize('jumpToCursor', "Jump to Cursor"),
category: { value: nls.localize('debug', "Debug"), original: 'Debug' }
},
when: ContextKeyExpr.and(CONTEXT_JUMP_TO_CURSOR_SUPPORTED, EditorContextKeys.editorTextFocus),
group: 'debug',
order: 3
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: RESTART_SESSION_ID,
weight: KeybindingWeight.WorkbenchContrib,
@@ -407,24 +463,18 @@ export function registerCommands(): void {
const widget = editorService.activeTextEditorWidget;
if (isCodeEditor(widget)) {
const position = widget.getPosition();
if (!position || !widget.hasModel()) {
return undefined;
}
if (position && widget.hasModel() && debugService.getConfigurationManager().canSetBreakpointsIn(widget.getModel())) {
const modelUri = widget.getModel().uri;
const breakpointAlreadySet = debugService.getModel().getBreakpoints({ lineNumber: position.lineNumber, uri: modelUri })
.some(bp => (bp.sessionAgnosticData.column === position.column || (!bp.column && position.column <= 1)));
const modelUri = widget.getModel().uri;
const bp = debugService.getModel().getBreakpoints({ lineNumber: position.lineNumber, uri: modelUri })
.filter(bp => (bp.column === position.column || !bp.column && position.column <= 1)).pop();
if (bp) {
return undefined;
}
if (debugService.getConfigurationManager().canSetBreakpointsIn(widget.getModel())) {
return debugService.addBreakpoints(modelUri, [{ lineNumber: position.lineNumber, column: position.column > 1 ? position.column : undefined }], 'debugCommands.inlineBreakpointCommand');
if (!breakpointAlreadySet) {
debugService.addBreakpoints(modelUri, [{ lineNumber: position.lineNumber, column: position.column > 1 ? position.column : undefined }], 'debugCommands.inlineBreakpointCommand');
}
}
}
return undefined;
};
KeybindingsRegistry.registerCommandAndKeybindingRule({
weight: KeybindingWeight.WorkbenchContrib,
primary: KeyMod.Shift | KeyCode.F9,
@@ -433,17 +483,11 @@ export function registerCommands(): void {
handler: inlineBreakpointHandler
});
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: TOGGLE_INLINE_BREAKPOINT_ID,
title: { value: nls.localize('inlineBreakpoint', "Inline Breakpoint"), original: 'Debug: Inline Breakpoint' },
category: nls.localize('debug', "Debug")
}
});
MenuRegistry.appendMenuItem(MenuId.EditorContext, {
command: {
id: TOGGLE_INLINE_BREAKPOINT_ID,
title: nls.localize('addInlineBreakpoint', "Add Inline Breakpoint")
title: nls.localize('addInlineBreakpoint', "Add Inline Breakpoint"),
category: { value: nls.localize('debug', "Debug"), original: 'Debug' }
},
when: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, PanelFocusContext.toNegated(), EditorContextKeys.editorTextFocus),
group: 'debug',

View File

@@ -21,13 +21,12 @@ import { IFileService } from 'vs/platform/files/common/files';
import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IDebugConfigurationProvider, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IDebugAdapterDescriptorFactory, IDebugAdapter, ITerminalSettings, ITerminalLauncher, IDebugSession, IAdapterDescriptor, CONTEXT_DEBUG_CONFIGURATION_TYPE, IDebugAdapterFactory, IDebugService } from 'vs/workbench/contrib/debug/common/debug';
import { Debugger } from 'vs/workbench/contrib/debug/node/debugger';
import { IDebugConfigurationProvider, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IDebugAdapterDescriptorFactory, IDebugAdapter, ITerminalSettings, IDebugSession, IAdapterDescriptor, CONTEXT_DEBUG_CONFIGURATION_TYPE, IDebugAdapterFactory, IDebugService } from 'vs/workbench/contrib/debug/common/debug';
import { Debugger } from 'vs/workbench/contrib/debug/common/debugger';
import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { launchSchemaId } from 'vs/workbench/services/configuration/common/configuration';
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { TerminalLauncher } from 'vs/workbench/contrib/debug/electron-browser/terminalSupport';
import { Registry } from 'vs/platform/registry/common/platform';
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { launchSchema, debuggersExtPoint, breakpointsExtPoint } from 'vs/workbench/contrib/debug/common/debugSchemas';
@@ -52,8 +51,7 @@ export class ConfigurationManager implements IConfigurationManager {
private _onDidSelectConfigurationName = new Emitter<void>();
private configProviders: IDebugConfigurationProvider[];
private adapterDescriptorFactories: IDebugAdapterDescriptorFactory[];
private debugAdapterFactories: Map<string, IDebugAdapterFactory>;
private terminalLauncher: ITerminalLauncher;
private debugAdapterFactories = new Map<string, IDebugAdapterFactory>();
private debugConfigurationTypeContext: IContextKey<string>;
constructor(
@@ -73,12 +71,11 @@ export class ConfigurationManager implements IConfigurationManager {
this.adapterDescriptorFactories = [];
this.debuggers = [];
this.toDispose = [];
this.registerListeners(lifecycleService);
this.initLaunches();
this.registerListeners(lifecycleService);
const previousSelectedRoot = this.storageService.get(DEBUG_SELECTED_ROOT, StorageScope.WORKSPACE);
const previousSelectedLaunch = this.launches.filter(l => l.uri.toString() === previousSelectedRoot).pop();
this.debugConfigurationTypeContext = CONTEXT_DEBUG_CONFIGURATION_TYPE.bindTo(contextKeyService);
this.debugAdapterFactories = new Map();
if (previousSelectedLaunch) {
this.selectConfiguration(previousSelectedLaunch, this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE));
}
@@ -112,14 +109,11 @@ export class ConfigurationManager implements IConfigurationManager {
}
runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise<number | undefined> {
let tl: ITerminalLauncher | undefined = this.debugAdapterFactories.get(debugType);
if (!tl) {
if (!this.terminalLauncher) {
this.terminalLauncher = this.instantiationService.createInstance(TerminalLauncher);
}
tl = this.terminalLauncher;
let tl = this.debugAdapterFactories.get(debugType);
if (tl) {
return tl.runInTerminal(args, config);
}
return tl.runInTerminal(args, config);
return Promise.resolve(void 0);
}
// debug adapter
@@ -290,8 +284,6 @@ export class ConfigurationManager implements IConfigurationManager {
this.setCompoundSchemaValues();
}
}));
this.toDispose.push(this.storageService.onWillSaveState(this.saveState, this));
}
private initLaunches(): void {
@@ -302,7 +294,7 @@ export class ConfigurationManager implements IConfigurationManager {
this.launches.push(this.instantiationService.createInstance(UserLaunch));
if (this.selectedLaunch && this.launches.indexOf(this.selectedLaunch) === -1) {
this.selectedLaunch = undefined;
this.setSelectedLaunch(undefined);
}
}
@@ -354,13 +346,13 @@ export class ConfigurationManager implements IConfigurationManager {
const previousLaunch = this.selectedLaunch;
const previousName = this.selectedName;
this.selectedLaunch = launch;
this.setSelectedLaunch(launch);
const names = launch ? launch.getConfigurationNames() : [];
if (name && names.indexOf(name) >= 0) {
this.selectedName = name;
this.setSelectedLaunchName(name);
}
if (!this.selectedName || names.indexOf(this.selectedName) === -1) {
this.selectedName = names.length ? names[0] : undefined;
this.setSelectedLaunchName(names.length ? names[0] : undefined);
}
const configuration = this.selectedLaunch && this.selectedName ? this.selectedLaunch.getConfiguration(this.selectedName) : undefined;
@@ -445,12 +437,23 @@ export class ConfigurationManager implements IConfigurationManager {
});
}
private saveState(): void {
private setSelectedLaunchName(selectedName: string | undefined): void {
this.selectedName = selectedName;
if (this.selectedName) {
this.storageService.store(DEBUG_SELECTED_CONFIG_NAME_KEY, this.selectedName, StorageScope.WORKSPACE);
} else {
this.storageService.remove(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE);
}
}
private setSelectedLaunch(selectedLaunch: ILaunch | undefined): void {
this.selectedLaunch = selectedLaunch;
if (this.selectedLaunch) {
this.storageService.store(DEBUG_SELECTED_ROOT, this.selectedLaunch.uri.toString(), StorageScope.WORKSPACE);
} else {
this.storageService.remove(DEBUG_SELECTED_ROOT, StorageScope.WORKSPACE);
}
}

View File

@@ -17,7 +17,6 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { openBreakpointSource } from 'vs/workbench/contrib/debug/browser/breakpointsView';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { PanelFocusContext } from 'vs/workbench/common/panel';
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
export const TOGGLE_BREAKPOINT_ID = 'editor.debug.action.toggleBreakpoint';
class ToggleBreakpointAction extends EditorAction {
@@ -99,7 +98,7 @@ class LogPointAction extends EditorAction {
}
}
class RunToCursorAction extends EditorAction {
export class RunToCursorAction extends EditorAction {
public static ID = 'editor.debug.action.runToCursor';
public static LABEL = nls.localize('runToCursor', "Run to Cursor");
@@ -313,12 +312,3 @@ registerEditorAction(SelectionToWatchExpressionsAction);
registerEditorAction(ShowDebugHoverAction);
registerEditorAction(GoToNextBreakpointAction);
registerEditorAction(GoToPreviousBreakpointAction);
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: RunToCursorAction.ID,
title: { value: RunToCursorAction.LABEL, original: 'Debug: Run to Cursor' },
category: nls.localize('debug', "Debug")
},
group: 'debug',
when: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')),
});

View File

@@ -15,6 +15,7 @@ import { getBreakpointMessageAndClassName } from 'vs/workbench/contrib/debug/bro
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { registerColor } from 'vs/platform/theme/common/colorRegistry';
import { localize } from 'vs/nls';
import { onUnexpectedError } from 'vs/base/common/errors';
interface IBreakpointDecoration {
decorationId: string;
@@ -180,7 +181,7 @@ export class DebugEditorModelManager implements IWorkbenchContribution {
return;
}
const data: { [id: string]: IBreakpointUpdateData } = Object.create(null);
const data = new Map<string, IBreakpointUpdateData>();
const breakpoints = this.debugService.getModel().getBreakpoints();
const modelUri = modelData.model.uri;
for (let i = 0, len = modelData.breakpointDecorations.length; i < len; i++) {
@@ -191,15 +192,15 @@ export class DebugEditorModelManager implements IWorkbenchContribution {
const breakpoint = breakpoints.filter(bp => bp.getId() === breakpointDecoration.modelId).pop();
// since we know it is collapsed, it cannot grow to multiple lines
if (breakpoint) {
data[breakpoint.getId()] = {
data.set(breakpoint.getId(), {
lineNumber: decorationRange.startLineNumber,
column: breakpoint.column ? decorationRange.startColumn : undefined,
};
});
}
}
}
this.debugService.updateBreakpoints(modelUri, data, true);
this.debugService.updateBreakpoints(modelUri, data, true).then(undefined, onUnexpectedError);
}
private onBreakpointsChange(): void {

View File

@@ -0,0 +1,21 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug';
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export class BrowserDebugHelperService implements IDebugHelperService {
_serviceBrand: ServiceIdentifier<IDebugHelperService>;
createTelemetryService(configurationService: IConfigurationService, args: string[]): TelemetryService | undefined {
return undefined;
}
}
registerSingleton(IDebugHelperService, BrowserDebugHelperService);

View File

@@ -16,7 +16,7 @@ import { IContentWidget, ICodeEditor, IContentWidgetPosition, ContentWidgetPosit
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IDebugService, IExpression, IExpressionContainer } from 'vs/workbench/contrib/debug/common/debug';
import { Expression } from 'vs/workbench/contrib/debug/common/debugModel';
import { renderExpressionValue } from 'vs/workbench/contrib/debug/browser/baseDebugView';
import { renderExpressionValue, replaceWhitespace } from 'vs/workbench/contrib/debug/browser/baseDebugView';
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';
@@ -237,7 +237,7 @@ export class DebugHoverWidget implements IContentWidget {
this.complexValueContainer.hidden = false;
return this.tree.setInput(expression).then(() => {
this.complexValueTitle.textContent = expression.value;
this.complexValueTitle.textContent = replaceWhitespace(expression.value);
this.complexValueTitle.title = expression.value;
this.layoutTreeAndContainer();
this.editor.layoutContentWidget(this);

View File

@@ -21,7 +21,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
import { DebugModel, ExceptionBreakpoint, FunctionBreakpoint, Breakpoint, Expression } from 'vs/workbench/contrib/debug/common/debugModel';
import { ViewModel } from 'vs/workbench/contrib/debug/common/debugViewModel';
import * as debugactions from 'vs/workbench/contrib/debug/browser/debugActions';
import { ConfigurationManager } from 'vs/workbench/contrib/debug/electron-browser/debugConfigurationManager';
import { ConfigurationManager } from 'vs/workbench/contrib/debug/browser/debugConfigurationManager';
import Constants from 'vs/workbench/contrib/markers/browser/constants';
import { ITaskService, ITaskSummary } from 'vs/workbench/contrib/tasks/common/taskService';
import { TaskError } from 'vs/workbench/contrib/tasks/common/taskSystem';
@@ -39,13 +39,14 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IAction, Action } from 'vs/base/common/actions';
import { deepClone, equals } from 'vs/base/common/objects';
import { DebugSession } from 'vs/workbench/contrib/debug/electron-browser/debugSession';
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 } 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/workbench/services/extensions/common/extensionHostDebug';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint';
const DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated';
@@ -132,7 +133,6 @@ export class DebugService implements IDebugService {
this.viewModel = new ViewModel(contextKeyService);
this.toDispose.push(this.fileService.onFileChanges(e => this.onFileChanges(e)));
this.toDispose.push(this.storageService.onWillSaveState(this.saveState, this));
this.lifecycleService.onShutdown(this.dispose, this);
this.toDispose.push(this.extensionHostDebugService.onAttachSession(event => {
@@ -431,9 +431,6 @@ export class DebugService implements IDebugService {
return this.launchOrAttachToSession(session).then(() => {
// since the initialized response has arrived announce the new Session (including extensions)
this._onDidNewSession.fire(session);
const internalConsoleOptions = session.configuration.internalConsoleOptions || this.configurationService.getValue<IDebugConfiguration>('debug').internalConsoleOptions;
if (internalConsoleOptions === 'openOnSessionStart' || (this.viewModel.firstSessionStart && internalConsoleOptions === 'openOnFirstSessionStart')) {
this.panelService.openPanel(REPL_ID, false);
@@ -447,6 +444,9 @@ export class DebugService implements IDebugService {
this.viewModel.setMultiSessionView(true);
}
// since the initialized response has arrived announce the new Session (including extensions)
this._onDidNewSession.fire(session);
return this.telemetryDebugSessionStart(root, session.configuration.type);
}).then(() => true, (error: Error | string) => {
@@ -658,9 +658,9 @@ export class DebugService implements IDebugService {
return Promise.resolve(config);
}
private showError(message: string, actions: IAction[] = []): Promise<void> {
private showError(message: string, errorActions: ReadonlyArray<IAction> = []): Promise<void> {
const configureAction = this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL);
actions.push(configureAction);
const actions = [...errorActions, configureAction];
return this.dialogService.show(severity.Error, message, actions.map(a => a.label).concat(nls.localize('cancel', "Cancel")), { cancelId: actions.length }).then(choice => {
if (choice < actions.length) {
return actions[choice].run();
@@ -789,8 +789,18 @@ export class DebugService implements IDebugService {
}
if (stackFrame) {
stackFrame.openInEditor(this.editorService, true);
aria.alert(nls.localize('debuggingPaused', "Debugging paused {0}, {1} {2}", thread && thread.stoppedDetails ? `, reason ${thread.stoppedDetails.reason}` : '', stackFrame.source ? stackFrame.source.name : '', stackFrame.range.startLineNumber));
stackFrame.openInEditor(this.editorService, true).then(editor => {
if (editor) {
const control = editor.getControl();
if (stackFrame && isCodeEditor(control) && control.hasModel()) {
const model = control.getModel();
if (stackFrame.range.startLineNumber <= model.getLineCount()) {
const lineContent = control.getModel().getLineContent(stackFrame.range.startLineNumber);
aria.alert(nls.localize('debuggingPaused', "Debugging paused {0}, {1} {2} {3}", thread && thread.stoppedDetails ? `, reason ${thread.stoppedDetails.reason}` : '', stackFrame.source ? stackFrame.source.name : '', stackFrame.range.startLineNumber, lineContent));
}
}
}
});
}
if (session) {
this.debugType.set(session.configuration.type);
@@ -806,67 +816,82 @@ export class DebugService implements IDebugService {
addWatchExpression(name: string): void {
const we = this.model.addWatchExpression(name);
this.viewModel.setSelectedExpression(we);
this.storeWatchExpressions();
}
renameWatchExpression(id: string, newName: string): void {
return this.model.renameWatchExpression(id, newName);
this.model.renameWatchExpression(id, newName);
this.storeWatchExpressions();
}
moveWatchExpression(id: string, position: number): void {
this.model.moveWatchExpression(id, position);
this.storeWatchExpressions();
}
removeWatchExpressions(id?: string): void {
this.model.removeWatchExpressions(id);
this.storeWatchExpressions();
}
//---- breakpoints
enableOrDisableBreakpoints(enable: boolean, breakpoint?: IEnablement): Promise<void> {
async enableOrDisableBreakpoints(enable: boolean, breakpoint?: IEnablement): Promise<void> {
if (breakpoint) {
this.model.setEnablement(breakpoint, enable);
if (breakpoint instanceof Breakpoint) {
return this.sendBreakpoints(breakpoint.uri);
await this.sendBreakpoints(breakpoint.uri);
} else if (breakpoint instanceof FunctionBreakpoint) {
return this.sendFunctionBreakpoints();
await this.sendFunctionBreakpoints();
} else {
await this.sendExceptionBreakpoints();
}
return this.sendExceptionBreakpoints();
} else {
this.model.enableOrDisableAllBreakpoints(enable);
await this.sendAllBreakpoints();
}
this.model.enableOrDisableAllBreakpoints(enable);
return this.sendAllBreakpoints();
this.storeBreakpoints();
}
addBreakpoints(uri: uri, rawBreakpoints: IBreakpointData[], context: string): Promise<IBreakpoint[]> {
async addBreakpoints(uri: uri, rawBreakpoints: IBreakpointData[], context: string): Promise<IBreakpoint[]> {
const breakpoints = this.model.addBreakpoints(uri, rawBreakpoints);
breakpoints.forEach(bp => aria.status(nls.localize('breakpointAdded', "Added breakpoint, line {0}, file {1}", bp.lineNumber, uri.fsPath)));
breakpoints.forEach(bp => this.telemetryDebugAddBreakpoint(bp, context));
return this.sendBreakpoints(uri).then(() => breakpoints);
await this.sendBreakpoints(uri);
this.storeBreakpoints();
return breakpoints;
}
updateBreakpoints(uri: uri, data: { [id: string]: DebugProtocol.Breakpoint }, sendOnResourceSaved: boolean): void {
async updateBreakpoints(uri: uri, data: Map<string, DebugProtocol.Breakpoint>, sendOnResourceSaved: boolean): Promise<void> {
this.model.updateBreakpoints(data);
if (sendOnResourceSaved) {
this.breakpointsToSendOnResourceSaved.add(uri.toString());
} else {
this.sendBreakpoints(uri);
await this.sendBreakpoints(uri);
}
this.storeBreakpoints();
}
removeBreakpoints(id?: string): Promise<any> {
async removeBreakpoints(id?: string): Promise<void> {
const toRemove = this.model.getBreakpoints().filter(bp => !id || bp.getId() === id);
toRemove.forEach(bp => aria.status(nls.localize('breakpointRemoved', "Removed breakpoint, line {0}, file {1}", bp.lineNumber, bp.uri.fsPath)));
const urisToClear = distinct(toRemove, bp => bp.uri.toString()).map(bp => bp.uri);
this.model.removeBreakpoints(toRemove);
return Promise.all(urisToClear.map(uri => this.sendBreakpoints(uri)));
await Promise.all(urisToClear.map(uri => this.sendBreakpoints(uri)));
this.storeBreakpoints();
}
setBreakpointsActivated(activated: boolean): Promise<void> {
this.model.setBreakpointsActivated(activated);
if (activated) {
this.storageService.store(DEBUG_BREAKPOINTS_ACTIVATED_KEY, 'false', StorageScope.WORKSPACE);
} else {
this.storageService.remove(DEBUG_BREAKPOINTS_ACTIVATED_KEY, StorageScope.WORKSPACE);
}
return this.sendAllBreakpoints();
}
@@ -875,14 +900,16 @@ export class DebugService implements IDebugService {
this.viewModel.setSelectedFunctionBreakpoint(newFunctionBreakpoint);
}
renameFunctionBreakpoint(id: string, newFunctionName: string): Promise<void> {
async renameFunctionBreakpoint(id: string, newFunctionName: string): Promise<void> {
this.model.renameFunctionBreakpoint(id, newFunctionName);
return this.sendFunctionBreakpoints();
await this.sendFunctionBreakpoints();
this.storeBreakpoints();
}
removeFunctionBreakpoints(id?: string): Promise<void> {
async removeFunctionBreakpoints(id?: string): Promise<void> {
this.model.removeFunctionBreakpoints(id);
return this.sendFunctionBreakpoints();
await this.sendFunctionBreakpoints();
this.storeBreakpoints();
}
sendAllBreakpoints(session?: IDebugSession): Promise<any> {
@@ -982,7 +1009,16 @@ export class DebugService implements IDebugService {
return result || [];
}
private saveState(): void {
private storeWatchExpressions(): void {
const watchExpressions = this.model.getWatchExpressions();
if (watchExpressions.length) {
this.storageService.store(DEBUG_WATCH_EXPRESSIONS_KEY, JSON.stringify(watchExpressions.map(we => ({ name: we.name, id: we.getId() }))), StorageScope.WORKSPACE);
} else {
this.storageService.remove(DEBUG_WATCH_EXPRESSIONS_KEY, StorageScope.WORKSPACE);
}
}
private storeBreakpoints(): void {
const breakpoints = this.model.getBreakpoints();
if (breakpoints.length) {
this.storageService.store(DEBUG_BREAKPOINTS_KEY, JSON.stringify(breakpoints), StorageScope.WORKSPACE);
@@ -990,12 +1026,6 @@ export class DebugService implements IDebugService {
this.storageService.remove(DEBUG_BREAKPOINTS_KEY, StorageScope.WORKSPACE);
}
if (!this.model.areBreakpointsActivated()) {
this.storageService.store(DEBUG_BREAKPOINTS_ACTIVATED_KEY, 'false', StorageScope.WORKSPACE);
} else {
this.storageService.remove(DEBUG_BREAKPOINTS_ACTIVATED_KEY, StorageScope.WORKSPACE);
}
const functionBreakpoints = this.model.getFunctionBreakpoints();
if (functionBreakpoints.length) {
this.storageService.store(DEBUG_FUNCTION_BREAKPOINTS_KEY, JSON.stringify(functionBreakpoints), StorageScope.WORKSPACE);
@@ -1009,13 +1039,6 @@ export class DebugService implements IDebugService {
} else {
this.storageService.remove(DEBUG_EXCEPTION_BREAKPOINTS_KEY, StorageScope.WORKSPACE);
}
const watchExpressions = this.model.getWatchExpressions();
if (watchExpressions.length) {
this.storageService.store(DEBUG_WATCH_EXPRESSIONS_KEY, JSON.stringify(watchExpressions.map(we => ({ name: we.name, id: we.getId() }))), StorageScope.WORKSPACE);
} else {
this.storageService.remove(DEBUG_WATCH_EXPRESSIONS_KEY, StorageScope.WORKSPACE);
}
}
//---- telemetry

View File

@@ -16,13 +16,13 @@ import { IDebugSession, IConfig, IThread, IRawModelUpdate, IDebugService, IRawSt
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
import { mixin } from 'vs/base/common/objects';
import { Thread, ExpressionContainer, DebugModel } from 'vs/workbench/contrib/debug/common/debugModel';
import { RawDebugSession } from 'vs/workbench/contrib/debug/electron-browser/rawDebugSession';
import product from 'vs/platform/product/node/product';
import { RawDebugSession } from 'vs/workbench/contrib/debug/browser/rawDebugSession';
import { IProductService } from 'vs/platform/product/common/product';
import { IWorkspaceFolder, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { RunOnceScheduler } from 'vs/base/common/async';
import { generateUuid } from 'vs/base/common/uuid';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { normalizeDriveLetter } from 'vs/base/common/labels';
import { Range } from 'vs/editor/common/core/range';
@@ -30,8 +30,8 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ISignService } from 'vs/platform/sign/common/sign';
export class DebugSession implements IDebugSession {
@@ -65,8 +65,10 @@ export class DebugSession implements IDebugSession {
@IConfigurationService private readonly configurationService: IConfigurationService,
@IViewletService private readonly viewletService: IViewletService,
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@INotificationService private readonly notificationService: INotificationService
@INotificationService private readonly notificationService: INotificationService,
@ISignService private readonly signService: ISignService,
@IProductService private readonly productService: IProductService,
@IWindowsService private readonly windowsService: IWindowsService
) {
this.id = generateUuid();
this.repl = new ReplModel(this);
@@ -167,7 +169,7 @@ export class DebugSession implements IDebugSession {
return dbgr.createDebugAdapter(this).then(debugAdapter => {
this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.environmentService);
this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.signService, this.windowsService);
return this.raw!.start().then(() => {
@@ -175,7 +177,7 @@ export class DebugSession implements IDebugSession {
return this.raw!.initialize({
clientID: 'vscode',
clientName: product.nameLong,
clientName: this.productService.nameLong,
adapterID: this.configuration.type,
pathFormat: 'path',
linesStartAt1: true,
@@ -282,14 +284,14 @@ export class DebugSession implements IDebugSession {
return this.raw.setBreakpoints({
source: rawSource,
lines: breakpointsToSend.map(bp => bp.lineNumber),
breakpoints: breakpointsToSend.map(bp => ({ line: bp.lineNumber, column: bp.column, condition: bp.condition, hitCondition: bp.hitCondition, logMessage: bp.logMessage })),
lines: breakpointsToSend.map(bp => bp.sessionAgnosticData.lineNumber),
breakpoints: breakpointsToSend.map(bp => ({ line: bp.sessionAgnosticData.lineNumber, column: bp.sessionAgnosticData.column, condition: bp.condition, hitCondition: bp.hitCondition, logMessage: bp.logMessage })),
sourceModified
}).then(response => {
if (response && response.body) {
const data: { [id: string]: DebugProtocol.Breakpoint } = Object.create(null);
const data = new Map<string, DebugProtocol.Breakpoint>();
for (let i = 0; i < breakpointsToSend.length; i++) {
data[breakpointsToSend[i].getId()] = response.body.breakpoints[i];
data.set(breakpointsToSend[i].getId(), response.body.breakpoints[i]);
}
this.model.setBreakpointSessionData(this.getId(), data);
@@ -302,9 +304,9 @@ export class DebugSession implements IDebugSession {
if (this.raw.readyForBreakpoints) {
return this.raw.setFunctionBreakpoints({ breakpoints: fbpts }).then(response => {
if (response && response.body) {
const data: { [id: string]: DebugProtocol.Breakpoint } = Object.create(null);
const data = new Map<string, DebugProtocol.Breakpoint>();
for (let i = 0; i < fbpts.length; i++) {
data[fbpts[i].getId()] = response.body.breakpoints[i];
data.set(fbpts[i].getId(), response.body.breakpoints[i]);
}
this.model.setBreakpointSessionData(this.getId(), data);
}
@@ -449,6 +451,20 @@ export class DebugSession implements IDebugSession {
return Promise.reject(new Error('no debug adapter'));
}
gotoTargets(source: DebugProtocol.Source, line: number, column?: number): Promise<DebugProtocol.GotoTargetsResponse> {
if (this.raw) {
return this.raw.gotoTargets({ source, line, column });
}
return Promise.reject(new Error('no debug adapter'));
}
goto(threadId: number, targetId: number): Promise<DebugProtocol.GotoResponse> {
if (this.raw) {
return this.raw.goto({ threadId, targetId });
}
return Promise.reject(new Error('no debug adapter'));
}
loadSource(resource: URI): Promise<DebugProtocol.SourceResponse> {
if (!this.raw) {
@@ -561,7 +577,9 @@ export class DebugSession implements IDebugSession {
}
rawUpdate(data: IRawModelUpdate): void {
const threadIds: number[] = [];
data.threads.forEach(thread => {
threadIds.push(thread.id);
if (!this.threads.has(thread.id)) {
// A new thread came in, initialize it.
this.threads.set(thread.id, new Thread(this, thread.name, thread.id));
@@ -573,6 +591,12 @@ export class DebugSession implements IDebugSession {
}
}
});
this.threads.forEach(t => {
// Remove all old threads which are no longer part of the update #75980
if (threadIds.indexOf(t.threadId) === -1) {
this.threads.delete(t.threadId);
}
});
const stoppedDetails = data.stoppedDetails;
if (stoppedDetails) {
@@ -753,7 +777,8 @@ export class DebugSession implements IDebugSession {
lineNumber: event.body.breakpoint.line,
}], false);
if (bps.length === 1) {
this.model.setBreakpointSessionData(this.getId(), { [bps[0].getId()]: event.body.breakpoint });
const data = new Map<string, DebugProtocol.Breakpoint>([[bps[0].getId(), event.body.breakpoint]]);
this.model.setBreakpointSessionData(this.getId(), data);
}
}
@@ -771,10 +796,12 @@ export class DebugSession implements IDebugSession {
if (!breakpoint.column) {
event.body.breakpoint.column = undefined;
}
this.model.setBreakpointSessionData(this.getId(), { [breakpoint.getId()]: event.body.breakpoint });
const data = new Map<string, DebugProtocol.Breakpoint>([[breakpoint.getId(), event.body.breakpoint]]);
this.model.setBreakpointSessionData(this.getId(), data);
}
if (functionBreakpoint) {
this.model.setBreakpointSessionData(this.getId(), { [functionBreakpoint.getId()]: event.body.breakpoint });
const data = new Map<string, DebugProtocol.Breakpoint>([[functionBreakpoint.getId(), event.body.breakpoint]]);
this.model.setBreakpointSessionData(this.getId(), data);
}
}
}));

View File

@@ -4,100 +4,81 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IDebugService, State, IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug';
import { Themable, STATUS_BAR_FOREGROUND } from 'vs/workbench/common/theme';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { STATUS_BAR_DEBUGGING_FOREGROUND, isStatusbarInDebugMode } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider';
import { IStatusbarEntry, IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
const $ = dom.$;
export class DebugStatus extends Themable implements IStatusbarItem {
private container: HTMLElement;
private statusBarItem: HTMLElement;
private label: HTMLElement;
private icon: HTMLElement;
export class DebugStatusContribution implements IWorkbenchContribution {
private showInStatusBar: 'never' | 'always' | 'onFirstSessionStart';
private toDispose: IDisposable[] = [];
private entryAccessor: IStatusbarEntryAccessor | undefined;
constructor(
@IQuickOpenService private readonly quickOpenService: IQuickOpenService,
@IDebugService private readonly debugService: IDebugService,
@IThemeService themeService: IThemeService,
@IConfigurationService configurationService: IConfigurationService
@IStatusbarService private readonly statusBarService: IStatusbarService,
@IDebugService readonly debugService: IDebugService,
@IConfigurationService readonly configurationService: IConfigurationService
) {
super(themeService);
this._register(this.debugService.getConfigurationManager().onDidSelectConfiguration(e => {
this.setLabel();
}));
this._register(this.debugService.onDidChangeState(state => {
if (state !== State.Inactive && this.showInStatusBar === 'onFirstSessionStart') {
this.doRender();
} else {
if (this.showInStatusBar !== 'never') {
this.updateStyles();
}
const addStatusBarEntry = () => {
this.entryAccessor = this.statusBarService.addEntry(this.entry, 'status.debug', nls.localize('status.debug', "Debug"), StatusbarAlignment.LEFT, 30 /* Low Priority */);
};
const setShowInStatusBar = () => {
this.showInStatusBar = configurationService.getValue<IDebugConfiguration>('debug').showInStatusBar;
if (this.showInStatusBar === 'always' && !this.entryAccessor) {
addStatusBarEntry();
}
};
setShowInStatusBar();
this.toDispose.push(this.debugService.onDidChangeState(state => {
if (state !== State.Inactive && this.showInStatusBar === 'onFirstSessionStart' && !this.entryAccessor) {
addStatusBarEntry();
}
}));
this.showInStatusBar = configurationService.getValue<IDebugConfiguration>('debug').showInStatusBar;
this._register(configurationService.onDidChangeConfiguration(e => {
this.toDispose.push(configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('debug.showInStatusBar')) {
this.showInStatusBar = configurationService.getValue<IDebugConfiguration>('debug').showInStatusBar;
if (this.showInStatusBar === 'always') {
this.doRender();
}
if (this.statusBarItem) {
dom.toggleClass(this.statusBarItem, 'hidden', this.showInStatusBar === 'never');
setShowInStatusBar();
if (this.entryAccessor && this.showInStatusBar === 'never') {
this.entryAccessor.dispose();
this.entryAccessor = undefined;
}
}
}));
this.toDispose.push(this.debugService.getConfigurationManager().onDidSelectConfiguration(e => {
if (this.entryAccessor) {
this.entryAccessor.update(this.entry);
}
}));
}
protected updateStyles(): void {
if (this.icon) {
if (isStatusbarInDebugMode(this.debugService)) {
this.icon.style.backgroundColor = this.getColor(STATUS_BAR_DEBUGGING_FOREGROUND);
} else {
this.icon.style.backgroundColor = this.getColor(STATUS_BAR_FOREGROUND);
}
private getText(): string {
const manager = this.debugService.getConfigurationManager();
const name = manager.selectedConfiguration.name || '';
const nameAndLaunchPresent = name && manager.selectedConfiguration.launch;
if (nameAndLaunchPresent) {
return '$(play) ' + (manager.getLaunches().length > 1 ? `${name} (${manager.selectedConfiguration.launch!.name})` : name);
}
return '';
}
public render(container: HTMLElement): IDisposable {
this.container = container;
if (this.showInStatusBar === 'always') {
this.doRender();
}
// noop, we render when we decide is best
return this;
private get entry(): IStatusbarEntry {
return {
text: this.getText(),
tooltip: nls.localize('selectAndStartDebug', "Select and start debug configuration"),
command: 'workbench.action.debug.selectandstart'
};
}
private doRender(): void {
if (!this.statusBarItem && this.container) {
this.statusBarItem = dom.append(this.container, $('.debug-statusbar-item'));
this._register(dom.addDisposableListener(this.statusBarItem, 'click', () => this.quickOpenService.show('debug ')));
this.statusBarItem.title = nls.localize('selectAndStartDebug', "Select and start debug configuration");
const a = dom.append(this.statusBarItem, $('a'));
this.icon = dom.append(a, $('.icon'));
this.label = dom.append(a, $('span.label'));
this.setLabel();
}
this.updateStyles();
}
private setLabel(): void {
if (this.label && this.statusBarItem) {
const manager = this.debugService.getConfigurationManager();
const name = manager.selectedConfiguration.name || '';
const nameAndLaunchPresent = name && manager.selectedConfiguration.launch;
dom.toggleClass(this.statusBarItem, 'hidden', this.showInStatusBar === 'never' || !nameAndLaunchPresent);
if (nameAndLaunchPresent) {
this.label.textContent = manager.getLaunches().length > 1 ? `${name} (${manager.selectedConfiguration.launch!.name})` : name;
}
dispose(): void {
if (this.entryAccessor) {
this.entryAccessor.dispose();
}
dispose(this.toDispose);
}
}

View File

@@ -9,7 +9,7 @@ import * as browser from 'vs/base/browser/browser';
import * as dom from 'vs/base/browser/dom';
import * as arrays from 'vs/base/common/arrays';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { IAction, IRunEvent } from 'vs/base/common/actions';
import { IAction, IRunEvent, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
import { ActionBar, ActionsOrientation, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
@@ -27,10 +27,11 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { INotificationService } from 'vs/platform/notification/common/notification';
import { RunOnceScheduler } from 'vs/base/common/async';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { fillInActionBarActions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { createAndFillInActionBarActions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenu, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { FocusSessionAction } from 'vs/workbench/contrib/debug/browser/debugActions';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
const DEBUG_TOOLBAR_POSITION_KEY = 'debug.actionswidgetposition';
const DEBUG_TOOLBAR_Y_KEY = 'debug.actionswidgety';
@@ -54,6 +55,7 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
private activeActions: IAction[];
private updateScheduler: RunOnceScheduler;
private debugToolBarMenu: IMenu;
private disposeOnUpdate: IDisposable;
private isVisible: boolean;
private isBuilt: boolean;
@@ -81,7 +83,7 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
const actionBarContainer = dom.append(this.$el, dom.$('div.action-bar-container'));
this.debugToolBarMenu = menuService.createMenu(MenuId.DebugToolBar, contextKeyService);
this.toDispose.push(this.debugToolBarMenu);
this._register(this.debugToolBarMenu);
this.activeActions = [];
this.actionBar = this._register(new ActionBar(actionBarContainer, {
@@ -105,12 +107,17 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
return this.hide();
}
const actions = DebugToolBar.getActions(this.debugToolBarMenu, this.debugService, this.instantiationService);
const { actions, disposable } = DebugToolBar.getActions(this.debugToolBarMenu, this.debugService, this.instantiationService);
if (!arrays.equals(actions, this.activeActions, (first, second) => first.id === second.id)) {
this.actionBar.clear();
this.actionBar.push(actions, { icon: true, label: false });
this.activeActions = actions;
}
if (this.disposeOnUpdate) {
dispose(this.disposeOnUpdate);
}
this.disposeOnUpdate = disposable;
this.show();
}, 20));
@@ -134,13 +141,7 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
// log in telemetry
if (this.telemetryService) {
/* __GDPR__
"workbenchActionExecuted" : {
"id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('workbenchActionExecuted', { id: e.action.id, from: 'debugActionsWidget' });
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id: e.action.id, from: 'debugActionsWidget' });
}
}));
this._register(dom.addDisposableListener(window, dom.EventType.RESIZE, () => this.setCoordinates()));
@@ -263,14 +264,17 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
dom.hide(this.$el);
}
public static getActions(menu: IMenu, debugService: IDebugService, instantiationService: IInstantiationService): IAction[] {
public static getActions(menu: IMenu, debugService: IDebugService, instantiationService: IInstantiationService): { actions: IAction[], disposable: IDisposable } {
const actions: IAction[] = [];
fillInActionBarActions(menu, undefined, actions, () => false);
const disposable = createAndFillInActionBarActions(menu, undefined, actions, () => false);
if (debugService.getViewModel().isMultiSessionView()) {
actions.push(instantiationService.createInstance(FocusSessionAction, FocusSessionAction.ID, FocusSessionAction.LABEL));
}
return actions.filter(a => !(a instanceof Separator)); // do not render separators for now
return {
actions: actions.filter(a => !(a instanceof Separator)), // do not render separators for now
disposable
};
}
public dispose(): void {
@@ -280,5 +284,8 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
this.$el.remove();
delete this.$el;
}
if (this.disposeOnUpdate) {
dispose(this.disposeOnUpdate);
}
}
}

View File

@@ -14,7 +14,7 @@ import { StartAction, ConfigureAction, SelectAndStartAction, FocusSessionAction
import { StartDebugActionViewItem, FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress';
import { IProgressService } from 'vs/platform/progress/common/progress';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IStorageService } from 'vs/platform/storage/common/storage';
@@ -37,10 +37,11 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
export class DebugViewlet extends ViewContainerViewlet {
private startDebugActionViewItem: StartDebugActionViewItem;
private progressRunner: IProgressRunner;
private progressResolve: (() => void) | undefined;
private breakpointView: ViewletPanel;
private panelListeners = new Map<string, IDisposable>();
private debugToolBarMenu: IMenu;
private disposeOnTitleUpdate: IDisposable;
constructor(
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@@ -112,9 +113,16 @@ export class DebugViewlet extends ViewContainerViewlet {
if (!this.debugToolBarMenu) {
this.debugToolBarMenu = this.menuService.createMenu(MenuId.DebugToolBar, this.contextKeyService);
this.toDispose.push(this.debugToolBarMenu);
this._register(this.debugToolBarMenu);
}
return DebugToolBar.getActions(this.debugToolBarMenu, this.debugService, this.instantiationService);
const { actions, disposable } = DebugToolBar.getActions(this.debugToolBarMenu, this.debugService, this.instantiationService);
if (this.disposeOnTitleUpdate) {
dispose(this.disposeOnTitleUpdate);
}
this.disposeOnTitleUpdate = disposable;
return actions;
}
get showInitialDebugActions(): boolean {
@@ -153,12 +161,15 @@ export class DebugViewlet extends ViewContainerViewlet {
}
private onDebugServiceStateChange(state: State): void {
if (this.progressRunner) {
this.progressRunner.done();
if (this.progressResolve) {
this.progressResolve();
this.progressResolve = undefined;
}
if (state === State.Initializing) {
this.progressRunner = this.progressService.show(true);
this.progressService.withProgress({ location: VIEWLET_ID }, _progress => {
return new Promise(resolve => this.progressResolve = resolve);
});
}
this.updateToolBar();

View File

@@ -35,12 +35,12 @@ export class ExceptionWidget extends ZoneWidget {
this._backgroundColor = Color.white;
this._applyTheme(themeService.getTheme());
this._disposables.push(themeService.onThemeChange(this._applyTheme.bind(this)));
this._disposables.add(themeService.onThemeChange(this._applyTheme.bind(this)));
this.create();
const onDidLayoutChangeScheduler = new RunOnceScheduler(() => this._doLayout(undefined, undefined), 50);
this._disposables.push(this.editor.onDidLayoutChange(() => onDidLayoutChangeScheduler.schedule()));
this._disposables.push(onDidLayoutChangeScheduler);
this._disposables.add(this.editor.onDidLayoutChange(() => onDidLayoutChangeScheduler.schedule()));
this._disposables.add(onDidLayoutChangeScheduler);
}
private _applyTheme(theme: ITheme): void {

View File

@@ -19,7 +19,7 @@ export class LinkDetector {
// group 2: drive letter on windows with trailing backslash or leading slash on mac/linux
// group 3: line number, matched by (:(\d+))
// group 4: column number, matched by ((?::(\d+))?)
// eg: at Context.<anonymous> (c:\Users\someone\Desktop\mocha-runner\test\test.js:26:11)
// e.g.: at Context.<anonymous> (c:\Users\someone\Desktop\mocha-runner\test\test.js:26:11)
/(?![\(])(?:file:\/\/)?((?:([a-zA-Z]+:)|[^\(\)<>\'\"\[\]:\s]+)(?:[\\/][^\(\)<>\'\"\[\]:]*)?\.[a-zA-Z]+[0-9]*):(\d+)(?::(\d+))?/g
];

View File

@@ -45,16 +45,15 @@ type LoadedScriptsItem = BaseTreeItem;
class BaseTreeItem {
private _showedMoreThanOne: boolean;
private _children: { [key: string]: BaseTreeItem; };
private _children = new Map<string, BaseTreeItem>();
private _source: Source;
constructor(private _parent: BaseTreeItem | undefined, private _label: string) {
this._children = {};
this._showedMoreThanOne = false;
}
isLeaf(): boolean {
return Object.keys(this._children).length === 0;
return this._children.size === 0;
}
getSession(): IDebugSession | undefined {
@@ -66,12 +65,12 @@ class BaseTreeItem {
setSource(session: IDebugSession, source: Source): void {
this._source = source;
this._children = {};
this._children.clear();
if (source.raw && source.raw.sources) {
for (const src of source.raw.sources) {
if (src.name && src.path) {
const s = new BaseTreeItem(this, src.name);
this._children[src.path] = s;
this._children.set(src.path, s);
const ss = session.getSource(src);
s.setSource(session, ss);
}
@@ -80,26 +79,26 @@ class BaseTreeItem {
}
createIfNeeded<T extends BaseTreeItem>(key: string, factory: (parent: BaseTreeItem, label: string) => T): T {
let child = <T>this._children[key];
let child = <T>this._children.get(key);
if (!child) {
child = factory(this, key);
this._children[key] = child;
this._children.set(key, child);
}
return child;
}
getChild(key: string): BaseTreeItem {
return this._children[key];
getChild(key: string): BaseTreeItem | undefined {
return this._children.get(key);
}
remove(key: string): void {
delete this._children[key];
this._children.delete(key);
}
removeFromParent(): void {
if (this._parent) {
this._parent.remove(this._label);
if (Object.keys(this._parent._children).length === 0) {
if (this._parent._children.size === 0) {
this._parent.removeFromParent();
}
}
@@ -142,7 +141,7 @@ class BaseTreeItem {
if (child) {
return child.hasChildren();
}
return Object.keys(this._children).length > 0;
return this._children.size > 0;
}
// skips intermediate single-child nodes
@@ -151,7 +150,10 @@ class BaseTreeItem {
if (child) {
return child.getChildren();
}
const array = Object.keys(this._children).map(key => this._children[key]);
const array: BaseTreeItem[] = [];
for (let child of this._children.values()) {
array.push(child);
}
return Promise.resolve(array.sort((a, b) => this.compare(a, b)));
}
@@ -199,12 +201,11 @@ class BaseTreeItem {
private oneChild(): BaseTreeItem | undefined {
if (SMART && !this._source && !this._showedMoreThanOne && !(this instanceof RootFolderTreeItem) && !(this instanceof SessionTreeItem)) {
const keys = Object.keys(this._children);
if (keys.length === 1) {
return this._children[keys[0]];
if (this._children.size === 1) {
return this._children.values().next().value;
}
// if a node had more than one child once, it will never be skipped again
if (keys.length > 1) {
if (this._children.size > 1) {
this._showedMoreThanOne = true;
}
}
@@ -243,7 +244,7 @@ class SessionTreeItem extends BaseTreeItem {
private _session: IDebugSession;
private _initialized: boolean;
private _map: Map<string, BaseTreeItem>;
private _map = new Map<string, BaseTreeItem>();
private _labelService: ILabelService;
constructor(labelService: ILabelService, parent: BaseTreeItem, session: IDebugSession, private _environmentService: IEnvironmentService, private rootProvider: IWorkspaceContextService) {
@@ -251,7 +252,6 @@ class SessionTreeItem extends BaseTreeItem {
this._labelService = labelService;
this._initialized = false;
this._session = session;
this._map = new Map();
}
getSession(): IDebugSession {
@@ -417,7 +417,7 @@ export class LoadedScriptsView extends ViewletPanel {
const root = new RootTreeItem(this.debugService.getModel(), this.environmentService, this.contextService, this.labelService);
this.treeLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility });
this.disposables.push(this.treeLabels);
this._register(this.treeLabels);
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, this.treeContainer, new LoadedScriptsDelegate(),
[new LoadedScriptsRenderer(this.treeLabels)],
@@ -443,11 +443,11 @@ export class LoadedScriptsView extends ViewletPanel {
this.tree.updateChildren();
}
}, 300);
this.disposables.push(this.changeScheduler);
this._register(this.changeScheduler);
const loadedScriptsNavigator = new TreeResourceNavigator2(this.tree);
this.disposables.push(loadedScriptsNavigator);
this.disposables.push(loadedScriptsNavigator.onDidOpenResource(e => {
this._register(loadedScriptsNavigator);
this._register(loadedScriptsNavigator.onDidOpenResource(e => {
if (e.element instanceof BaseTreeItem) {
const source = e.element.getSource();
if (source && source.available) {
@@ -457,7 +457,7 @@ export class LoadedScriptsView extends ViewletPanel {
}
}));
this.disposables.push(this.tree.onDidChangeFocus(() => {
this._register(this.tree.onDidChangeFocus(() => {
const focus = this.tree.getFocus();
if (focus instanceof SessionTreeItem) {
this.loadedScriptsItemType.set('session');
@@ -467,7 +467,7 @@ export class LoadedScriptsView extends ViewletPanel {
}));
const registerLoadedSourceListener = (session: IDebugSession) => {
this.disposables.push(session.onDidLoadedSource(event => {
this._register(session.onDidLoadedSource(event => {
let sessionRoot: SessionTreeItem;
switch (event.reason) {
case 'new':
@@ -501,17 +501,17 @@ export class LoadedScriptsView extends ViewletPanel {
}));
};
this.disposables.push(this.debugService.onDidNewSession(registerLoadedSourceListener));
this._register(this.debugService.onDidNewSession(registerLoadedSourceListener));
this.debugService.getModel().getSessions().forEach(registerLoadedSourceListener);
this.disposables.push(this.debugService.onDidEndSession(session => {
this._register(this.debugService.onDidEndSession(session => {
root.remove(session.getId());
this.changeScheduler.schedule();
}));
this.changeScheduler.schedule(0);
this.disposables.push(this.onDidChangeBodyVisibility(visible => {
this._register(this.onDidChangeBodyVisibility(visible => {
if (visible && this.treeNeedsRefreshOnVisible) {
this.changeScheduler.schedule();
}

View File

@@ -1,3 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 3H11V13H13V3ZM8.5 3V13L2 8L8.5 3Z" fill="#75BEFF"/>
<path d="M14 7V8H8V14H7V8H1V7H7V1H8V7H14Z" fill="#C5C5C5"/>
</svg>

Before

Width:  |  Height:  |  Size: 168 B

After

Width:  |  Height:  |  Size: 163 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent{fill:#f6f6f6;opacity:0;}.icon-white{fill:#fff;}</style></defs><title>add-focus</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,16H0V0H16Z"/></g><g id="iconBg"><path class="icon-white" d="M13,7V9H9v4H7V9H3V7H7V3H9V7Z"/></g></svg>

Before

Width:  |  Height:  |  Size: 345 B

View File

@@ -1,3 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 3H11V13H13V3ZM8.5 3V13L2 8L8.5 3Z" fill="#00539C"/>
<path d="M14 7V8H8V14H7V8H1V7H7V1H8V7H14Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 168 B

After

Width:  |  Height:  |  Size: 161 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#252526;}.icon-canvas-transparent{opacity:0;}.icon-vs-bg{fill:#c5c5c5;}</style></defs><title>add</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,16H0V0H16Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M14,6v4H10v4H6V10H2V6H6V2h4V6Z"/></g><g id="iconBg"><path class="icon-vs-bg" d="M13,7V9H9v4H7V9H3V7H7V3H9V7Z"/></g></svg>

Before

Width:  |  Height:  |  Size: 486 B

View File

@@ -0,0 +1,3 @@
<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>

After

Width:  |  Height:  |  Size: 163 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-vs-bg{fill:#424242;}</style></defs><title>add</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,16H0V0H16Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M14,6v4H10v4H6V10H2V6H6V2h4V6Z"/></g><g id="iconBg"><path class="icon-vs-bg" d="M13,7V9H9v4H7V9H3V7H7V3H9V7Z"/></g></svg>

Before

Width:  |  Height:  |  Size: 486 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1,.icon-vs-out{fill:#f6f6f6;}.cls-1{fill-opacity:0;}.icon-disabled-grey{fill:#848484;}.icon-white{fill:#fff;}</style></defs><title>breakpoint-conditional-disabled</title><g id="canvas"><path class="cls-1" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M12.8,8A4.8,4.8,0,1,1,8,3.2,4.806,4.806,0,0,1,12.8,8Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M11.8,8A3.8,3.8,0,1,1,8,4.2,3.8,3.8,0,0,1,11.8,8Z"/><path class="icon-white" d="M10.1,6.7v.8H5.9V6.7ZM5.9,9.2h4.2V8.4H5.9Z"/></g></svg>
<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="#848484"/>
</svg>

Before

Width:  |  Height:  |  Size: 620 B

After

Width:  |  Height:  |  Size: 327 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-disabled-grey{fill:#848484;}</style></defs><title>breakpoint-conditional-unverified</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M12.632,8A4.632,4.632,0,1,1,8,3.368,4.638,4.638,0,0,1,12.632,8Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M6.526,8.421H9.474v.842H6.526ZM11.789,8A3.789,3.789,0,1,1,8,4.211,3.788,3.788,0,0,1,11.789,8Zm-1,0A2.789,2.789,0,1,0,8,10.79,2.793,2.793,0,0,0,10.789,8ZM6.526,7.579H9.474V6.737H6.526Z"/></g></svg>
<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 10.75C9.51878 10.75 10.75 9.51878 10.75 8C10.75 6.48122 9.51878 5.25 8 5.25C6.48122 5.25 5.25 6.48122 5.25 8C5.25 9.51878 6.48122 10.75 8 10.75ZM8 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 12ZM9.5 6.5V7.5H6.5V6.5H9.5ZM9.5 9.5V8.5H6.5V9.5H9.5Z" fill="#848484"/>
</svg>

Before

Width:  |  Height:  |  Size: 719 B

After

Width:  |  Height:  |  Size: 476 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1,.icon-vs-out{fill:#f6f6f6;}.cls-1{fill-opacity:0;}.icon-vs-red{fill:#e51400;}.icon-white{fill:#fff;}</style></defs><title>breakpoint-conditional</title><g id="canvas"><path class="cls-1" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M12.8,8A4.8,4.8,0,1,1,8,3.2,4.806,4.806,0,0,1,12.8,8Z"/></g><g id="iconBg"><path class="icon-vs-red" d="M11.8,8A3.8,3.8,0,1,1,8,4.2,3.8,3.8,0,0,1,11.8,8Z"/><path class="icon-white" d="M10.1,6.7v.8H5.9V6.7ZM5.9,9.2h4.2V8.4H5.9Z"/></g></svg>
<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: 597 B

After

Width:  |  Height:  |  Size: 327 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-disabled-grey{fill:#848484;}</style></defs><title>breakpoint-disabled</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M12.632,8A4.632,4.632,0,1,1,8,3.368,4.638,4.638,0,0,1,12.632,8Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M11.789,8A3.789,3.789,0,1,1,8,4.211,3.788,3.788,0,0,1,11.789,8Z"/></g></svg>
<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: 585 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-disabled-grey{fill:#848484;}</style></defs><title>breakpoint-function-disabled</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M13.7,13H2.3L8,2.741Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M12,12H4L8,4.8Z"/></g></svg>
<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: 504 B

After

Width:  |  Height:  |  Size: 153 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-disabled-grey{fill:#848484;}</style></defs><title>breakpoint-function-unverified</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M13.95,13H2.05L8,2.291Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M8,4.35,3.75,12h8.5ZM8,6.924l2.125,3.826H5.875Z"/></g></svg>
<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: 540 B

After

Width:  |  Height:  |  Size: 200 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-vs-red{fill:#e51400;}</style></defs><title>breakpoint-function</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M13.7,13H2.3L8,2.741Z"/></g><g id="iconBg"><path class="icon-vs-red" d="M12,12H4L8,4.8Z"/></g></svg>
<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: 481 B

After

Width:  |  Height:  |  Size: 153 B

View File

@@ -1 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.cls-1{fill:#e51400;opacity:0.4;}</style></defs><title>breakpoint-hint</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M12.632,8A4.632,4.632,0,1,1,8,3.368,4.638,4.638,0,0,1,12.632,8Z"/></g><g id="iconBg"><path class="cls-1" d="M11.789,8A3.789,3.789,0,1,1,8,4.211,3.788,3.788,0,0,1,11.789,8Z"/></g></svg>
<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: 567 B

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-disabled-grey{fill:#848484;}</style></defs><title>breakpoint-log-disabled</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M13.414,8,8,13.414,2.586,8,8,2.586Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M12,8,8,12,4,8,8,4Z"/></g></svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 4L12 8L8 12L4 8L8 4Z" fill="#848484"/>
</svg>

Before

Width:  |  Height:  |  Size: 517 B

After

Width:  |  Height:  |  Size: 154 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-disabled-grey{fill:#848484;}</style></defs><title>breakpoint-log-unverified</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M13.664,8,8,13.664,2.336,8,8,2.336Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M8,3.75,3.75,8,8,12.25,12.25,8ZM5.518,8,8,5.518,10.482,8,8,10.482Z"/></g></svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 4.84323L11.1365 7.97969L8 11.1161L4.86355 7.97969L8 4.84323Z" stroke="#848484" stroke-width="1.25"/>
</svg>

Before

Width:  |  Height:  |  Size: 566 B

After

Width:  |  Height:  |  Size: 216 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-vs-red{fill:#e51400;}</style></defs><title>breakpoint-log</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M13.414,8,8,13.414,2.586,8,8,2.586Z"/></g><g id="iconBg"><path class="icon-vs-red" d="M12,8,8,12,4,8,8,4Z"/></g></svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 4L12 8L8 12L4 8L8 4Z" fill="#E51400"/>
</svg>

Before

Width:  |  Height:  |  Size: 494 B

After

Width:  |  Height:  |  Size: 154 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-vs-red{fill:#e51400;}.icon-white{fill:#fff;}</style></defs><title>breakpoint-unsupported</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M12.632,8A4.632,4.632,0,1,1,8,3.368,4.638,4.638,0,0,1,12.632,8Z"/></g><g id="iconBg"><path class="icon-vs-red" d="M11.789,8A3.789,3.789,0,1,1,8,4.211,3.788,3.788,0,0,1,11.789,8Z"/><path class="icon-white" d="M7.5,9.5h1v1h-1Zm0-4v3h1v-3Z"/></g></svg>
<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.4 9.6H7.6V10.4H8.4V9.6ZM7.6 8.8V5.6H8.4V8.8H7.6Z" fill="#E51400"/>
</svg>

Before

Width:  |  Height:  |  Size: 656 B

After

Width:  |  Height:  |  Size: 774 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-disabled-grey{fill:#848484;}</style></defs><title>breakpoint-unverified</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M12.632,8A4.632,4.632,0,1,1,8,3.368,4.638,4.638,0,0,1,12.632,8Z"/></g><g id="iconBg"><path class="icon-disabled-grey" d="M8,4.211A3.789,3.789,0,1,0,11.79,8,3.788,3.788,0,0,0,8,4.211ZM8,10.29A2.29,2.29,0,1,1,10.29,8,2.292,2.292,0,0,1,8,10.29Z"/></g></svg>
<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: 644 B

After

Width:  |  Height:  |  Size: 583 B

View File

@@ -1 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-vs-red{fill:#e51400;}</style></defs><title>breakpoint</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M12.632,8A4.632,4.632,0,1,1,8,3.368,4.638,4.638,0,0,1,12.632,8Z"/></g><g id="iconBg"><path class="icon-vs-red" d="M11.789,8A3.789,3.789,0,1,1,8,4.211,3.788,3.788,0,0,1,11.789,8Z"/></g></svg>
<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: 562 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -18,6 +18,5 @@
.monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .inputContainer {
flex: 1;
margin-top: 6px;
margin-bottom: 6px;
margin-top: 8px;
}

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#252526;}.icon-canvas-transparent{opacity:0;}.icon-vs-bg{fill:#c5c5c5;}</style></defs><title>breakpoints-activate</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M16,5.5A5.536,5.536,0,0,1,11,11a5.536,5.536,0,0,1-5.5,5A5.549,5.549,0,0,1,0,10.5,5.465,5.465,0,0,1,5,5a5.512,5.512,0,0,1,11,.5Z"/></g><g id="iconBg"><path class="icon-vs-bg" d="M15,5.5A4.395,4.395,0,0,1,11,10a2.957,2.957,0,0,0-.2-1A3.565,3.565,0,0,0,14,5.5a3.507,3.507,0,0,0-7-.3A3.552,3.552,0,0,0,6,5a4.622,4.622,0,0,1,4.5-4A4.481,4.481,0,0,1,15,5.5ZM5.5,6A4.5,4.5,0,1,0,10,10.5,4.5,4.5,0,0,0,5.5,6Z"/></g></svg>

Before

Width:  |  Height:  |  Size: 795 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-vs-bg{fill:#424242;}</style></defs><title>breakpoints-activate</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M16,5.5A5.536,5.536,0,0,1,11,11a5.536,5.536,0,0,1-5.5,5A5.549,5.549,0,0,1,0,10.5,5.465,5.465,0,0,1,5,5a5.512,5.512,0,0,1,11,.5Z"/></g><g id="iconBg"><path class="icon-vs-bg" d="M15,5.5A4.395,4.395,0,0,1,11,10a2.957,2.957,0,0,0-.2-1A3.565,3.565,0,0,0,14,5.5a3.507,3.507,0,0,0-7-.3A3.552,3.552,0,0,0,6,5a4.622,4.622,0,0,1,4.5-4A4.481,4.481,0,0,1,15,5.5ZM5.5,6A4.5,4.5,0,1,0,10,10.5,4.5,4.5,0,0,0,5.5,6Z"/></g></svg>

Before

Width:  |  Height:  |  Size: 794 B

View File

@@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="#C5C5C5"/>
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="#C5C5C5"/>
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="#C5C5C5"/>
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="#C5C5C5"/>
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="#C5C5C5"/>
</svg>

After

Width:  |  Height:  |  Size: 484 B

View File

@@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="white"/>
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="white"/>
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="white"/>
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="white"/>
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 474 B

View File

@@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="#424242"/>
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="#424242"/>
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="#424242"/>
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="#424242"/>
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="#424242"/>
</svg>

After

Width:  |  Height:  |  Size: 484 B

View File

@@ -1 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.065 13H15v2H2.056v-2h5.009zm3.661-12H7.385L8.44 2.061 7.505 3H15V1h-4.274zM3.237 9H2.056v2H15V9H3.237zm4.208-4l.995 1-.995 1H15V5H7.445z" fill="#C5C5C5"/><path d="M5.072 4.03L7.032 6 5.978 7.061l-1.96-1.97-1.961 1.97L1 6l1.96-1.97L1 2.061 2.056 1l1.96 1.97L5.977 1l1.057 1.061L5.072 4.03z" fill="#F48771"/></svg>

Before

Width:  |  Height:  |  Size: 419 B

View File

@@ -1 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.065 13H15v2H2.056v-2h5.009zm3.661-12H7.385L8.44 2.061 7.505 3H15V1h-4.274zM3.237 9H2.056v2H15V9H3.237zm4.208-4l.995 1-.995 1H15V5H7.445z" fill="#424242"/><path d="M5.072 4.03L7.032 6 5.978 7.061l-1.96-1.97-1.961 1.97L1 6l1.96-1.97L1 2.061 2.056 1l1.96 1.97L5.977 1l1.057 1.061L5.072 4.03z" fill="#A1260D"/></svg>

Before

Width:  |  Height:  |  Size: 419 B

View File

@@ -0,0 +1,4 @@
<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>

After

Width:  |  Height:  |  Size: 532 B

View File

@@ -0,0 +1,4 @@
<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>

After

Width:  |  Height:  |  Size: 528 B

View File

@@ -0,0 +1,4 @@
<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>

After

Width:  |  Height:  |  Size: 532 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#252526;}.icon-canvas-transparent{opacity:0;}.icon-vs-bg{fill:#c5c5c5;}</style></defs><title>configure</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M16,10.015l-2.238.372,1.318,1.847L12.233,15.08l-1.847-1.318L10.013,16H5.986l-.373-2.237L3.767,15.08.919,12.233l1.319-1.847L0,10.013V5.986l2.238-.373L.919,3.767,3.768.919,5.613,2.238,5.986,0h4.028l.372,2.238L12.233.919,15.08,3.768,13.762,5.613,16,5.986Z"/></g><g id="iconBg"><path class="icon-vs-bg" d="M12.876,9.521,15,9.167V6.834L12.879,6.48a5.12,5.12,0,0,0-.354-.854l1.25-1.75-1.65-1.65L10.373,3.477c-.137-.072-.262-.159-.408-.219s-.3-.087-.444-.133L9.167,1H6.834L6.48,3.121a5.118,5.118,0,0,0-.854.354l-1.75-1.25-1.65,1.65L3.477,5.627c-.072.137-.159.262-.219.408s-.087.3-.133.444L1,6.833V9.166l2.121.354a5.122,5.122,0,0,0,.354.854l-1.25,1.75,1.65,1.65,1.752-1.252c.137.072.262.159.408.22s.3.087.444.133L6.833,15H9.166l.354-2.121a5.121,5.121,0,0,0,.854-.354l1.75,1.25,1.65-1.65-1.252-1.752c.072-.137.159-.263.219-.409S12.83,9.669,12.876,9.521ZM8,10.212A2.212,2.212,0,1,1,10.212,8,2.212,2.212,0,0,1,8,10.212Z"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-vs-bg{fill:#424242;}</style></defs><title>configure</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M16,10.015l-2.238.372,1.318,1.847L12.233,15.08l-1.847-1.318L10.013,16H5.986l-.373-2.237L3.767,15.08.919,12.233l1.319-1.847L0,10.013V5.986l2.238-.373L.919,3.767,3.768.919,5.613,2.238,5.986,0h4.028l.372,2.238L12.233.919,15.08,3.768,13.762,5.613,16,5.986Z"/></g><g id="iconBg"><path class="icon-vs-bg" d="M12.876,9.521,15,9.167V6.834L12.879,6.48a5.12,5.12,0,0,0-.354-.854l1.25-1.75-1.65-1.65L10.373,3.477c-.137-.072-.262-.159-.408-.219s-.3-.087-.444-.133L9.167,1H6.834L6.48,3.121a5.118,5.118,0,0,0-.854.354l-1.75-1.25-1.65,1.65L3.477,5.627c-.072.137-.159.262-.219.408s-.087.3-.133.444L1,6.833V9.166l2.121.354a5.122,5.122,0,0,0,.354.854l-1.25,1.75,1.65,1.65,1.752-1.252c.137.072.262.159.408.22s.3.087.444.133L6.833,15H9.166l.354-2.121a5.121,5.121,0,0,0,.854-.354l1.75,1.25,1.65-1.65-1.252-1.752c.072-.137.159-.263.219-.409S12.83,9.669,12.876,9.521ZM8,10.212A2.212,2.212,0,1,1,10.212,8,2.212,2.212,0,0,1,8,10.212Z"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,3 @@
<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>

After

Width:  |  Height:  |  Size: 339 B

View File

@@ -0,0 +1,3 @@
<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>

After

Width:  |  Height:  |  Size: 337 B

View File

@@ -0,0 +1,3 @@
<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>

After

Width:  |  Height:  |  Size: 339 B

View File

@@ -0,0 +1,3 @@
<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>

After

Width:  |  Height:  |  Size: 300 B

Some files were not shown because too many files have changed in this diff Show More