mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode 4f85c3c94c15457e1d4c9e67da6800630394ea54 (#8757)
* Merge from vscode 4f85c3c94c15457e1d4c9e67da6800630394ea54 * disable failing tests
This commit is contained in:
@@ -34,7 +34,8 @@ export function getSimpleEditorOptions(): IEditorOptions {
|
||||
acceptSuggestionOnEnter: 'smart',
|
||||
minimap: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
renderIndentGuides: false
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -68,8 +68,8 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IHistoryService historyService: IHistoryService
|
||||
@IHistoryService private readonly historyService: IHistoryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
) {
|
||||
this.configProviders = [];
|
||||
this.adapterDescriptorFactories = [];
|
||||
@@ -83,13 +83,7 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
if (previousSelectedLaunch && previousSelectedLaunch.getConfigurationNames().length) {
|
||||
this.selectConfiguration(previousSelectedLaunch, this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE));
|
||||
} else if (this.launches.length > 0) {
|
||||
const rootUri = historyService.getLastActiveWorkspaceRoot();
|
||||
let launch = this.getLaunch(rootUri);
|
||||
if (!launch || launch.getConfigurationNames().length === 0) {
|
||||
launch = first(this.launches, l => !!(l && l.getConfigurationNames().length), launch) || this.launches[0];
|
||||
}
|
||||
|
||||
this.selectConfiguration(launch);
|
||||
this.selectConfiguration(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,13 +280,13 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
|
||||
this.toDispose.push(Event.any<IWorkspaceFoldersChangeEvent | WorkbenchState>(this.contextService.onDidChangeWorkspaceFolders, this.contextService.onDidChangeWorkbenchState)(() => {
|
||||
this.initLaunches();
|
||||
const toSelect = this.selectedLaunch || (this.launches.length > 0 ? this.launches[0] : undefined);
|
||||
this.selectConfiguration(toSelect);
|
||||
this.selectConfiguration(undefined);
|
||||
this.setCompoundSchemaValues();
|
||||
}));
|
||||
this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('launch')) {
|
||||
this.selectConfiguration(this.selectedLaunch);
|
||||
// A change happen in the launch.json. If there is already a launch configuration selected, do not change the selection.
|
||||
this.selectConfiguration(undefined);
|
||||
this.setCompoundSchemaValues();
|
||||
}
|
||||
}));
|
||||
@@ -306,7 +300,7 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
this.launches.push(this.instantiationService.createInstance(UserLaunch));
|
||||
|
||||
if (this.selectedLaunch && this.launches.indexOf(this.selectedLaunch) === -1) {
|
||||
this.setSelectedLaunch(undefined);
|
||||
this.selectConfiguration(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,10 +349,23 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
}
|
||||
|
||||
selectConfiguration(launch: ILaunch | undefined, name?: string): void {
|
||||
if (typeof launch === 'undefined') {
|
||||
const rootUri = this.historyService.getLastActiveWorkspaceRoot();
|
||||
launch = this.getLaunch(rootUri);
|
||||
if (!launch || launch.getConfigurationNames().length === 0) {
|
||||
launch = first(this.launches, l => !!(l && l.getConfigurationNames().length), launch) || this.launches[0];
|
||||
}
|
||||
}
|
||||
|
||||
const previousLaunch = this.selectedLaunch;
|
||||
const previousName = this.selectedName;
|
||||
this.selectedLaunch = launch;
|
||||
|
||||
this.setSelectedLaunch(launch);
|
||||
if (this.selectedLaunch) {
|
||||
this.storageService.store(DEBUG_SELECTED_ROOT, this.selectedLaunch.uri.toString(), StorageScope.WORKSPACE);
|
||||
} else {
|
||||
this.storageService.remove(DEBUG_SELECTED_ROOT, StorageScope.WORKSPACE);
|
||||
}
|
||||
const names = launch ? launch.getConfigurationNames() : [];
|
||||
if (name && names.indexOf(name) >= 0) {
|
||||
this.setSelectedLaunchName(name);
|
||||
@@ -467,16 +474,6 @@ export class ConfigurationManager implements IConfigurationManager {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.toDispose = dispose(this.toDispose);
|
||||
}
|
||||
|
||||
@@ -4,15 +4,12 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!vs/workbench/contrib/debug/browser/media/repl';
|
||||
import * as nls from 'vs/nls';
|
||||
import { URI as uri } from 'vs/base/common/uri';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { IAction, IActionViewItem, Action } from 'vs/base/common/actions';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { SuggestController } from 'vs/editor/contrib/suggest/suggestController';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
@@ -30,7 +27,7 @@ import { memoize } from 'vs/base/common/decorators';
|
||||
import { dispose, IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { IDebugService, REPL_ID, DEBUG_SCHEME, CONTEXT_IN_DEBUG_REPL, IDebugSession, State, IReplElement, IExpressionContainer, IExpression, IReplElementSource, IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebugService, REPL_ID, DEBUG_SCHEME, CONTEXT_IN_DEBUG_REPL, IDebugSession, State, IReplElement, IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { HistoryNavigator } from 'vs/base/common/history';
|
||||
import { IHistoryNavigationWidget } from 'vs/base/browser/history';
|
||||
import { createAndBindHistoryNavigationWidgetScopedContextKeyService } from 'vs/platform/browser/contextScopedHistoryWidget';
|
||||
@@ -43,27 +40,21 @@ import { FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/d
|
||||
import { CompletionContext, CompletionList, CompletionProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { first } from 'vs/base/common/arrays';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { Variable } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
import { CachedListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { ITreeRenderer, ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
|
||||
import { ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { renderExpressionValue, AbstractExpressionsRenderer, IExpressionTemplateData, renderVariable, IInputBoxOptions } from 'vs/workbench/contrib/debug/browser/baseDebugView';
|
||||
import { handleANSIOutput } from 'vs/workbench/contrib/debug/browser/debugANSIHandling';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { removeAnsiEscapeCodes } from 'vs/base/common/strings';
|
||||
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||
import { HighlightedLabel, IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { FuzzyScore } from 'vs/base/common/filters';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { PANEL_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { ReplDelegate, ReplVariablesRenderer, ReplSimpleElementsRenderer, ReplEvaluationInputsRenderer, ReplEvaluationResultsRenderer, ReplRawObjectsRenderer, ReplDataSource, ReplAccessibilityProvider } from 'vs/workbench/contrib/debug/browser/replViewer';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -401,17 +392,17 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
|
||||
@memoize
|
||||
private get refreshScheduler(): RunOnceScheduler {
|
||||
return new RunOnceScheduler(() => {
|
||||
return new RunOnceScheduler(async () => {
|
||||
if (!this.tree.getInput()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lastElementVisible = this.tree.scrollTop + this.tree.renderHeight >= this.tree.scrollHeight;
|
||||
this.tree.updateChildren().then(() => {
|
||||
if (lastElementVisible) {
|
||||
// Only scroll if we were scrolled all the way down before tree refreshed #10486
|
||||
revealLastElement(this.tree);
|
||||
}
|
||||
}, errors.onUnexpectedError);
|
||||
await this.tree.updateChildren();
|
||||
if (lastElementVisible) {
|
||||
// Only scroll if we were scrolled all the way down before tree refreshed #10486
|
||||
revealLastElement(this.tree);
|
||||
}
|
||||
}, Repl.REFRESH_DELAY);
|
||||
}
|
||||
|
||||
@@ -442,7 +433,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
// https://github.com/microsoft/TypeScript/issues/32526
|
||||
new ReplDataSource() as IAsyncDataSource<IDebugSession, IReplElement>,
|
||||
{
|
||||
ariaLabel: nls.localize('replAriaLabel', "Read Eval Print Loop Panel"),
|
||||
ariaLabel: localize('replAriaLabel', "Read Eval Print Loop Panel"),
|
||||
accessibilityProvider: new ReplAccessibilityProvider(),
|
||||
identityProvider: { getId: (element: IReplElement) => element.getId() },
|
||||
mouseSupport: false,
|
||||
@@ -482,7 +473,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
[IContextKeyService, scopedContextKeyService], [IPrivateReplService, this]));
|
||||
const options = getSimpleEditorOptions();
|
||||
options.readOnly = true;
|
||||
options.ariaLabel = nls.localize('debugConsole', "Debug Console");
|
||||
options.ariaLabel = localize('debugConsole', "Debug Console");
|
||||
|
||||
this.replInput = this.scopedInstantiationService.createInstance(CodeEditorWidget, this.replInputContainer, options, getSimpleCodeEditorWidgetOptions());
|
||||
|
||||
@@ -505,18 +496,18 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
|
||||
private onContextMenu(e: ITreeContextMenuEvent<IReplElement>): void {
|
||||
const actions: IAction[] = [];
|
||||
actions.push(new Action('debug.replCopy', nls.localize('copy', "Copy"), undefined, true, async () => {
|
||||
actions.push(new Action('debug.replCopy', localize('copy', "Copy"), undefined, true, async () => {
|
||||
const nativeSelection = window.getSelection();
|
||||
if (nativeSelection) {
|
||||
await this.clipboardService.writeText(nativeSelection.toString());
|
||||
}
|
||||
return Promise.resolve();
|
||||
}));
|
||||
actions.push(new Action('workbench.debug.action.copyAll', nls.localize('copyAll', "Copy All"), undefined, true, async () => {
|
||||
actions.push(new Action('workbench.debug.action.copyAll', localize('copyAll', "Copy All"), undefined, true, async () => {
|
||||
await this.clipboardService.writeText(this.getVisibleContent());
|
||||
return Promise.resolve();
|
||||
}));
|
||||
actions.push(new Action('debug.collapseRepl', nls.localize('collapse', "Collapse All"), undefined, true, () => {
|
||||
actions.push(new Action('debug.collapseRepl', localize('collapse', "Collapse All"), undefined, true, () => {
|
||||
this.tree.collapseAll();
|
||||
this.replInput.focus();
|
||||
return Promise.resolve();
|
||||
@@ -561,7 +552,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
},
|
||||
renderOptions: {
|
||||
after: {
|
||||
contentText: nls.localize('startDebugFirst', "Please start a debug session to evaluate expressions"),
|
||||
contentText: localize('startDebugFirst', "Please start a debug session to evaluate expressions"),
|
||||
color: transparentForeground ? transparentForeground.toString() : undefined
|
||||
}
|
||||
}
|
||||
@@ -588,338 +579,11 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
|
||||
this.replElementsChangeListener.dispose();
|
||||
}
|
||||
this.refreshScheduler.dispose();
|
||||
this.modelChangeListener.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// Repl tree
|
||||
|
||||
interface IReplEvaluationInputTemplateData {
|
||||
label: HighlightedLabel;
|
||||
}
|
||||
|
||||
interface IReplEvaluationResultTemplateData {
|
||||
value: HTMLElement;
|
||||
annotation: HTMLElement;
|
||||
}
|
||||
|
||||
interface ISimpleReplElementTemplateData {
|
||||
container: HTMLElement;
|
||||
value: HTMLElement;
|
||||
source: HTMLElement;
|
||||
getReplElementSource(): IReplElementSource | undefined;
|
||||
toDispose: IDisposable[];
|
||||
}
|
||||
|
||||
interface IRawObjectReplTemplateData {
|
||||
container: HTMLElement;
|
||||
expression: HTMLElement;
|
||||
name: HTMLElement;
|
||||
value: HTMLElement;
|
||||
annotation: HTMLElement;
|
||||
label: HighlightedLabel;
|
||||
}
|
||||
|
||||
class ReplEvaluationInputsRenderer implements ITreeRenderer<ReplEvaluationInput, FuzzyScore, IReplEvaluationInputTemplateData> {
|
||||
static readonly ID = 'replEvaluationInput';
|
||||
|
||||
get templateId(): string {
|
||||
return ReplEvaluationInputsRenderer.ID;
|
||||
}
|
||||
|
||||
renderTemplate(container: HTMLElement): IReplEvaluationInputTemplateData {
|
||||
dom.append(container, $('span.arrow.codicon.codicon-chevron-right'));
|
||||
const input = dom.append(container, $('.expression'));
|
||||
const label = new HighlightedLabel(input, false);
|
||||
return { label };
|
||||
}
|
||||
|
||||
renderElement(element: ITreeNode<ReplEvaluationInput, FuzzyScore>, index: number, templateData: IReplEvaluationInputTemplateData): void {
|
||||
const evaluation = element.element;
|
||||
templateData.label.set(evaluation.value, createMatches(element.filterData));
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IReplEvaluationInputTemplateData): void {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
class ReplEvaluationResultsRenderer implements ITreeRenderer<ReplEvaluationResult, FuzzyScore, IReplEvaluationResultTemplateData> {
|
||||
static readonly ID = 'replEvaluationResult';
|
||||
|
||||
get templateId(): string {
|
||||
return ReplEvaluationResultsRenderer.ID;
|
||||
}
|
||||
|
||||
constructor(private readonly linkDetector: LinkDetector) { }
|
||||
|
||||
renderTemplate(container: HTMLElement): IReplEvaluationResultTemplateData {
|
||||
dom.append(container, $('span.arrow.codicon.codicon-chevron-left'));
|
||||
const output = dom.append(container, $('.evaluation-result.expression'));
|
||||
const value = dom.append(output, $('span.value'));
|
||||
const annotation = dom.append(output, $('span'));
|
||||
|
||||
return { value, annotation };
|
||||
}
|
||||
|
||||
renderElement(element: ITreeNode<ReplEvaluationResult, FuzzyScore>, index: number, templateData: IReplEvaluationResultTemplateData): void {
|
||||
const expression = element.element;
|
||||
renderExpressionValue(expression, templateData.value, {
|
||||
preserveWhitespace: !expression.hasChildren,
|
||||
showHover: false,
|
||||
colorize: true,
|
||||
linkDetector: this.linkDetector
|
||||
});
|
||||
if (expression.hasChildren) {
|
||||
templateData.annotation.className = 'annotation codicon codicon-info';
|
||||
templateData.annotation.title = nls.localize('stateCapture', "Object state is captured from first evaluation");
|
||||
}
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IReplEvaluationResultTemplateData): void {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
class ReplSimpleElementsRenderer implements ITreeRenderer<SimpleReplElement, FuzzyScore, ISimpleReplElementTemplateData> {
|
||||
static readonly ID = 'simpleReplElement';
|
||||
|
||||
constructor(
|
||||
private readonly linkDetector: LinkDetector,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IThemeService private readonly themeService: IThemeService
|
||||
) { }
|
||||
|
||||
get templateId(): string {
|
||||
return ReplSimpleElementsRenderer.ID;
|
||||
}
|
||||
|
||||
renderTemplate(container: HTMLElement): ISimpleReplElementTemplateData {
|
||||
const data: ISimpleReplElementTemplateData = Object.create(null);
|
||||
dom.addClass(container, 'output');
|
||||
const expression = dom.append(container, $('.output.expression.value-and-source'));
|
||||
|
||||
data.container = container;
|
||||
data.value = dom.append(expression, $('span.value'));
|
||||
data.source = dom.append(expression, $('.source'));
|
||||
data.toDispose = [];
|
||||
data.toDispose.push(dom.addDisposableListener(data.source, 'click', e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const source = data.getReplElementSource();
|
||||
if (source) {
|
||||
source.source.openInEditor(this.editorService, {
|
||||
startLineNumber: source.lineNumber,
|
||||
startColumn: source.column,
|
||||
endLineNumber: source.lineNumber,
|
||||
endColumn: source.column
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
renderElement({ element }: ITreeNode<SimpleReplElement, FuzzyScore>, index: number, templateData: ISimpleReplElementTemplateData): void {
|
||||
// value
|
||||
dom.clearNode(templateData.value);
|
||||
// Reset classes to clear ansi decorations since templates are reused
|
||||
templateData.value.className = 'value';
|
||||
const result = handleANSIOutput(element.value, this.linkDetector, this.themeService, element.session);
|
||||
templateData.value.appendChild(result);
|
||||
|
||||
dom.addClass(templateData.value, (element.severity === severity.Warning) ? 'warn' : (element.severity === severity.Error) ? 'error' : (element.severity === severity.Ignore) ? 'ignore' : 'info');
|
||||
templateData.source.textContent = element.sourceData ? `${element.sourceData.source.name}:${element.sourceData.lineNumber}` : '';
|
||||
templateData.source.title = element.sourceData ? this.labelService.getUriLabel(element.sourceData.source.uri) : '';
|
||||
templateData.getReplElementSource = () => element.sourceData;
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: ISimpleReplElementTemplateData): void {
|
||||
dispose(templateData.toDispose);
|
||||
}
|
||||
}
|
||||
|
||||
export class ReplVariablesRenderer extends AbstractExpressionsRenderer {
|
||||
|
||||
static readonly ID = 'replVariable';
|
||||
|
||||
get templateId(): string {
|
||||
return ReplVariablesRenderer.ID;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly linkDetector: LinkDetector,
|
||||
@IDebugService debugService: IDebugService,
|
||||
@IContextViewService contextViewService: IContextViewService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
) {
|
||||
super(debugService, contextViewService, themeService);
|
||||
}
|
||||
|
||||
protected renderExpression(expression: IExpression, data: IExpressionTemplateData, highlights: IHighlight[]): void {
|
||||
renderVariable(expression as Variable, data, true, highlights, this.linkDetector);
|
||||
}
|
||||
|
||||
protected getInputBoxOptions(expression: IExpression): IInputBoxOptions | undefined {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
class ReplRawObjectsRenderer implements ITreeRenderer<RawObjectReplElement, FuzzyScore, IRawObjectReplTemplateData> {
|
||||
static readonly ID = 'rawObject';
|
||||
|
||||
constructor(private readonly linkDetector: LinkDetector) { }
|
||||
|
||||
get templateId(): string {
|
||||
return ReplRawObjectsRenderer.ID;
|
||||
}
|
||||
|
||||
renderTemplate(container: HTMLElement): IRawObjectReplTemplateData {
|
||||
dom.addClass(container, 'output');
|
||||
|
||||
const expression = dom.append(container, $('.output.expression'));
|
||||
const name = dom.append(expression, $('span.name'));
|
||||
const label = new HighlightedLabel(name, false);
|
||||
const value = dom.append(expression, $('span.value'));
|
||||
const annotation = dom.append(expression, $('span'));
|
||||
|
||||
return { container, expression, name, label, value, annotation };
|
||||
}
|
||||
|
||||
renderElement(node: ITreeNode<RawObjectReplElement, FuzzyScore>, index: number, templateData: IRawObjectReplTemplateData): void {
|
||||
// key
|
||||
const element = node.element;
|
||||
templateData.label.set(element.name ? `${element.name}:` : '', createMatches(node.filterData));
|
||||
if (element.name) {
|
||||
templateData.name.textContent = `${element.name}:`;
|
||||
} else {
|
||||
templateData.name.textContent = '';
|
||||
}
|
||||
|
||||
// value
|
||||
renderExpressionValue(element.value, templateData.value, {
|
||||
preserveWhitespace: true,
|
||||
showHover: false,
|
||||
linkDetector: this.linkDetector
|
||||
});
|
||||
|
||||
// annotation if any
|
||||
if (element.annotation) {
|
||||
templateData.annotation.className = 'annotation codicon codicon-info';
|
||||
templateData.annotation.title = element.annotation;
|
||||
} else {
|
||||
templateData.annotation.className = '';
|
||||
templateData.annotation.title = '';
|
||||
}
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IRawObjectReplTemplateData): void {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
class ReplDelegate extends CachedListVirtualDelegate<IReplElement> {
|
||||
|
||||
constructor(private configurationService: IConfigurationService) {
|
||||
super();
|
||||
}
|
||||
|
||||
getHeight(element: IReplElement): number {
|
||||
const config = this.configurationService.getValue<IDebugConfiguration>('debug');
|
||||
|
||||
if (!config.console.wordWrap) {
|
||||
return this.estimateHeight(element, true);
|
||||
}
|
||||
|
||||
return super.getHeight(element);
|
||||
}
|
||||
|
||||
protected estimateHeight(element: IReplElement, ignoreValueLength = false): number {
|
||||
const config = this.configurationService.getValue<IDebugConfiguration>('debug');
|
||||
const rowHeight = Math.ceil(1.4 * config.console.fontSize);
|
||||
const countNumberOfLines = (str: string) => Math.max(1, (str && str.match(/\r\n|\n/g) || []).length);
|
||||
const hasValue = (e: any): e is { value: string } => typeof e.value === 'string';
|
||||
|
||||
// Calculate a rough overestimation for the height
|
||||
// For every 30 characters increase the number of lines needed
|
||||
if (hasValue(element)) {
|
||||
let value = element.value;
|
||||
let valueRows = countNumberOfLines(value) + (ignoreValueLength ? 0 : Math.floor(value.length / 30));
|
||||
|
||||
return valueRows * rowHeight;
|
||||
}
|
||||
|
||||
return rowHeight;
|
||||
}
|
||||
|
||||
getTemplateId(element: IReplElement): string {
|
||||
if (element instanceof Variable && element.name) {
|
||||
return ReplVariablesRenderer.ID;
|
||||
}
|
||||
if (element instanceof ReplEvaluationResult) {
|
||||
return ReplEvaluationResultsRenderer.ID;
|
||||
}
|
||||
if (element instanceof ReplEvaluationInput) {
|
||||
return ReplEvaluationInputsRenderer.ID;
|
||||
}
|
||||
if (element instanceof SimpleReplElement || (element instanceof Variable && !element.name)) {
|
||||
// Variable with no name is a top level variable which should be rendered like a repl element #17404
|
||||
return ReplSimpleElementsRenderer.ID;
|
||||
}
|
||||
|
||||
return ReplRawObjectsRenderer.ID;
|
||||
}
|
||||
|
||||
hasDynamicHeight(element: IReplElement): boolean {
|
||||
// Empty elements should not have dynamic height since they will be invisible
|
||||
return element.toString().length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
function isDebugSession(obj: any): obj is IDebugSession {
|
||||
return typeof obj.getReplElements === 'function';
|
||||
}
|
||||
|
||||
class ReplDataSource implements IAsyncDataSource<IDebugSession, IReplElement> {
|
||||
|
||||
hasChildren(element: IReplElement | IDebugSession): boolean {
|
||||
if (isDebugSession(element)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !!(<IExpressionContainer>element).hasChildren;
|
||||
}
|
||||
|
||||
getChildren(element: IReplElement | IDebugSession): Promise<IReplElement[]> {
|
||||
if (isDebugSession(element)) {
|
||||
return Promise.resolve(element.getReplElements());
|
||||
}
|
||||
if (element instanceof RawObjectReplElement) {
|
||||
return element.getChildren();
|
||||
}
|
||||
|
||||
return (<IExpression>element).getChildren();
|
||||
}
|
||||
}
|
||||
|
||||
class ReplAccessibilityProvider implements IAccessibilityProvider<IReplElement> {
|
||||
getAriaLabel(element: IReplElement): string {
|
||||
if (element instanceof Variable) {
|
||||
return nls.localize('replVariableAriaLabel', "Variable {0} has value {1}, read eval print loop, debug", element.name, element.value);
|
||||
}
|
||||
if (element instanceof SimpleReplElement || element instanceof ReplEvaluationInput || element instanceof ReplEvaluationResult) {
|
||||
return nls.localize('replValueOutputAriaLabel', "{0}, read eval print loop, debug", element.value);
|
||||
}
|
||||
if (element instanceof RawObjectReplElement) {
|
||||
return nls.localize('replRawObjectAriaLabel', "Repl variable {0} has value {1}, read eval print loop, debug", element.name, element.value);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Repl actions and commands
|
||||
|
||||
class AcceptReplInputAction extends EditorAction {
|
||||
@@ -927,7 +591,7 @@ class AcceptReplInputAction extends EditorAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'repl.action.acceptInput',
|
||||
label: nls.localize({ key: 'actions.repl.acceptInput', comment: ['Apply input from the debug console input box'] }, "REPL Accept Input"),
|
||||
label: localize({ key: 'actions.repl.acceptInput', comment: ['Apply input from the debug console input box'] }, "REPL Accept Input"),
|
||||
alias: 'REPL Accept Input',
|
||||
precondition: CONTEXT_IN_DEBUG_REPL,
|
||||
kbOpts: {
|
||||
@@ -949,7 +613,7 @@ class FilterReplAction extends EditorAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'repl.action.filter',
|
||||
label: nls.localize('repl.action.filter', "REPL Focus Content to Filter"),
|
||||
label: localize('repl.action.filter', "REPL Focus Content to Filter"),
|
||||
alias: 'REPL Filter',
|
||||
precondition: CONTEXT_IN_DEBUG_REPL,
|
||||
kbOpts: {
|
||||
@@ -971,7 +635,7 @@ class ReplCopyAllAction extends EditorAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'repl.action.copyAll',
|
||||
label: nls.localize('actions.repl.copyAll', "Debug: Console Copy All"),
|
||||
label: localize('actions.repl.copyAll', "Debug: Console Copy All"),
|
||||
alias: 'Debug Console Copy All',
|
||||
precondition: CONTEXT_IN_DEBUG_REPL,
|
||||
});
|
||||
@@ -1004,7 +668,7 @@ class SelectReplActionViewItem extends FocusSessionActionViewItem {
|
||||
class SelectReplAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.action.debug.selectRepl';
|
||||
static readonly LABEL = nls.localize('selectRepl', "Select Debug Console");
|
||||
static readonly LABEL = localize('selectRepl', "Select Debug Console");
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IDebugService private readonly debugService: IDebugService,
|
||||
@@ -1027,7 +691,7 @@ class SelectReplAction extends Action {
|
||||
|
||||
export class ClearReplAction extends Action {
|
||||
static readonly ID = 'workbench.debug.panel.action.clearReplAction';
|
||||
static readonly LABEL = nls.localize('clearRepl', "Clear Console");
|
||||
static readonly LABEL = localize('clearRepl', "Clear Console");
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IPanelService private readonly panelService: IPanelService
|
||||
@@ -1038,6 +702,6 @@ export class ClearReplAction extends Action {
|
||||
async run(): Promise<any> {
|
||||
const repl = <Repl>this.panelService.openPanel(REPL_ID);
|
||||
await repl.clearRepl();
|
||||
aria.status(nls.localize('debugConsoleCleared', "Debug console was cleared"));
|
||||
aria.status(localize('debugConsoleCleared', "Debug console was cleared"));
|
||||
}
|
||||
}
|
||||
|
||||
352
src/vs/workbench/contrib/debug/browser/replViewer.ts
Normal file
352
src/vs/workbench/contrib/debug/browser/replViewer.ts
Normal file
@@ -0,0 +1,352 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import severity from 'vs/base/common/severity';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { Variable } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
import { CachedListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { ITreeRenderer, ITreeNode, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { renderExpressionValue, AbstractExpressionsRenderer, IExpressionTemplateData, renderVariable, IInputBoxOptions } from 'vs/workbench/contrib/debug/browser/baseDebugView';
|
||||
import { handleANSIOutput } from 'vs/workbench/contrib/debug/browser/debugANSIHandling';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||
import { HighlightedLabel, IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { IReplElementSource, IDebugService, IExpression, IReplElement, IDebugConfiguration, IDebugSession, IExpressionContainer } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
interface IReplEvaluationInputTemplateData {
|
||||
label: HighlightedLabel;
|
||||
}
|
||||
|
||||
interface IReplEvaluationResultTemplateData {
|
||||
value: HTMLElement;
|
||||
annotation: HTMLElement;
|
||||
}
|
||||
|
||||
interface ISimpleReplElementTemplateData {
|
||||
container: HTMLElement;
|
||||
value: HTMLElement;
|
||||
source: HTMLElement;
|
||||
getReplElementSource(): IReplElementSource | undefined;
|
||||
toDispose: IDisposable[];
|
||||
}
|
||||
|
||||
interface IRawObjectReplTemplateData {
|
||||
container: HTMLElement;
|
||||
expression: HTMLElement;
|
||||
name: HTMLElement;
|
||||
value: HTMLElement;
|
||||
annotation: HTMLElement;
|
||||
label: HighlightedLabel;
|
||||
}
|
||||
|
||||
export class ReplEvaluationInputsRenderer implements ITreeRenderer<ReplEvaluationInput, FuzzyScore, IReplEvaluationInputTemplateData> {
|
||||
static readonly ID = 'replEvaluationInput';
|
||||
|
||||
get templateId(): string {
|
||||
return ReplEvaluationInputsRenderer.ID;
|
||||
}
|
||||
|
||||
renderTemplate(container: HTMLElement): IReplEvaluationInputTemplateData {
|
||||
dom.append(container, $('span.arrow.codicon.codicon-chevron-right'));
|
||||
const input = dom.append(container, $('.expression'));
|
||||
const label = new HighlightedLabel(input, false);
|
||||
return { label };
|
||||
}
|
||||
|
||||
renderElement(element: ITreeNode<ReplEvaluationInput, FuzzyScore>, index: number, templateData: IReplEvaluationInputTemplateData): void {
|
||||
const evaluation = element.element;
|
||||
templateData.label.set(evaluation.value, createMatches(element.filterData));
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IReplEvaluationInputTemplateData): void {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
export class ReplEvaluationResultsRenderer implements ITreeRenderer<ReplEvaluationResult, FuzzyScore, IReplEvaluationResultTemplateData> {
|
||||
static readonly ID = 'replEvaluationResult';
|
||||
|
||||
get templateId(): string {
|
||||
return ReplEvaluationResultsRenderer.ID;
|
||||
}
|
||||
|
||||
constructor(private readonly linkDetector: LinkDetector) { }
|
||||
|
||||
renderTemplate(container: HTMLElement): IReplEvaluationResultTemplateData {
|
||||
dom.append(container, $('span.arrow.codicon.codicon-chevron-left'));
|
||||
const output = dom.append(container, $('.evaluation-result.expression'));
|
||||
const value = dom.append(output, $('span.value'));
|
||||
const annotation = dom.append(output, $('span'));
|
||||
|
||||
return { value, annotation };
|
||||
}
|
||||
|
||||
renderElement(element: ITreeNode<ReplEvaluationResult, FuzzyScore>, index: number, templateData: IReplEvaluationResultTemplateData): void {
|
||||
const expression = element.element;
|
||||
renderExpressionValue(expression, templateData.value, {
|
||||
preserveWhitespace: !expression.hasChildren,
|
||||
showHover: false,
|
||||
colorize: true,
|
||||
linkDetector: this.linkDetector
|
||||
});
|
||||
if (expression.hasChildren) {
|
||||
templateData.annotation.className = 'annotation codicon codicon-info';
|
||||
templateData.annotation.title = localize('stateCapture', "Object state is captured from first evaluation");
|
||||
}
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IReplEvaluationResultTemplateData): void {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
export class ReplSimpleElementsRenderer implements ITreeRenderer<SimpleReplElement, FuzzyScore, ISimpleReplElementTemplateData> {
|
||||
static readonly ID = 'simpleReplElement';
|
||||
|
||||
constructor(
|
||||
private readonly linkDetector: LinkDetector,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IThemeService private readonly themeService: IThemeService
|
||||
) { }
|
||||
|
||||
get templateId(): string {
|
||||
return ReplSimpleElementsRenderer.ID;
|
||||
}
|
||||
|
||||
renderTemplate(container: HTMLElement): ISimpleReplElementTemplateData {
|
||||
const data: ISimpleReplElementTemplateData = Object.create(null);
|
||||
dom.addClass(container, 'output');
|
||||
const expression = dom.append(container, $('.output.expression.value-and-source'));
|
||||
|
||||
data.container = container;
|
||||
data.value = dom.append(expression, $('span.value'));
|
||||
data.source = dom.append(expression, $('.source'));
|
||||
data.toDispose = [];
|
||||
data.toDispose.push(dom.addDisposableListener(data.source, 'click', e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const source = data.getReplElementSource();
|
||||
if (source) {
|
||||
source.source.openInEditor(this.editorService, {
|
||||
startLineNumber: source.lineNumber,
|
||||
startColumn: source.column,
|
||||
endLineNumber: source.lineNumber,
|
||||
endColumn: source.column
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
renderElement({ element }: ITreeNode<SimpleReplElement, FuzzyScore>, index: number, templateData: ISimpleReplElementTemplateData): void {
|
||||
// value
|
||||
dom.clearNode(templateData.value);
|
||||
// Reset classes to clear ansi decorations since templates are reused
|
||||
templateData.value.className = 'value';
|
||||
const result = handleANSIOutput(element.value, this.linkDetector, this.themeService, element.session);
|
||||
templateData.value.appendChild(result);
|
||||
|
||||
dom.addClass(templateData.value, (element.severity === severity.Warning) ? 'warn' : (element.severity === severity.Error) ? 'error' : (element.severity === severity.Ignore) ? 'ignore' : 'info');
|
||||
templateData.source.textContent = element.sourceData ? `${element.sourceData.source.name}:${element.sourceData.lineNumber}` : '';
|
||||
templateData.source.title = element.sourceData ? this.labelService.getUriLabel(element.sourceData.source.uri) : '';
|
||||
templateData.getReplElementSource = () => element.sourceData;
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: ISimpleReplElementTemplateData): void {
|
||||
dispose(templateData.toDispose);
|
||||
}
|
||||
}
|
||||
|
||||
export class ReplVariablesRenderer extends AbstractExpressionsRenderer {
|
||||
|
||||
static readonly ID = 'replVariable';
|
||||
|
||||
get templateId(): string {
|
||||
return ReplVariablesRenderer.ID;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly linkDetector: LinkDetector,
|
||||
@IDebugService debugService: IDebugService,
|
||||
@IContextViewService contextViewService: IContextViewService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
) {
|
||||
super(debugService, contextViewService, themeService);
|
||||
}
|
||||
|
||||
protected renderExpression(expression: IExpression, data: IExpressionTemplateData, highlights: IHighlight[]): void {
|
||||
renderVariable(expression as Variable, data, true, highlights, this.linkDetector);
|
||||
}
|
||||
|
||||
protected getInputBoxOptions(expression: IExpression): IInputBoxOptions | undefined {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class ReplRawObjectsRenderer implements ITreeRenderer<RawObjectReplElement, FuzzyScore, IRawObjectReplTemplateData> {
|
||||
static readonly ID = 'rawObject';
|
||||
|
||||
constructor(private readonly linkDetector: LinkDetector) { }
|
||||
|
||||
get templateId(): string {
|
||||
return ReplRawObjectsRenderer.ID;
|
||||
}
|
||||
|
||||
renderTemplate(container: HTMLElement): IRawObjectReplTemplateData {
|
||||
dom.addClass(container, 'output');
|
||||
|
||||
const expression = dom.append(container, $('.output.expression'));
|
||||
const name = dom.append(expression, $('span.name'));
|
||||
const label = new HighlightedLabel(name, false);
|
||||
const value = dom.append(expression, $('span.value'));
|
||||
const annotation = dom.append(expression, $('span'));
|
||||
|
||||
return { container, expression, name, label, value, annotation };
|
||||
}
|
||||
|
||||
renderElement(node: ITreeNode<RawObjectReplElement, FuzzyScore>, index: number, templateData: IRawObjectReplTemplateData): void {
|
||||
// key
|
||||
const element = node.element;
|
||||
templateData.label.set(element.name ? `${element.name}:` : '', createMatches(node.filterData));
|
||||
if (element.name) {
|
||||
templateData.name.textContent = `${element.name}:`;
|
||||
} else {
|
||||
templateData.name.textContent = '';
|
||||
}
|
||||
|
||||
// value
|
||||
renderExpressionValue(element.value, templateData.value, {
|
||||
preserveWhitespace: true,
|
||||
showHover: false,
|
||||
linkDetector: this.linkDetector
|
||||
});
|
||||
|
||||
// annotation if any
|
||||
if (element.annotation) {
|
||||
templateData.annotation.className = 'annotation codicon codicon-info';
|
||||
templateData.annotation.title = element.annotation;
|
||||
} else {
|
||||
templateData.annotation.className = '';
|
||||
templateData.annotation.title = '';
|
||||
}
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IRawObjectReplTemplateData): void {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
export class ReplDelegate extends CachedListVirtualDelegate<IReplElement> {
|
||||
|
||||
constructor(private configurationService: IConfigurationService) {
|
||||
super();
|
||||
}
|
||||
|
||||
getHeight(element: IReplElement): number {
|
||||
const config = this.configurationService.getValue<IDebugConfiguration>('debug');
|
||||
|
||||
if (!config.console.wordWrap) {
|
||||
return this.estimateHeight(element, true);
|
||||
}
|
||||
|
||||
return super.getHeight(element);
|
||||
}
|
||||
|
||||
protected estimateHeight(element: IReplElement, ignoreValueLength = false): number {
|
||||
const config = this.configurationService.getValue<IDebugConfiguration>('debug');
|
||||
const rowHeight = Math.ceil(1.4 * config.console.fontSize);
|
||||
const countNumberOfLines = (str: string) => Math.max(1, (str && str.match(/\r\n|\n/g) || []).length);
|
||||
const hasValue = (e: any): e is { value: string } => typeof e.value === 'string';
|
||||
|
||||
// Calculate a rough overestimation for the height
|
||||
// For every 30 characters increase the number of lines needed
|
||||
if (hasValue(element)) {
|
||||
let value = element.value;
|
||||
let valueRows = countNumberOfLines(value) + (ignoreValueLength ? 0 : Math.floor(value.length / 30));
|
||||
|
||||
return valueRows * rowHeight;
|
||||
}
|
||||
|
||||
return rowHeight;
|
||||
}
|
||||
|
||||
getTemplateId(element: IReplElement): string {
|
||||
if (element instanceof Variable && element.name) {
|
||||
return ReplVariablesRenderer.ID;
|
||||
}
|
||||
if (element instanceof ReplEvaluationResult) {
|
||||
return ReplEvaluationResultsRenderer.ID;
|
||||
}
|
||||
if (element instanceof ReplEvaluationInput) {
|
||||
return ReplEvaluationInputsRenderer.ID;
|
||||
}
|
||||
if (element instanceof SimpleReplElement || (element instanceof Variable && !element.name)) {
|
||||
// Variable with no name is a top level variable which should be rendered like a repl element #17404
|
||||
return ReplSimpleElementsRenderer.ID;
|
||||
}
|
||||
|
||||
return ReplRawObjectsRenderer.ID;
|
||||
}
|
||||
|
||||
hasDynamicHeight(element: IReplElement): boolean {
|
||||
// Empty elements should not have dynamic height since they will be invisible
|
||||
return element.toString().length > 0;
|
||||
}
|
||||
}
|
||||
|
||||
function isDebugSession(obj: any): obj is IDebugSession {
|
||||
return typeof obj.getReplElements === 'function';
|
||||
}
|
||||
|
||||
export class ReplDataSource implements IAsyncDataSource<IDebugSession, IReplElement> {
|
||||
|
||||
hasChildren(element: IReplElement | IDebugSession): boolean {
|
||||
if (isDebugSession(element)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !!(<IExpressionContainer>element).hasChildren;
|
||||
}
|
||||
|
||||
getChildren(element: IReplElement | IDebugSession): Promise<IReplElement[]> {
|
||||
if (isDebugSession(element)) {
|
||||
return Promise.resolve(element.getReplElements());
|
||||
}
|
||||
if (element instanceof RawObjectReplElement) {
|
||||
return element.getChildren();
|
||||
}
|
||||
|
||||
return (<IExpression>element).getChildren();
|
||||
}
|
||||
}
|
||||
|
||||
export class ReplAccessibilityProvider implements IAccessibilityProvider<IReplElement> {
|
||||
getAriaLabel(element: IReplElement): string {
|
||||
if (element instanceof Variable) {
|
||||
return localize('replVariableAriaLabel', "Variable {0} has value {1}, read eval print loop, debug", element.name, element.value);
|
||||
}
|
||||
if (element instanceof SimpleReplElement || element instanceof ReplEvaluationInput || element instanceof ReplEvaluationResult) {
|
||||
return localize('replValueOutputAriaLabel', "{0}, read eval print loop, debug", element.value);
|
||||
}
|
||||
if (element instanceof RawObjectReplElement) {
|
||||
return localize('replRawObjectAriaLabel', "Repl variable {0} has value {1}, read eval print loop, debug", element.name, element.value);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -726,13 +726,11 @@ export class ManageExtensionAction extends ExtensionDropDownAction {
|
||||
groups.push([this.instantiationService.createInstance(UninstallAction)]);
|
||||
groups.push([this.instantiationService.createInstance(InstallAnotherVersionAction)]);
|
||||
|
||||
if (this.extension) {
|
||||
const extensionActions: ExtensionAction[] = [this.instantiationService.createInstance(ExtensionInfoAction), this.instantiationService.createInstance(CopyExtensionIdAction)];
|
||||
if (this.extension.local && this.extension.local.manifest.contributes && this.extension.local.manifest.contributes.configuration) {
|
||||
extensionActions.push(this.instantiationService.createInstance(ExtensionSettingsAction));
|
||||
}
|
||||
groups.push(extensionActions);
|
||||
const extensionActions: ExtensionAction[] = [this.instantiationService.createInstance(CopyExtensionInfoAction), this.instantiationService.createInstance(CopyExtensionIdAction)];
|
||||
if (this.extension && this.extension.local && this.extension.local.manifest.contributes && this.extension.local.manifest.contributes.configuration) {
|
||||
extensionActions.push(this.instantiationService.createInstance(ExtensionSettingsAction));
|
||||
}
|
||||
groups.push(extensionActions);
|
||||
|
||||
groups.forEach(group => group.forEach(extensionAction => extensionAction.extension = this.extension));
|
||||
|
||||
@@ -810,7 +808,7 @@ export class InstallAnotherVersionAction extends ExtensionAction {
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtensionInfoAction extends ExtensionAction {
|
||||
export class CopyExtensionInfoAction extends ExtensionAction {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.copyExtension';
|
||||
static readonly LABEL = localize('workbench.extensions.action.copyExtension', "Copy");
|
||||
@@ -818,7 +816,7 @@ export class ExtensionInfoAction extends ExtensionAction {
|
||||
constructor(
|
||||
@IClipboardService private readonly clipboardService: IClipboardService
|
||||
) {
|
||||
super(ExtensionInfoAction.ID, ExtensionInfoAction.LABEL);
|
||||
super(CopyExtensionInfoAction.ID, CopyExtensionInfoAction.LABEL);
|
||||
this.update();
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ import { ViewPane, ViewPaneContainer } from 'vs/workbench/browser/parts/views/vi
|
||||
import { KeyChord, KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||
import { Viewlet } from 'vs/workbench/browser/viewlet';
|
||||
|
||||
export class ExplorerViewletViewsContribution extends Disposable implements IWorkbenchContribution {
|
||||
@@ -202,8 +201,7 @@ export class ExplorerViewPaneContainer extends ViewPaneContainer {
|
||||
// without causing the animation in the opened editors view to kick in and change scroll position.
|
||||
// We try to be smart and only use the delay if we recognize that the user action is likely to cause
|
||||
// a new entry in the opened editors view.
|
||||
const delegatingEditorService = this.instantiationService.createInstance(DelegatingEditorService);
|
||||
delegatingEditorService.setEditorOpenHandler(async (delegate, group, editor, options): Promise<IEditor | null> => {
|
||||
const delegatingEditorService = this.instantiationService.createInstance(DelegatingEditorService, async (delegate, group, editor, options): Promise<IEditor | null> => {
|
||||
let openEditorsView = this.getOpenEditorsView();
|
||||
if (openEditorsView) {
|
||||
let delay = 0;
|
||||
@@ -219,19 +217,16 @@ export class ExplorerViewPaneContainer extends ViewPaneContainer {
|
||||
openEditorsView.setStructuralRefreshDelay(delay);
|
||||
}
|
||||
|
||||
let openedEditor: IEditor | undefined;
|
||||
try {
|
||||
openedEditor = await delegate(group, editor, options);
|
||||
return await delegate(group, editor, options);
|
||||
} catch (error) {
|
||||
// ignore
|
||||
return null; // ignore
|
||||
} finally {
|
||||
const openEditorsView = this.getOpenEditorsView();
|
||||
if (openEditorsView) {
|
||||
openEditorsView.setStructuralRefreshDelay(0);
|
||||
}
|
||||
}
|
||||
|
||||
return withUndefinedAsNull(openedEditor);
|
||||
});
|
||||
|
||||
const explorerInstantiator = this.instantiationService.createChild(new ServiceCollection([IEditorService, delegatingEditorService]));
|
||||
|
||||
@@ -171,7 +171,7 @@ export class MarkersView extends ViewPane implements IMarkerFilterController {
|
||||
|
||||
public layoutBody(height: number, width: number): void {
|
||||
const wasSmallLayout = this.isSmallLayout;
|
||||
this.isSmallLayout = width < 600;
|
||||
this.isSmallLayout = width < 600 && height > 100;
|
||||
if (this.isSmallLayout !== wasSmallLayout) {
|
||||
this.updateActions();
|
||||
if (this.filterActionBar) {
|
||||
|
||||
@@ -20,13 +20,13 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { ITreeRenderer, ITreeNode, IAsyncDataSource, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { Disposable, IDisposable, toDisposable, MutableDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, IDisposable, toDisposable, MutableDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ActionBar, ActionViewItem, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { ActionRunner, IAction } from 'vs/base/common/actions';
|
||||
import { IMenuService, MenuId, IMenu, MenuRegistry, MenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { createAndFillInContextMenuActions, createAndFillInActionBarActions, ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IRemoteExplorerService, TunnelModel, MakeAddress } from 'vs/workbench/services/remote/common/remoteExplorerService';
|
||||
import { IRemoteExplorerService, TunnelModel, MakeAddress, TunnelType, ITunnelItem } from 'vs/workbench/services/remote/common/remoteExplorerService';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
@@ -55,6 +55,7 @@ export interface ITunnelViewModel {
|
||||
readonly forwarded: TunnelItem[];
|
||||
readonly detected: TunnelItem[];
|
||||
readonly candidates: Promise<TunnelItem[]>;
|
||||
readonly input: ITunnelItem | ITunnelGroup | undefined;
|
||||
groups(): Promise<ITunnelGroup[]>;
|
||||
}
|
||||
|
||||
@@ -62,6 +63,7 @@ export class TunnelViewModel extends Disposable implements ITunnelViewModel {
|
||||
private _onForwardedPortsChanged: Emitter<void> = new Emitter();
|
||||
public onForwardedPortsChanged: Event<void> = this._onForwardedPortsChanged.event;
|
||||
private model: TunnelModel;
|
||||
private _input: ITunnelItem | ITunnelGroup | undefined;
|
||||
|
||||
constructor(
|
||||
@IRemoteExplorerService remoteExplorerService: IRemoteExplorerService) {
|
||||
@@ -70,6 +72,7 @@ export class TunnelViewModel extends Disposable implements ITunnelViewModel {
|
||||
this._register(this.model.onForwardPort(() => this._onForwardedPortsChanged.fire()));
|
||||
this._register(this.model.onClosePort(() => this._onForwardedPortsChanged.fire()));
|
||||
this._register(this.model.onPortName(() => this._onForwardedPortsChanged.fire()));
|
||||
this._register(this.model.onCandidatesChanged(() => this._onForwardedPortsChanged.fire()));
|
||||
}
|
||||
|
||||
async groups(): Promise<ITunnelGroup[]> {
|
||||
@@ -96,10 +99,13 @@ export class TunnelViewModel extends Disposable implements ITunnelViewModel {
|
||||
items: candidates
|
||||
});
|
||||
}
|
||||
groups.push({
|
||||
label: nls.localize('remote.tunnelsView.add', "Forward a Port..."),
|
||||
tunnelType: TunnelType.Add,
|
||||
});
|
||||
if (!this._input) {
|
||||
this._input = {
|
||||
label: nls.localize('remote.tunnelsView.add', "Forward a Port..."),
|
||||
tunnelType: TunnelType.Add,
|
||||
};
|
||||
}
|
||||
groups.push(this._input);
|
||||
return groups;
|
||||
}
|
||||
|
||||
@@ -128,6 +134,10 @@ export class TunnelViewModel extends Disposable implements ITunnelViewModel {
|
||||
});
|
||||
}
|
||||
|
||||
get input(): ITunnelItem | ITunnelGroup | undefined {
|
||||
return this._input;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
@@ -197,7 +207,7 @@ class TunnelTreeRenderer extends Disposable implements ITreeRenderer<ITunnelGrou
|
||||
templateData.actionBar.clear();
|
||||
let editableData: IEditableData | undefined;
|
||||
if (this.isTunnelItem(node)) {
|
||||
editableData = this.remoteExplorerService.getEditableData(node.remoteHost, node.remotePort);
|
||||
editableData = this.remoteExplorerService.getEditableData(node);
|
||||
if (editableData) {
|
||||
templateData.iconLabel.element.style.display = 'none';
|
||||
this.renderInputBox(templateData.container, editableData);
|
||||
@@ -205,7 +215,7 @@ class TunnelTreeRenderer extends Disposable implements ITreeRenderer<ITunnelGrou
|
||||
templateData.iconLabel.element.style.display = 'flex';
|
||||
this.renderTunnel(node, templateData);
|
||||
}
|
||||
} else if ((node.tunnelType === TunnelType.Add) && (editableData = this.remoteExplorerService.getEditableData(undefined, undefined))) {
|
||||
} else if ((node.tunnelType === TunnelType.Add) && (editableData = this.remoteExplorerService.getEditableData(undefined))) {
|
||||
templateData.iconLabel.element.style.display = 'none';
|
||||
this.renderInputBox(templateData.container, editableData);
|
||||
} else {
|
||||
@@ -217,14 +227,15 @@ class TunnelTreeRenderer extends Disposable implements ITreeRenderer<ITunnelGrou
|
||||
private renderTunnel(node: ITunnelItem, templateData: ITunnelTemplateData) {
|
||||
templateData.iconLabel.setLabel(node.label, node.description, { title: node.label + ' - ' + node.description, extraClasses: ['tunnel-view-label'] });
|
||||
templateData.actionBar.context = node;
|
||||
const contextKeyService = this.contextKeyService.createScoped();
|
||||
const contextKeyService = this._register(this.contextKeyService.createScoped());
|
||||
contextKeyService.createKey('view', this.viewId);
|
||||
contextKeyService.createKey('tunnelType', node.tunnelType);
|
||||
contextKeyService.createKey('tunnelCloseable', node.closeable);
|
||||
const menu = this.menuService.createMenu(MenuId.TunnelInline, contextKeyService);
|
||||
this._register(menu);
|
||||
const disposableStore = new DisposableStore();
|
||||
templateData.elementDisposable = disposableStore;
|
||||
const menu = disposableStore.add(this.menuService.createMenu(MenuId.TunnelInline, contextKeyService));
|
||||
const actions: IAction[] = [];
|
||||
this._register(createAndFillInActionBarActions(menu, { shouldForwardArgs: true }, actions));
|
||||
disposableStore.add(createAndFillInActionBarActions(menu, { shouldForwardArgs: true }, actions));
|
||||
if (actions) {
|
||||
templateData.actionBar.push(actions, { icon: true, label: false });
|
||||
if (this._actionRunner) {
|
||||
@@ -324,30 +335,12 @@ class TunnelDataSource implements IAsyncDataSource<ITunnelViewModel, ITunnelItem
|
||||
}
|
||||
}
|
||||
|
||||
enum TunnelType {
|
||||
Candidate = 'Candidate',
|
||||
Detected = 'Detected',
|
||||
Forwarded = 'Forwarded',
|
||||
Add = 'Add'
|
||||
}
|
||||
|
||||
interface ITunnelGroup {
|
||||
tunnelType: TunnelType;
|
||||
label: string;
|
||||
items?: ITunnelItem[] | Promise<ITunnelItem[]>;
|
||||
}
|
||||
|
||||
interface ITunnelItem {
|
||||
tunnelType: TunnelType;
|
||||
remoteHost: string;
|
||||
remotePort: number;
|
||||
localAddress?: string;
|
||||
name?: string;
|
||||
closeable?: boolean;
|
||||
readonly description?: string;
|
||||
readonly label: string;
|
||||
}
|
||||
|
||||
class TunnelItem implements ITunnelItem {
|
||||
constructor(
|
||||
public tunnelType: TunnelType,
|
||||
@@ -432,12 +425,11 @@ export class TunnelPanel extends ViewPane {
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement): void {
|
||||
dom.addClass(container, '.tree-explorer-viewlet-tree-view');
|
||||
const treeContainer = document.createElement('div');
|
||||
dom.addClass(treeContainer, 'customview-tree');
|
||||
const panelContainer = dom.append(container, dom.$('.tree-explorer-viewlet-tree-view'));
|
||||
const treeContainer = dom.append(panelContainer, dom.$('.customview-tree'));
|
||||
dom.addClass(treeContainer, 'file-icon-themable-tree');
|
||||
dom.addClass(treeContainer, 'show-file-icons');
|
||||
container.appendChild(treeContainer);
|
||||
|
||||
const renderer = new TunnelTreeRenderer(TunnelPanel.ID, this.menuService, this.contextKeyService, this.instantiationService, this.contextViewService, this.themeService, this.remoteExplorerService);
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree,
|
||||
'RemoteTunnels',
|
||||
@@ -472,12 +464,12 @@ export class TunnelPanel extends ViewPane {
|
||||
|
||||
this._register(Event.debounce(navigator.onDidOpenResource, (last, event) => event, 75, true)(e => {
|
||||
if (e.element && (e.element.tunnelType === TunnelType.Add)) {
|
||||
this.commandService.executeCommand(ForwardPortAction.ID, 'inline add');
|
||||
this.commandService.executeCommand(ForwardPortAction.INLINE_ID);
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.remoteExplorerService.onDidChangeEditable(async e => {
|
||||
const isEditing = !!this.remoteExplorerService.getEditableData(e.host, e.port);
|
||||
const isEditing = !!this.remoteExplorerService.getEditableData(e);
|
||||
|
||||
if (!isEditing) {
|
||||
dom.removeClass(treeContainer, 'highlight');
|
||||
@@ -487,6 +479,7 @@ export class TunnelPanel extends ViewPane {
|
||||
|
||||
if (isEditing) {
|
||||
dom.addClass(treeContainer, 'highlight');
|
||||
this.tree.reveal(e ? e : this.viewModel.input);
|
||||
} else {
|
||||
this.tree.domFocus();
|
||||
}
|
||||
@@ -494,8 +487,7 @@ export class TunnelPanel extends ViewPane {
|
||||
}
|
||||
|
||||
private get contributedContextMenu(): IMenu {
|
||||
const contributedContextMenu = this.menuService.createMenu(MenuId.TunnelContext, this.tree.contextKeyService);
|
||||
this._register(contributedContextMenu);
|
||||
const contributedContextMenu = this._register(this.menuService.createMenu(MenuId.TunnelContext, this.tree.contextKeyService));
|
||||
return contributedContextMenu;
|
||||
}
|
||||
|
||||
@@ -578,12 +570,12 @@ namespace LabelTunnelAction {
|
||||
return async (accessor, arg) => {
|
||||
if (arg instanceof TunnelItem) {
|
||||
const remoteExplorerService = accessor.get(IRemoteExplorerService);
|
||||
remoteExplorerService.setEditable(arg.remoteHost, arg.remotePort, {
|
||||
remoteExplorerService.setEditable(arg, {
|
||||
onFinish: (value, success) => {
|
||||
if (success) {
|
||||
remoteExplorerService.tunnelModel.name(arg.remoteHost, arg.remotePort, value);
|
||||
}
|
||||
remoteExplorerService.setEditable(arg.remoteHost, arg.remotePort, null);
|
||||
remoteExplorerService.setEditable(arg, null);
|
||||
},
|
||||
validationMessage: () => null,
|
||||
placeholder: nls.localize('remote.tunnelsView.labelPlaceholder', "Port label"),
|
||||
@@ -596,7 +588,8 @@ namespace LabelTunnelAction {
|
||||
}
|
||||
|
||||
namespace ForwardPortAction {
|
||||
export const ID = 'remote.tunnel.forward';
|
||||
export const INLINE_ID = 'remote.tunnel.forwardInline';
|
||||
export const COMMANDPALETTE_ID = 'remote.tunnel.forwardCommandPalette';
|
||||
export const LABEL = nls.localize('remote.tunnel.forward', "Forward a Port");
|
||||
const forwardPrompt = nls.localize('remote.tunnel.forwardPrompt', "Port number or address (eg. 3000 or 10.10.10.10:2000).");
|
||||
|
||||
@@ -615,35 +608,40 @@ namespace ForwardPortAction {
|
||||
return null;
|
||||
}
|
||||
|
||||
export function handler(): ICommandHandler {
|
||||
export function inlineHandler(): ICommandHandler {
|
||||
return async (accessor, arg) => {
|
||||
const remoteExplorerService = accessor.get(IRemoteExplorerService);
|
||||
if (arg instanceof TunnelItem) {
|
||||
remoteExplorerService.forward({ host: arg.remoteHost, port: arg.remotePort });
|
||||
} else if (arg) {
|
||||
remoteExplorerService.setEditable(undefined, undefined, {
|
||||
} else {
|
||||
remoteExplorerService.setEditable(undefined, {
|
||||
onFinish: (value, success) => {
|
||||
let parsed: { host: string, port: number } | undefined;
|
||||
if (success && (parsed = parseInput(value))) {
|
||||
remoteExplorerService.forward({ host: parsed.host, port: parsed.port });
|
||||
}
|
||||
remoteExplorerService.setEditable(undefined, undefined, null);
|
||||
remoteExplorerService.setEditable(undefined, null);
|
||||
},
|
||||
validationMessage: validateInput,
|
||||
placeholder: forwardPrompt
|
||||
});
|
||||
} else {
|
||||
const viewsService = accessor.get(IViewsService);
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
await viewsService.openView(TunnelPanel.ID, true);
|
||||
const value = await quickInputService.input({
|
||||
prompt: forwardPrompt,
|
||||
validateInput: (value) => Promise.resolve(validateInput(value))
|
||||
});
|
||||
let parsed: { host: string, port: number } | undefined;
|
||||
if (value && (parsed = parseInput(value))) {
|
||||
remoteExplorerService.forward({ host: parsed.host, port: parsed.port });
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function commandPaletteHandler(): ICommandHandler {
|
||||
return async (accessor, arg) => {
|
||||
const remoteExplorerService = accessor.get(IRemoteExplorerService);
|
||||
const viewsService = accessor.get(IViewsService);
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
await viewsService.openView(TunnelPanel.ID, true);
|
||||
const value = await quickInputService.input({
|
||||
prompt: forwardPrompt,
|
||||
validateInput: (value) => Promise.resolve(validateInput(value))
|
||||
});
|
||||
let parsed: { host: string, port: number } | undefined;
|
||||
if (value && (parsed = parseInput(value))) {
|
||||
remoteExplorerService.forward({ host: parsed.host, port: parsed.port });
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -702,30 +700,51 @@ namespace CopyAddressAction {
|
||||
}
|
||||
}
|
||||
|
||||
namespace RefreshTunnelViewAction {
|
||||
export const ID = 'remote.tunnel.refresh';
|
||||
export const LABEL = nls.localize('remote.tunnel.refreshView', "Refresh");
|
||||
|
||||
export function handler(): ICommandHandler {
|
||||
return (accessor, arg) => {
|
||||
const remoteExplorerService = accessor.get(IRemoteExplorerService);
|
||||
return remoteExplorerService.refresh();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
CommandsRegistry.registerCommand(LabelTunnelAction.ID, LabelTunnelAction.handler());
|
||||
CommandsRegistry.registerCommand(ForwardPortAction.ID, ForwardPortAction.handler());
|
||||
CommandsRegistry.registerCommand(ForwardPortAction.INLINE_ID, ForwardPortAction.inlineHandler());
|
||||
CommandsRegistry.registerCommand(ForwardPortAction.COMMANDPALETTE_ID, ForwardPortAction.commandPaletteHandler());
|
||||
CommandsRegistry.registerCommand(ClosePortAction.ID, ClosePortAction.handler());
|
||||
CommandsRegistry.registerCommand(OpenPortInBrowserAction.ID, OpenPortInBrowserAction.handler());
|
||||
CommandsRegistry.registerCommand(CopyAddressAction.ID, CopyAddressAction.handler());
|
||||
CommandsRegistry.registerCommand(RefreshTunnelViewAction.ID, RefreshTunnelViewAction.handler());
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.CommandPalette, ({
|
||||
command: {
|
||||
id: ForwardPortAction.ID,
|
||||
id: ForwardPortAction.COMMANDPALETTE_ID,
|
||||
title: ForwardPortAction.LABEL
|
||||
},
|
||||
when: forwardedPortsViewEnabled
|
||||
}));
|
||||
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.TunnelTitle, ({
|
||||
group: 'navigation',
|
||||
order: 0,
|
||||
command: {
|
||||
id: ForwardPortAction.ID,
|
||||
id: ForwardPortAction.INLINE_ID,
|
||||
title: ForwardPortAction.LABEL,
|
||||
icon: { id: 'codicon/plus' }
|
||||
}
|
||||
}));
|
||||
MenuRegistry.appendMenuItem(MenuId.TunnelTitle, ({
|
||||
group: 'navigation',
|
||||
order: 1,
|
||||
command: {
|
||||
id: RefreshTunnelViewAction.ID,
|
||||
title: RefreshTunnelViewAction.LABEL,
|
||||
icon: { id: 'codicon/refresh' }
|
||||
}
|
||||
}));
|
||||
MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
|
||||
group: '0_manage',
|
||||
order: 0,
|
||||
@@ -757,7 +776,7 @@ MenuRegistry.appendMenuItem(MenuId.TunnelContext, ({
|
||||
group: '0_manage',
|
||||
order: 1,
|
||||
command: {
|
||||
id: ForwardPortAction.ID,
|
||||
id: ForwardPortAction.INLINE_ID,
|
||||
title: ForwardPortAction.LABEL,
|
||||
},
|
||||
when: TunnelTypeContextKey.isEqualTo(TunnelType.Candidate)
|
||||
@@ -784,7 +803,7 @@ MenuRegistry.appendMenuItem(MenuId.TunnelInline, ({
|
||||
MenuRegistry.appendMenuItem(MenuId.TunnelInline, ({
|
||||
order: 0,
|
||||
command: {
|
||||
id: ForwardPortAction.ID,
|
||||
id: ForwardPortAction.INLINE_ID,
|
||||
title: ForwardPortAction.LABEL,
|
||||
icon: { id: 'codicon/plus' }
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user