Merge from vscode 718331d6f3ebd1b571530ab499edb266ddd493d5

This commit is contained in:
ADS Merger
2020-02-08 04:50:58 +00:00
parent 8c61538a27
commit 2af13c18d2
752 changed files with 16458 additions and 10063 deletions

View File

@@ -27,7 +27,6 @@ const stringRegex = /^(['"]).*\1$/;
const $ = dom.$;
export interface IRenderValueOptions {
preserveWhitespace?: boolean;
showChanged?: boolean;
maxValueLength?: number;
showHover?: boolean;
@@ -49,11 +48,6 @@ export function renderViewTree(container: HTMLElement): HTMLElement {
return treeContainer;
}
export function replaceWhitespace(value: string): string {
const map: { [x: string]: string } = { '\n': '\\n', '\r': '\\r', '\t': '\\t' };
return value.replace(/[\n\r\t]/g, char => map[char]);
}
export function renderExpressionValue(expressionOrValue: IExpressionContainer | string, container: HTMLElement, options: IRenderValueOptions): void {
let value = typeof expressionOrValue === 'string' ? expressionOrValue : expressionOrValue.value;
@@ -86,11 +80,10 @@ export function renderExpressionValue(expressionOrValue: IExpressionContainer |
if (options.maxValueLength && value && value.length > options.maxValueLength) {
value = value.substr(0, options.maxValueLength) + '...';
}
if (value && !options.preserveWhitespace) {
value = replaceWhitespace(value);
} else {
value = value || '';
if (!value) {
value = '';
}
if (options.linkDetector) {
container.textContent = '';
const session = (expressionOrValue instanceof ExpressionContainer) ? expressionOrValue.getSession() : undefined;
@@ -105,20 +98,19 @@ export function renderExpressionValue(expressionOrValue: IExpressionContainer |
export function renderVariable(variable: Variable, data: IVariableTemplateData, showChanged: boolean, highlights: IHighlight[], linkDetector?: LinkDetector): void {
if (variable.available) {
let text = replaceWhitespace(variable.name);
let text = variable.name;
if (variable.value && typeof variable.name === 'string') {
text += ':';
}
data.label.set(text, highlights, variable.type ? variable.type : variable.name);
dom.toggleClass(data.name, 'virtual', !!variable.presentationHint && variable.presentationHint.kind === 'virtual');
} else if (variable.value && typeof variable.name === 'string') {
} else if (variable.value && typeof variable.name === 'string' && variable.name) {
data.label.set(':');
}
renderExpressionValue(variable, data.value, {
showChanged,
maxValueLength: MAX_VALUE_RENDER_LENGTH_IN_VIEWLET,
preserveWhitespace: false,
showHover: true,
colorize: true,
linkDetector
@@ -185,7 +177,7 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
const inputBox = new InputBox(inputBoxContainer, this.contextViewService, options);
const styler = attachInputBoxStyler(inputBox, this.themeService);
inputBox.value = replaceWhitespace(options.initialValue);
inputBox.value = options.initialValue;
inputBox.focus();
inputBox.select();

View File

@@ -34,6 +34,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import { Gesture } from 'vs/base/browser/touch';
import { IViewDescriptorService } from 'vs/workbench/common/views';
import { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor';
const $ = dom.$;
@@ -633,7 +634,7 @@ export function openBreakpointSource(breakpoint: IBreakpoint, sideBySide: boolea
preserveFocus,
selection,
revealIfOpened: true,
revealInCenterIfOutsideViewport: true,
selectionRevealType: TextEditorSelectionRevealType.CenterIfOutsideViewport,
pinned: !preserveFocus
}
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);

View File

@@ -19,7 +19,7 @@ import { CallStackView } from 'vs/workbench/contrib/debug/browser/callStackView'
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
import {
IDebugService, VIEWLET_ID, DEBUG_PANEL_ID, CONTEXT_IN_DEBUG_MODE, INTERNAL_CONSOLE_OPTIONS_SCHEMA,
CONTEXT_DEBUG_STATE, VARIABLES_VIEW_ID, CALLSTACK_VIEW_ID, WATCH_VIEW_ID, BREAKPOINTS_VIEW_ID, LOADED_SCRIPTS_VIEW_ID, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_CALLSTACK_ITEM_TYPE, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_DEBUG_UX, BREAKPOINT_EDITOR_CONTRIBUTION_ID, REPL_VIEW_ID,
CONTEXT_DEBUG_STATE, VARIABLES_VIEW_ID, CALLSTACK_VIEW_ID, WATCH_VIEW_ID, BREAKPOINTS_VIEW_ID, LOADED_SCRIPTS_VIEW_ID, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_CALLSTACK_ITEM_TYPE, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_DEBUG_UX, BREAKPOINT_EDITOR_CONTRIBUTION_ID, REPL_VIEW_ID, CONTEXT_BREAKPOINTS_EXIST,
} from 'vs/workbench/contrib/debug/common/debug';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { StartAction, AddFunctionBreakpointAction, ConfigureAction, DisableAllBreakpointsAction, EnableAllBreakpointsAction, RemoveAllBreakpointsAction, RunAction, ReapplyBreakpointsAction, SelectAndStartAction } from 'vs/workbench/contrib/debug/browser/debugActions';
@@ -107,7 +107,7 @@ const viewsRegistry = Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry);
viewsRegistry.registerViews([{ id: VARIABLES_VIEW_ID, name: nls.localize('variables', "Variables"), ctorDescriptor: new SyncDescriptor(VariablesView), order: 10, weight: 40, canToggleVisibility: true, focusCommand: { id: 'workbench.debug.action.focusVariablesView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], viewContainer);
viewsRegistry.registerViews([{ id: WATCH_VIEW_ID, name: nls.localize('watch', "Watch"), ctorDescriptor: new SyncDescriptor(WatchExpressionsView), order: 20, weight: 10, canToggleVisibility: true, focusCommand: { id: 'workbench.debug.action.focusWatchView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], viewContainer);
viewsRegistry.registerViews([{ id: CALLSTACK_VIEW_ID, name: nls.localize('callStack', "Call Stack"), ctorDescriptor: new SyncDescriptor(CallStackView), order: 30, weight: 30, canToggleVisibility: true, focusCommand: { id: 'workbench.debug.action.focusCallStackView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], viewContainer);
viewsRegistry.registerViews([{ id: BREAKPOINTS_VIEW_ID, name: nls.localize('breakpoints', "Breakpoints"), ctorDescriptor: new SyncDescriptor(BreakpointsView), order: 40, weight: 20, canToggleVisibility: true, focusCommand: { id: 'workbench.debug.action.focusBreakpointsView' }, when: CONTEXT_DEBUG_UX.isEqualTo('default') }], viewContainer);
viewsRegistry.registerViews([{ id: BREAKPOINTS_VIEW_ID, name: nls.localize('breakpoints', "Breakpoints"), ctorDescriptor: new SyncDescriptor(BreakpointsView), order: 40, weight: 20, canToggleVisibility: true, focusCommand: { id: 'workbench.debug.action.focusBreakpointsView' }, when: ContextKeyExpr.or(CONTEXT_BREAKPOINTS_EXIST, CONTEXT_DEBUG_UX.isEqualTo('default')) }], viewContainer);
viewsRegistry.registerViews([{ id: StartView.ID, name: StartView.LABEL, ctorDescriptor: new SyncDescriptor(StartView), order: 10, weight: 40, canToggleVisibility: true, when: CONTEXT_DEBUG_UX.isEqualTo('simple') }], viewContainer);
viewsRegistry.registerViews([{ id: LOADED_SCRIPTS_VIEW_ID, name: nls.localize('loadedScripts', "Loaded Scripts"), ctorDescriptor: new SyncDescriptor(LoadedScriptsView), order: 35, weight: 5, canToggleVisibility: true, collapsed: true, when: ContextKeyExpr.and(CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_DEBUG_UX.isEqualTo('default')) }], viewContainer);

View File

@@ -16,7 +16,7 @@ import { IContentWidget, ICodeEditor, IContentWidgetPosition, ContentWidgetPosit
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IDebugService, IExpression, IExpressionContainer, IStackFrame } from 'vs/workbench/contrib/debug/common/debug';
import { Expression } from 'vs/workbench/contrib/debug/common/debugModel';
import { renderExpressionValue, replaceWhitespace } from 'vs/workbench/contrib/debug/browser/baseDebugView';
import { renderExpressionValue } 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';
@@ -230,7 +230,6 @@ export class DebugHoverWidget implements IContentWidget {
this.valueContainer.hidden = false;
renderExpressionValue(expression, this.valueContainer, {
showChanged: false,
preserveWhitespace: true,
colorize: true
});
this.valueContainer.title = '';
@@ -248,7 +247,7 @@ export class DebugHoverWidget implements IContentWidget {
this.complexValueContainer.hidden = false;
await this.tree.setInput(expression);
this.complexValueTitle.textContent = replaceWhitespace(expression.value);
this.complexValueTitle.textContent = expression.value;
this.complexValueTitle.title = expression.value;
this.layoutTreeAndContainer();
this.editor.layoutContentWidget(this);
@@ -274,11 +273,13 @@ export class DebugHoverWidget implements IContentWidget {
return;
}
if (dom.isAncestor(document.activeElement, this.domNode)) {
this.editor.focus();
}
this._isVisible = false;
this.editor.deltaDecorations(this.highlightDecorations, []);
this.highlightDecorations = [];
this.editor.layoutContentWidget(this);
this.editor.focus();
}
getPosition(): IContentWidgetPosition | null {

View File

@@ -36,7 +36,7 @@ import { IAction } from 'vs/base/common/actions';
import { deepClone, equals } from 'vs/base/common/objects';
import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { IDebugService, State, IDebugSession, CONTEXT_DEBUG_TYPE, CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_MODE, IThread, IDebugConfiguration, VIEWLET_ID, DEBUG_PANEL_ID, IConfig, ILaunch, IViewModel, IConfigurationManager, IDebugModel, IEnablement, IBreakpoint, IBreakpointData, ICompound, IGlobalConfig, IStackFrame, AdapterEndEvent, getStateLabel, IDebugSessionOptions, CONTEXT_DEBUG_UX, REPL_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug';
import { IDebugService, State, IDebugSession, CONTEXT_DEBUG_TYPE, CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_MODE, IThread, IDebugConfiguration, VIEWLET_ID, DEBUG_PANEL_ID, IConfig, ILaunch, IViewModel, IConfigurationManager, IDebugModel, IEnablement, IBreakpoint, IBreakpointData, ICompound, IGlobalConfig, IStackFrame, AdapterEndEvent, getStateLabel, IDebugSessionOptions, CONTEXT_DEBUG_UX, REPL_VIEW_ID, CONTEXT_BREAKPOINTS_EXIST } from 'vs/workbench/contrib/debug/common/debug';
import { getExtensionHostDebugSession } from 'vs/workbench/contrib/debug/common/debugUtils';
import { isErrorWithActions } from 'vs/base/common/errorsWithActions';
import { RunOnceScheduler } from 'vs/base/common/async';
@@ -69,6 +69,7 @@ export class DebugService implements IDebugService {
private debugState: IContextKey<string>;
private inDebugMode: IContextKey<boolean>;
private debugUx: IContextKey<string>;
private breakpointsExist: IContextKey<boolean>;
private breakpointsToSendOnResourceSaved: Set<string>;
private initializing = false;
private previousState: State | undefined;
@@ -117,6 +118,9 @@ export class DebugService implements IDebugService {
this.model = new DebugModel(this.loadBreakpoints(), this.loadFunctionBreakpoints(),
this.loadExceptionBreakpoints(), this.loadDataBreakpoints(), this.loadWatchExpressions(), this.textFileService);
this.toDispose.push(this.model);
const setBreakpointsExistContext = () => this.breakpointsExist.set(!!(this.model.getBreakpoints().length || this.model.getDataBreakpoints().length || this.model.getFunctionBreakpoints().length));
this.breakpointsExist = CONTEXT_BREAKPOINTS_EXIST.bindTo(contextKeyService);
setBreakpointsExistContext();
this.viewModel = new ViewModel(contextKeyService);
this.taskRunner = this.instantiationService.createInstance(DebugTaskRunner);
@@ -169,6 +173,7 @@ export class DebugService implements IDebugService {
this.activity = this.activityService.showActivity(VIEWLET_ID, new NumberBadge(numberOfSessions, n => n === 1 ? nls.localize('1activeSession', "1 active session") : nls.localize('nActiveSessions', "{0} active sessions", n)));
}
}));
this.toDispose.push(this.model.onDidChangeBreakpoints(() => setBreakpointsExistContext()));
}
getModel(): IDebugModel {
@@ -513,11 +518,14 @@ export class DebugService implements IDebugService {
try {
await session.initialize(dbgr!);
await session.launchOrAttach(session.configuration);
if (forceFocus || !this.viewModel.focusedSession) {
if (forceFocus || !this.viewModel.focusedSession || session.parentSession === this.viewModel.focusedSession) {
await this.focusStackFrame(undefined, undefined, session);
}
} catch (err) {
session.shutdown();
if (this.viewModel.focusedSession === session) {
await this.focusStackFrame(undefined);
}
return Promise.reject(err);
}
}
@@ -875,46 +883,44 @@ export class DebugService implements IDebugService {
await this.sendExceptionBreakpoints(session);
}
private sendBreakpoints(modelUri: uri, sourceModified = false, session?: IDebugSession): Promise<void> {
private async sendBreakpoints(modelUri: uri, sourceModified = false, session?: IDebugSession): Promise<void> {
const breakpointsToSend = this.model.getBreakpoints({ uri: modelUri, enabledOnly: true });
return this.sendToOneOrAllSessions(session, s =>
s.sendBreakpoints(modelUri, breakpointsToSend, sourceModified)
);
await sendToOneOrAllSessions(this.model, session, s => s.sendBreakpoints(modelUri, breakpointsToSend, sourceModified));
}
private sendFunctionBreakpoints(session?: IDebugSession): Promise<void> {
private async sendFunctionBreakpoints(session?: IDebugSession): Promise<void> {
const breakpointsToSend = this.model.getFunctionBreakpoints().filter(fbp => fbp.enabled && this.model.areBreakpointsActivated());
return this.sendToOneOrAllSessions(session, s => {
return s.capabilities.supportsFunctionBreakpoints ? s.sendFunctionBreakpoints(breakpointsToSend) : Promise.resolve(undefined);
await sendToOneOrAllSessions(this.model, session, async s => {
if (s.capabilities.supportsFunctionBreakpoints) {
await s.sendFunctionBreakpoints(breakpointsToSend);
}
});
}
private sendDataBreakpoints(session?: IDebugSession): Promise<void> {
const breakpointsToSend = this.model.getDataBreakpoints().filter(fbp => fbp.enabled && this.model.areBreakpointsActivated());
return this.sendToOneOrAllSessions(session, s => {
return s.capabilities.supportsDataBreakpoints ? s.sendDataBreakpoints(breakpointsToSend) : Promise.resolve(undefined);
return sendToOneOrAllSessions(this.model, session, async s => {
if (s.capabilities.supportsDataBreakpoints) {
await s.sendDataBreakpoints(breakpointsToSend);
}
});
}
private sendExceptionBreakpoints(session?: IDebugSession): Promise<void> {
const enabledExceptionBps = this.model.getExceptionBreakpoints().filter(exb => exb.enabled);
return this.sendToOneOrAllSessions(session, s => {
return s.sendExceptionBreakpoints(enabledExceptionBps);
return sendToOneOrAllSessions(this.model, session, async s => {
if (s.capabilities.supportsConfigurationDoneRequest && (!s.capabilities.exceptionBreakpointFilters || s.capabilities.exceptionBreakpointFilters.length === 0)) {
// Only call `setExceptionBreakpoints` as specified in dap protocol #90001
return;
}
await s.sendExceptionBreakpoints(enabledExceptionBps);
});
}
private async sendToOneOrAllSessions(session: IDebugSession | undefined, send: (session: IDebugSession) => Promise<void>): Promise<void> {
if (session) {
await send(session);
} else {
await Promise.all(this.model.getSessions().map(s => send(s)));
}
}
private onFileChanges(fileChangesEvent: FileChangesEvent): void {
const toRemove = this.model.getBreakpoints().filter(bp =>
fileChangesEvent.contains(bp.uri, FileChangeType.DELETED));
@@ -1126,3 +1132,11 @@ export function getStackFrameThreadAndSessionToFocus(model: IDebugModel, stackFr
return { session, thread, stackFrame };
}
async function sendToOneOrAllSessions(model: DebugModel, session: IDebugSession | undefined, send: (session: IDebugSession) => Promise<void>): Promise<void> {
if (session) {
await send(session);
} else {
await Promise.all(model.getSessions().map(s => send(s)));
}
}

View File

@@ -190,7 +190,7 @@ export class DebugSession implements IDebugSession {
try {
const customTelemetryService = await dbgr.getCustomTelemetryService();
const debugAdapter = await dbgr.createDebugAdapter(this);
this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.extensionHostDebugService, this.openerService);
this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.extensionHostDebugService, this.openerService, this.notificationService);
await this.raw.start();
this.registerListeners();
@@ -693,7 +693,6 @@ export class DebugSession implements IDebugSession {
await this.raw.configurationDone();
} catch (e) {
// Disconnect the debug session on configuration done error #10596
this.notificationService.error(e);
if (this.raw) {
this.raw.disconnect();
}

View File

@@ -8,7 +8,6 @@ import severity from 'vs/base/common/severity';
import { Event } from 'vs/base/common/event';
import Constants from 'vs/workbench/contrib/markers/browser/constants';
import { ITaskService, ITaskSummary } from 'vs/workbench/contrib/tasks/common/taskService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace';
import { TaskEvent, TaskEventKind, TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks';
@@ -18,6 +17,7 @@ import { withUndefinedAsNull } from 'vs/base/common/types';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug';
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
import { IViewsService } from 'vs/workbench/common/views';
function once(match: (e: TaskEvent) => boolean, event: Event<TaskEvent>): Event<TaskEvent> {
return (listener, thisArgs = null, disposables?) => {
@@ -44,7 +44,7 @@ export class DebugTaskRunner {
@ITaskService private readonly taskService: ITaskService,
@IMarkerService private readonly markerService: IMarkerService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IPanelService private readonly panelService: IPanelService,
@IViewsService private readonly viewsService: IViewsService,
@IDialogService private readonly dialogService: IDialogService,
) { }
@@ -56,7 +56,8 @@ export class DebugTaskRunner {
try {
this.canceled = false;
const taskSummary = await this.runTask(root, taskId);
if (this.canceled) {
if (this.canceled || (taskSummary && taskSummary.exitCode === undefined)) {
// User canceled, either debugging, or the prelaunch task
return TaskRunResult.Failure;
}
@@ -68,7 +69,7 @@ export class DebugTaskRunner {
return TaskRunResult.Success;
}
if (onTaskErrors === 'showErrors') {
this.panelService.openPanel(Constants.MARKERS_PANEL_ID);
await this.viewsService.openView(Constants.MARKERS_VIEW_ID);
return Promise.resolve(TaskRunResult.Failure);
}
@@ -77,7 +78,9 @@ export class DebugTaskRunner {
? nls.localize('preLaunchTaskErrors', "Errors exist after running preLaunchTask '{0}'.", taskLabel)
: errorCount === 1
? nls.localize('preLaunchTaskError', "Error exists after running preLaunchTask '{0}'.", taskLabel)
: nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", taskLabel, taskSummary ? taskSummary.exitCode : 0);
: taskSummary && typeof taskSummary.exitCode === 'number'
? nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", taskLabel, taskSummary.exitCode)
: nls.localize('preLaunchTaskTerminated', "The preLaunchTask '{0}' terminated.", taskLabel);
const result = await this.dialogService.show(severity.Warning, message, [nls.localize('debugAnyway', "Debug Anyway"), nls.localize('showErrors', "Show Errors"), nls.localize('cancel', "Cancel")], {
checkbox: {
@@ -97,7 +100,7 @@ export class DebugTaskRunner {
return TaskRunResult.Success;
}
this.panelService.openPanel(Constants.MARKERS_PANEL_ID);
await this.viewsService.openView(Constants.MARKERS_VIEW_ID);
return Promise.resolve(TaskRunResult.Failure);
} catch (err) {
await onError(err.message, [this.taskService.configureAction()]);

View File

@@ -606,8 +606,8 @@ export class LoadedScriptsView extends ViewPane {
}
dispose(): void {
this.tree = dispose(this.tree);
this.treeLabels = dispose(this.treeLabels);
dispose(this.tree);
dispose(this.treeLabels);
super.dispose();
}
}

View File

@@ -92,7 +92,6 @@
border-radius: 2px;
font-size: 0.9em;
padding: 0 3px;
margin-left: 0.8em;
line-height: 20px;
}
@@ -174,12 +173,7 @@
}
.debug-viewlet .debug-call-stack .monaco-list-row:hover .stack-frame.has-actions .file .line-number {
visibility: hidden;
}
.debug-viewlet .debug-call-stack .monaco-list-row:hover .stack-frame.has-actions .monaco-action-bar {
position: absolute;
right: 2px;
display: none;
}
.debug-viewlet .debug-call-stack .monaco-list-row .monaco-action-bar {
@@ -250,6 +244,7 @@
.debug-viewlet .debug-call-stack .stack-frame > .file > .file-name {
overflow: hidden;
text-overflow: ellipsis;
margin-right: 0.8em;
}
.vs-dark .debug-viewlet .debug-call-stack .monaco-list-row:not(.selected) .stack-frame > .file {

View File

@@ -30,10 +30,6 @@
cursor: pointer;
}
.monaco-workbench.mac .repl .repl-tree .monaco-tl-twistie {
padding-right: 2px;
}
.repl .repl-tree .output.expression.value-and-source {
display: flex;
}
@@ -63,10 +59,6 @@
cursor: text;
}
.repl .repl-tree .monaco-list-rows > .monaco-list-row .monaco-tl-twistie.collapsible {
padding-left: 18px !important;
}
.repl .repl-tree .output.expression > .value,
.repl .repl-tree .evaluation-result.expression > .value {
margin-left: 0px;

View File

@@ -19,6 +19,7 @@ import { env as processEnv } from 'vs/base/common/process';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { CancellationToken } from 'vs/base/common/cancellation';
import { INotificationService } from 'vs/platform/notification/common/notification';
/**
* This interface represents a single command line argument split into a "prefix" and a "path" half.
@@ -79,7 +80,8 @@ export class RawDebugSession implements IDisposable {
private readonly telemetryService: ITelemetryService,
public readonly customTelemetryService: ITelemetryService | undefined,
private readonly extensionHostDebugService: IExtensionHostDebugService,
private readonly openerService: IOpenerService
private readonly openerService: IOpenerService,
private readonly notificationService: INotificationService
) {
this.debugAdapter = debugAdapter;
this._capabilities = Object.create(null);
@@ -632,8 +634,8 @@ export class RawDebugSession implements IDisposable {
return errors.canceled();
}
const error = errorResponse && errorResponse.body ? errorResponse.body.error : null;
const errorMessage = errorResponse ? errorResponse.message || '' : '';
const error: DebugProtocol.Message | undefined = errorResponse?.body?.error;
const errorMessage = errorResponse?.message || '';
if (error && error.sendTelemetry) {
const telemetryMessage = error ? formatPII(error.format, true, error.variables) : errorMessage;
@@ -641,15 +643,19 @@ export class RawDebugSession implements IDisposable {
}
const userMessage = error ? formatPII(error.format, false, error.variables) : errorMessage;
if (error && error.url) {
const url = error?.url;
if (error && url) {
const label = error.urlLabel ? error.urlLabel : nls.localize('moreInfo', "More Info");
return createErrorWithActions(userMessage, {
actions: [new Action('debug.moreInfo', label, undefined, true, () => {
this.openerService.open(URI.parse(error.url));
this.openerService.open(URI.parse(url));
return Promise.resolve(null);
})]
});
}
if (error && error.format && error.showUser) {
this.notificationService.error(error.format);
}
return new Error(userMessage);
}

View File

@@ -18,7 +18,7 @@ import { registerEditorAction, ServicesAccessor, EditorAction } from 'vs/editor/
import { IModelService } from 'vs/editor/common/services/modelService';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
@@ -60,17 +60,8 @@ import { IViewsService, IViewDescriptorService } from 'vs/workbench/common/views
const $ = dom.$;
const HISTORY_STORAGE_KEY = 'debug.repl.history';
const IPrivateReplService = createDecorator<IPrivateReplService>('privateReplService');
const DECORATION_KEY = 'replinputdecoration';
interface IPrivateReplService {
_serviceBrand: undefined;
acceptReplInput(): void;
getVisibleContent(): string;
selectSession(session?: IDebugSession): Promise<void>;
clearRepl(): Promise<void>;
focusRepl(): void;
}
function revealLastElement(tree: WorkbenchAsyncDataTree<any, any, any>) {
tree.scrollTop = tree.scrollHeight - tree.renderHeight;
@@ -78,7 +69,7 @@ function revealLastElement(tree: WorkbenchAsyncDataTree<any, any, any>) {
const sessionsToIgnore = new Set<IDebugSession>();
export class Repl extends ViewPane implements IPrivateReplService, IHistoryNavigationWidget {
export class Repl extends ViewPane implements IHistoryNavigationWidget {
_serviceBrand: undefined;
private static readonly REFRESH_DELAY = 100; // delay in ms to refresh the repl for new elements to show
@@ -499,8 +490,7 @@ export class Repl extends ViewPane implements IPrivateReplService, IHistoryNavig
this._register(scopedContextKeyService);
CONTEXT_IN_DEBUG_REPL.bindTo(scopedContextKeyService).set(true);
this.scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection(
[IContextKeyService, scopedContextKeyService], [IPrivateReplService, this]));
this.scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, scopedContextKeyService]));
const options = getSimpleEditorOptions();
options.readOnly = true;
options.ariaLabel = localize('debugConsole', "Debug Console");
@@ -634,7 +624,8 @@ class AcceptReplInputAction extends EditorAction {
run(accessor: ServicesAccessor, editor: ICodeEditor): void | Promise<void> {
SuggestController.get(editor).acceptSelectedSuggestion(false, true);
accessor.get(IPrivateReplService).acceptReplInput();
const repl = getReplView(accessor.get(IViewsService));
repl?.acceptReplInput();
}
}
@@ -656,7 +647,8 @@ class FilterReplAction extends EditorAction {
run(accessor: ServicesAccessor, editor: ICodeEditor): void | Promise<void> {
SuggestController.get(editor).acceptSelectedSuggestion(false, true);
accessor.get(IPrivateReplService).focusRepl();
const repl = getReplView(accessor.get(IViewsService));
repl?.focusRepl();
}
}
@@ -673,7 +665,10 @@ class ReplCopyAllAction extends EditorAction {
run(accessor: ServicesAccessor, editor: ICodeEditor): void | Promise<void> {
const clipboardService = accessor.get(IClipboardService);
return clipboardService.writeText(accessor.get(IPrivateReplService).getVisibleContent());
const repl = getReplView(accessor.get(IViewsService));
if (repl) {
return clipboardService.writeText(repl.getVisibleContent());
}
}
}
@@ -702,7 +697,7 @@ class SelectReplAction extends Action {
constructor(id: string, label: string,
@IDebugService private readonly debugService: IDebugService,
@IPrivateReplService private readonly replService: IPrivateReplService
@IViewsService private readonly viewsService: IViewsService
) {
super(id, label);
}
@@ -712,7 +707,10 @@ class SelectReplAction extends Action {
if (session && session.state !== State.Inactive && session !== this.debugService.getViewModel().focusedSession) {
await this.debugService.focusStackFrame(undefined, undefined, session, true);
} else {
await this.replService.selectSession(session);
const repl = getReplView(this.viewsService);
if (repl) {
await repl.selectSession(session);
}
}
}
}
@@ -733,3 +731,7 @@ export class ClearReplAction extends Action {
aria.status(localize('debugConsoleCleared', "Debug console was cleared"));
}
}
function getReplView(viewsService: IViewsService): Repl | undefined {
return viewsService.getActiveViewWithId(REPL_VIEW_ID) as Repl ?? undefined;
}

View File

@@ -96,7 +96,6 @@ export class ReplEvaluationResultsRenderer implements ITreeRenderer<ReplEvaluati
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
@@ -230,7 +229,6 @@ export class ReplRawObjectsRenderer implements ITreeRenderer<RawObjectReplElemen
// value
renderExpressionValue(element.value, templateData.value, {
preserveWhitespace: true,
showHover: false,
linkDetector: this.linkDetector
});

View File

@@ -267,7 +267,6 @@ export class WatchExpressionsRenderer extends AbstractExpressionsRenderer {
renderExpressionValue(expression, data.value, {
showChanged: true,
maxValueLength: MAX_VALUE_RENDER_LENGTH_IN_VIEWLET,
preserveWhitespace: false,
showHover: true,
colorize: true
});

View File

@@ -55,6 +55,7 @@ export const CONTEXT_FOCUSED_SESSION_IS_ATTACH = new RawContextKey<boolean>('foc
export const CONTEXT_STEP_BACK_SUPPORTED = new RawContextKey<boolean>('stepBackSupported', false);
export const CONTEXT_RESTART_FRAME_SUPPORTED = new RawContextKey<boolean>('restartFrameSupported', false);
export const CONTEXT_JUMP_TO_CURSOR_SUPPORTED = new RawContextKey<boolean>('jumpToCursorSupported', false);
export const CONTEXT_BREAKPOINTS_EXIST = new RawContextKey<boolean>('breakpointsExist', false);
export const EDITOR_CONTRIBUTION_ID = 'editor.contrib.debug';
export const BREAKPOINT_EDITOR_CONTRIBUTION_ID = 'editor.contrib.breakpoint';

View File

@@ -17,7 +17,7 @@ import {
ITreeElement, IExpression, IExpressionContainer, IDebugSession, IStackFrame, IExceptionBreakpoint, IBreakpoint, IFunctionBreakpoint, IDebugModel,
IThread, IRawModelUpdate, IScope, IRawStoppedDetails, IEnablement, IBreakpointData, IExceptionInfo, IBreakpointsChangeEvent, IBreakpointUpdateData, IBaseBreakpoint, State, IDataBreakpoint
} from 'vs/workbench/contrib/debug/common/debug';
import { Source, UNKNOWN_SOURCE_LABEL } from 'vs/workbench/contrib/debug/common/debugSource';
import { Source, UNKNOWN_SOURCE_LABEL, getUriFromSource } from 'vs/workbench/contrib/debug/common/debugSource';
import { commonSuffixLength } from 'vs/base/common/strings';
import { posix } from 'vs/base/common/path';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
@@ -515,6 +515,7 @@ interface IBreakpointSessionData extends DebugProtocol.Breakpoint {
supportsLogPoints: boolean;
supportsFunctionBreakpoints: boolean;
supportsDataBreakpoints: boolean;
sessionId: string;
}
function toBreakpointSessionData(data: DebugProtocol.Breakpoint, capabilities: DebugProtocol.Capabilities): IBreakpointSessionData {
@@ -549,6 +550,7 @@ export abstract class BaseBreakpoint extends Enablement implements IBaseBreakpoi
if (!data) {
this.sessionData.delete(sessionId);
} else {
data.sessionId = sessionId;
this.sessionData.set(sessionId, data);
}
@@ -596,7 +598,7 @@ export abstract class BaseBreakpoint extends Enablement implements IBaseBreakpoi
export class Breakpoint extends BaseBreakpoint implements IBreakpoint {
constructor(
public uri: uri,
private _uri: uri,
private _lineNumber: number,
private _column: number | undefined,
enabled: boolean,
@@ -616,12 +618,16 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint {
get verified(): boolean {
if (this.data) {
return this.data.verified && !this.textFileService.isDirty(this.uri);
return this.data.verified && !this.textFileService.isDirty(this._uri);
}
return true;
}
get uri(): uri {
return this.verified && this.data && this.data.source ? getUriFromSource(this.data.source, this.data.source.path, this.data.sessionId) : this._uri;
}
get column(): number | undefined {
return this.verified && this.data && typeof this.data.column === 'number' ? this.data.column : this._column;
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { URI as uri } from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { normalize, isAbsolute } from 'vs/base/common/path';
import * as resources from 'vs/base/common/resources';
import { DEBUG_SCHEME } from 'vs/workbench/contrib/debug/common/debug';
@@ -13,6 +13,7 @@ import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/
import { Schemas } from 'vs/base/common/network';
import { isUri } from 'vs/workbench/contrib/debug/common/debugUtils';
import { ITextEditor } from 'vs/workbench/common/editor';
import { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor';
export const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source");
@@ -31,7 +32,7 @@ export const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Sourc
export class Source {
readonly uri: uri;
readonly uri: URI;
available: boolean;
raw: DebugProtocol.Source;
@@ -47,30 +48,7 @@ export class Source {
path = `${DEBUG_SCHEME}:${UNKNOWN_SOURCE_LABEL}`;
}
if (typeof this.raw.sourceReference === 'number' && this.raw.sourceReference > 0) {
this.uri = uri.from({
scheme: DEBUG_SCHEME,
path,
query: `session=${sessionId}&ref=${this.raw.sourceReference}`
});
} else {
if (isUri(path)) { // path looks like a uri
this.uri = uri.parse(path);
} else {
// assume a filesystem path
if (isAbsolute(path)) {
this.uri = uri.file(path);
} else {
// path is relative: since VS Code cannot deal with this by itself
// create a debug url that will result in a DAP 'source' request when the url is resolved.
this.uri = uri.from({
scheme: DEBUG_SCHEME,
path,
query: `session=${sessionId}`
});
}
}
}
this.uri = getUriFromSource(this.raw, path, sessionId);
}
get name() {
@@ -95,19 +73,19 @@ export class Source {
openInEditor(editorService: IEditorService, selection: IRange, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise<ITextEditor | undefined> {
return !this.available ? Promise.resolve(undefined) : editorService.openEditor({
resource: this.uri,
resource: this.uri.with({ query: null }),
description: this.origin,
options: {
preserveFocus,
selection,
revealIfOpened: true,
revealInCenterIfOutsideViewport: true,
selectionRevealType: TextEditorSelectionRevealType.CenterIfOutsideViewport,
pinned: pinned || (!preserveFocus && !this.inMemory)
}
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
}
static getEncodedDebugData(modelUri: uri): { name: string, path: string, sessionId?: string, sourceReference?: number } {
static getEncodedDebugData(modelUri: URI): { name: string, path: string, sessionId?: string, sourceReference?: number } {
let path: string;
let sourceReference: number | undefined;
let sessionId: string | undefined;
@@ -148,3 +126,28 @@ export class Source {
};
}
}
export function getUriFromSource(raw: DebugProtocol.Source, path: string | undefined, sessionId: string): URI {
if (typeof raw.sourceReference === 'number' && raw.sourceReference > 0) {
return URI.from({
scheme: DEBUG_SCHEME,
path,
query: `session=${sessionId}&ref=${raw.sourceReference}`
});
}
if (path && isUri(path)) { // path looks like a uri
return URI.parse(path);
}
// assume a filesystem path
if (path && isAbsolute(path)) {
return URI.file(path);
}
// path is relative: since VS Code cannot deal with this by itself
// create a debug url that will result in a DAP 'source' request when the url is resolved.
return URI.from({
scheme: DEBUG_SCHEME,
path,
query: `session=${sessionId}`
});
}

View File

@@ -11,7 +11,7 @@ import { deepClone } from 'vs/base/common/objects';
const _formatPIIRegexp = /{([^}]+)}/g;
export function formatPII(value: string, excludePII: boolean, args: { [key: string]: string }): string {
export function formatPII(value: string, excludePII: boolean, args: { [key: string]: string } | undefined): string {
return value.replace(_formatPIIRegexp, function (match, group) {
if (excludePII && group.length > 0 && group[0] !== '_') {
return match;
@@ -246,6 +246,9 @@ export function getVisibleAndSorted<T extends { presentation?: IConfigPresentati
return -1;
}
if (!first.presentation.group) {
if (!second.presentation.group) {
return compareOrders(first.presentation.order, second.presentation.order);
}
return 1;
}
if (!second.presentation.group) {
@@ -254,13 +257,18 @@ export function getVisibleAndSorted<T extends { presentation?: IConfigPresentati
if (first.presentation.group !== second.presentation.group) {
return first.presentation.group.localeCompare(second.presentation.group);
}
if (typeof first.presentation.order !== 'number') {
return 1;
}
if (typeof second.presentation.order !== 'number') {
return -1;
}
return first.presentation.order - second.presentation.order;
return compareOrders(first.presentation.order, second.presentation.order);
});
}
function compareOrders(first: number | undefined, second: number | undefined): number {
if (typeof first !== 'number') {
return 1;
}
if (typeof second !== 'number') {
return -1;
}
return first - second;
}

View File

@@ -4,17 +4,18 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { replaceWhitespace, renderExpressionValue, renderVariable, renderViewTree } from 'vs/workbench/contrib/debug/browser/baseDebugView';
import { renderExpressionValue, renderVariable, renderViewTree } from 'vs/workbench/contrib/debug/browser/baseDebugView';
import * as dom from 'vs/base/browser/dom';
import { Expression, Variable, Scope, StackFrame, Thread, DebugModel } from 'vs/workbench/contrib/debug/common/debugModel';
import { MockSession } from 'vs/workbench/contrib/debug/test/common/mockDebug';
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices';
import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
import { createMockSession } from 'vs/workbench/contrib/debug/test/browser/callStack.test';
import { isStatusbarInDebugMode } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider';
import { State } from 'vs/workbench/contrib/debug/common/debug';
import { isWindows } from 'vs/base/common/platform';
const $ = dom.$;
suite('Debug - Base Debug View', () => {
@@ -28,13 +29,6 @@ suite('Debug - Base Debug View', () => {
linkDetector = instantiationService.createInstance(LinkDetector);
});
test('replace whitespace', () => {
assert.equal(replaceWhitespace('hey there'), 'hey there');
assert.equal(replaceWhitespace('hey there\n'), 'hey there\\n');
assert.equal(replaceWhitespace('hey \r there\n\t'), 'hey \\r there\\n\\t');
assert.equal(replaceWhitespace('hey \r\t\n\t\t\n there'), 'hey \\r\\t\\n\\t\\t\\n there');
});
test('render view tree', () => {
const container = $('.container');
const treeContainer = renderViewTree(container);
@@ -47,7 +41,7 @@ suite('Debug - Base Debug View', () => {
test.skip('render expression value', () => { // {{SQL CARBON EDIT}} skip test
let container = $('.container');
renderExpressionValue('render \n me', container, { showHover: true, preserveWhitespace: true });
renderExpressionValue('render \n me', container, { showHover: true });
assert.equal(container.className, 'value');
assert.equal(container.title, 'render \n me');
assert.equal(container.textContent, 'render \n me');
@@ -76,7 +70,7 @@ suite('Debug - Base Debug View', () => {
renderExpressionValue(expression, container, { colorize: true, maxValueLength: 4, linkDetector });
assert.equal(container.textContent, 'this...');
expression.value = process.platform === 'win32' ? 'C:\\foo.js:5' : '/foo.js:5';
expression.value = isWindows ? 'C:\\foo.js:5' : '/foo.js:5';
container = $('.container');
renderExpressionValue(expression, container, { colorize: true, linkDetector });
assert.ok(container.querySelector('a'));
@@ -109,7 +103,7 @@ suite('Debug - Base Debug View', () => {
assert.equal(label.element.textContent, 'foo:');
assert.equal(label.element.title, 'string');
variable.value = process.platform === 'win32' ? 'C:\\foo.js:5' : '/foo.js:5';
variable.value = isWindows ? 'C:\\foo.js:5' : '/foo.js:5';
expression = $('.');
name = $('.');
value = $('.');

View File

@@ -5,7 +5,7 @@
import * as assert from 'assert';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices';
import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
import { isWindows } from 'vs/base/common/platform';
import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace';

View File

@@ -135,7 +135,7 @@ suite('Debug - REPL', () => {
model.addSession(session);
const adapter = new MockDebugAdapter();
const raw = new RawDebugSession(adapter, undefined!, undefined!, undefined!, undefined!, undefined!);
const raw = new RawDebugSession(adapter, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
session.initializeForTest(raw);
await session.addReplExpression(undefined, 'before.1');

View File

@@ -103,15 +103,34 @@ suite('Debug - Utils', () => {
order: 500
}
});
configs.push({
type: 'node',
request: 'launch',
name: 'h',
presentation: {
order: 700
}
});
configs.push({
type: 'node',
request: 'launch',
name: 'i',
presentation: {
order: 1000
}
});
const sorted = getVisibleAndSorted(configs);
assert.equal(sorted.length, 7);
assert.equal(sorted.length, 9);
assert.equal(sorted[0].name, 'f');
assert.equal(sorted[1].name, 'd');
assert.equal(sorted[2].name, 'e');
assert.equal(sorted[3].name, 'g');
assert.equal(sorted[4].name, 'b');
assert.equal(sorted[5].name, 'p');
assert.equal(sorted[6].name, 'a');
assert.equal(sorted[4].name, 'h');
assert.equal(sorted[5].name, 'i');
assert.equal(sorted[6].name, 'b');
assert.equal(sorted[7].name, 'p');
assert.equal(sorted[8].name, 'a');
});
});

View File

@@ -8,7 +8,7 @@ import * as dom from 'vs/base/browser/dom';
import { generateUuid } from 'vs/base/common/uuid';
import { appendStylizedStringToContainer, handleANSIOutput, calcANSI8bitColor } from 'vs/workbench/contrib/debug/browser/debugANSIHandling';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices';
import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
import { Color, RGBA } from 'vs/base/common/color';
import { IThemeService } from 'vs/platform/theme/common/themeService';

View File

@@ -11,7 +11,7 @@ import { Debugger } from 'vs/workbench/contrib/debug/common/debugger';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { URI } from 'vs/base/common/uri';
import { ExecutableDebugAdapter } from 'vs/workbench/contrib/debug/node/debugAdapter';
import { TestTextResourcePropertiesService } from 'vs/workbench/test/workbenchTestServices';
import { TestTextResourcePropertiesService } from 'vs/editor/test/common/services/modelService.test';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';