Skip to content

Commit 38e7cd1

Browse files
authored
Merge branch 'main' into prickly-earthworm
2 parents 1f40cff + a3d5787 commit 38e7cd1

File tree

12 files changed

+218
-30
lines changed

12 files changed

+218
-30
lines changed

src/vs/workbench/browser/parts/editor/textDiffEditor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,9 @@ export class TextDiffEditor extends AbstractTextEditor<IDiffEditorViewState> imp
267267
return editorConfiguration;
268268
}
269269

270-
protected override getConfigurationOverrides(): IDiffEditorOptions {
270+
protected override getConfigurationOverrides(configuration: IEditorConfiguration): IDiffEditorOptions {
271271
return {
272-
...super.getConfigurationOverrides(),
272+
...super.getConfigurationOverrides(configuration),
273273
...this.getReadonlyConfiguration(this.input?.isReadonly()),
274274
originalEditable: this.input instanceof DiffEditorInput && !this.input.original.isReadonly(),
275275
lineDecorationsWidth: '2ch'

src/vs/workbench/browser/parts/editor/textEditor.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ export interface IEditorConfiguration {
3838
diffEditor?: boolean;
3939
};
4040
};
41+
problems?: {
42+
visibility?: boolean;
43+
};
4144
}
4245

4346
/**
@@ -116,7 +119,7 @@ export abstract class AbstractTextEditor<T extends IEditorViewState> extends Abs
116119

117120
// Specific editor options always overwrite user configuration
118121
const editorConfiguration: ICodeEditorOptions = isObject(configuration.editor) ? deepClone(configuration.editor) : Object.create(null);
119-
Object.assign(editorConfiguration, this.getConfigurationOverrides());
122+
Object.assign(editorConfiguration, this.getConfigurationOverrides(configuration));
120123

121124
// ARIA label
122125
editorConfiguration.ariaLabel = this.computeAriaLabel();
@@ -155,14 +158,13 @@ export abstract class AbstractTextEditor<T extends IEditorViewState> extends Abs
155158
};
156159
}
157160

158-
protected getConfigurationOverrides(): ICodeEditorOptions {
159-
const config = this.textResourceConfigurationService.getValue(this.getActiveResource(), 'problems.visibility');
161+
protected getConfigurationOverrides(configuration: IEditorConfiguration): ICodeEditorOptions {
160162
return {
161163
overviewRulerLanes: 3,
162164
lineNumbersMinChars: 3,
163165
fixedOverflowWidgets: true,
164166
...this.getReadonlyConfiguration(this.input?.isReadonly()),
165-
renderValidationDecorations: config ? 'on' : 'off'
167+
renderValidationDecorations: configuration.problems?.visibility !== false ? 'on' : 'off'
166168
};
167169
}
168170

src/vs/workbench/contrib/debug/browser/breakpointsView.ts

Lines changed: 152 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export function getExpandedBodySize(model: IDebugModel, sessionId: string | unde
7272
type BreakpointItem = IBreakpoint | IFunctionBreakpoint | IDataBreakpoint | IExceptionBreakpoint | IInstructionBreakpoint;
7373

7474
interface InputBoxData {
75-
breakpoint: IFunctionBreakpoint | IExceptionBreakpoint;
75+
breakpoint: IFunctionBreakpoint | IExceptionBreakpoint | IDataBreakpoint;
7676
type: 'condition' | 'hitCount' | 'name';
7777
}
7878

@@ -136,8 +136,9 @@ export class BreakpointsView extends ViewPane {
136136
new ExceptionBreakpointsRenderer(this.menu, this.breakpointSupportsCondition, this.breakpointItemType, this.debugService),
137137
new ExceptionBreakpointInputRenderer(this, this.debugService, this.contextViewService),
138138
this.instantiationService.createInstance(FunctionBreakpointsRenderer, this.menu, this.breakpointSupportsCondition, this.breakpointItemType),
139-
this.instantiationService.createInstance(DataBreakpointsRenderer),
140139
new FunctionBreakpointInputRenderer(this, this.debugService, this.contextViewService, this.labelService),
140+
this.instantiationService.createInstance(DataBreakpointsRenderer, this.menu, this.breakpointSupportsCondition, this.breakpointItemType),
141+
new DataBreakpointInputRenderer(this, this.debugService, this.contextViewService, this.labelService),
141142
this.instantiationService.createInstance(InstructionBreakpointsRenderer),
142143
], {
143144
identityProvider: { getId: (element: IEnablement) => element.getId() },
@@ -403,6 +404,11 @@ class BreakpointsDelegate implements IListVirtualDelegate<BreakpointItem> {
403404
return ExceptionBreakpointsRenderer.ID;
404405
}
405406
if (element instanceof DataBreakpoint) {
407+
const inputBoxBreakpoint = this.view.inputBoxData?.breakpoint;
408+
if (inputBoxBreakpoint && inputBoxBreakpoint.getId() === element.getId()) {
409+
return DataBreakpointInputRenderer.ID;
410+
}
411+
406412
return DataBreakpointsRenderer.ID;
407413
}
408414
if (element instanceof InstructionBreakpoint) {
@@ -441,6 +447,7 @@ interface IFunctionBreakpointTemplateData extends IBaseBreakpointWithIconTemplat
441447

442448
interface IDataBreakpointTemplateData extends IBaseBreakpointWithIconTemplateData {
443449
accessType: HTMLElement;
450+
condition: HTMLElement;
444451
}
445452

446453
interface IInstructionBreakpointTemplateData extends IBaseBreakpointWithIconTemplateData {
@@ -457,6 +464,16 @@ interface IFunctionBreakpointInputTemplateData {
457464
updating?: boolean;
458465
}
459466

467+
interface IDataBreakpointInputTemplateData {
468+
inputBox: InputBox;
469+
checkbox: HTMLInputElement;
470+
icon: HTMLElement;
471+
breakpoint: IDataBreakpoint;
472+
toDispose: IDisposable[];
473+
type: 'hitCount' | 'condition' | 'name';
474+
updating?: boolean;
475+
}
476+
460477
interface IExceptionBreakpointInputTemplateData {
461478
inputBox: InputBox;
462479
checkbox: HTMLInputElement;
@@ -657,7 +674,7 @@ class FunctionBreakpointsRenderer implements IListRenderer<FunctionBreakpoint, I
657674
data.checkbox.checked = functionBreakpoint.enabled;
658675
data.breakpoint.title = message ? message : '';
659676
if (functionBreakpoint.condition && functionBreakpoint.hitCondition) {
660-
data.condition.textContent = localize('expressionAndHitCount', "Expression: {0} | Hit Count: {1}", functionBreakpoint.condition, functionBreakpoint.hitCondition);
677+
data.condition.textContent = localize('expressionAndHitCount', "Condition: {0} | Hit Count: {1}", functionBreakpoint.condition, functionBreakpoint.hitCondition);
661678
} else {
662679
data.condition.textContent = functionBreakpoint.condition || functionBreakpoint.hitCondition || '';
663680
}
@@ -686,6 +703,9 @@ class FunctionBreakpointsRenderer implements IListRenderer<FunctionBreakpoint, I
686703
class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IDataBreakpointTemplateData> {
687704

688705
constructor(
706+
private menu: IMenu,
707+
private breakpointSupportsCondition: IContextKey<boolean>,
708+
private breakpointItemType: IContextKey<string | undefined>,
689709
@IDebugService private readonly debugService: IDebugService,
690710
@ILabelService private readonly labelService: ILabelService
691711
) {
@@ -714,6 +734,10 @@ class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IDataBrea
714734

715735
data.name = dom.append(data.breakpoint, $('span.name'));
716736
data.accessType = dom.append(data.breakpoint, $('span.access-type'));
737+
data.condition = dom.append(data.breakpoint, $('span.condition'));
738+
739+
data.actionBar = new ActionBar(data.breakpoint);
740+
data.toDispose.push(data.actionBar);
717741

718742
return data;
719743
}
@@ -727,7 +751,7 @@ class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IDataBrea
727751
data.checkbox.checked = dataBreakpoint.enabled;
728752
data.breakpoint.title = message ? message : '';
729753

730-
// Mark function breakpoints as disabled if deactivated or if debug type does not support them #9099
754+
// Mark data breakpoints as disabled if deactivated or if debug type does not support them
731755
const session = this.debugService.getViewModel().focusedSession;
732756
data.breakpoint.classList.toggle('disabled', (session && !session.capabilities.supportsDataBreakpoints) || !this.debugService.getModel().areBreakpointsActivated());
733757
if (session && !session.capabilities.supportsDataBreakpoints) {
@@ -739,6 +763,19 @@ class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IDataBrea
739763
} else {
740764
data.accessType.textContent = '';
741765
}
766+
if (dataBreakpoint.condition && dataBreakpoint.hitCondition) {
767+
data.condition.textContent = localize('expressionAndHitCount', "Condition: {0} | Hit Count: {1}", dataBreakpoint.condition, dataBreakpoint.hitCondition);
768+
} else {
769+
data.condition.textContent = dataBreakpoint.condition || dataBreakpoint.hitCondition || '';
770+
}
771+
772+
const primary: IAction[] = [];
773+
this.breakpointSupportsCondition.set(!session || !!session.capabilities.supportsConditionalBreakpoints);
774+
this.breakpointItemType.set('dataBreakpoint');
775+
createAndFillInActionBarActions(this.menu, { arg: dataBreakpoint, shouldForwardArgs: true }, { primary, secondary: [] }, 'inline');
776+
data.actionBar.clear();
777+
data.actionBar.push(primary, { icon: true, label: false });
778+
breakpointIdToActionBarDomeNode.set(dataBreakpoint.getId(), data.actionBar.domNode);
742779
}
743780

744781
disposeTemplate(templateData: IBaseBreakpointWithIconTemplateData): void {
@@ -922,6 +959,113 @@ class FunctionBreakpointInputRenderer implements IListRenderer<IFunctionBreakpoi
922959
}
923960
}
924961

962+
class DataBreakpointInputRenderer implements IListRenderer<IDataBreakpoint, IDataBreakpointInputTemplateData> {
963+
964+
constructor(
965+
private view: BreakpointsView,
966+
private debugService: IDebugService,
967+
private contextViewService: IContextViewService,
968+
private labelService: ILabelService
969+
) { }
970+
971+
static readonly ID = 'databreakpointinput';
972+
973+
get templateId() {
974+
return DataBreakpointInputRenderer.ID;
975+
}
976+
977+
renderTemplate(container: HTMLElement): IDataBreakpointInputTemplateData {
978+
const template: IDataBreakpointInputTemplateData = Object.create(null);
979+
const toDispose: IDisposable[] = [];
980+
981+
const breakpoint = dom.append(container, $('.breakpoint'));
982+
template.icon = $('.icon');
983+
template.checkbox = createCheckbox(toDispose);
984+
985+
dom.append(breakpoint, template.icon);
986+
dom.append(breakpoint, template.checkbox);
987+
this.view.breakpointInputFocused.set(true);
988+
const inputBoxContainer = dom.append(breakpoint, $('.inputBoxContainer'));
989+
990+
991+
const inputBox = new InputBox(inputBoxContainer, this.contextViewService, { inputBoxStyles: defaultInputBoxStyles });
992+
993+
const wrapUp = (success: boolean) => {
994+
template.updating = true;
995+
try {
996+
this.view.breakpointInputFocused.set(false);
997+
const id = template.breakpoint.getId();
998+
999+
if (success) {
1000+
if (template.type === 'condition') {
1001+
this.debugService.updateDataBreakpoint(id, { condition: inputBox.value });
1002+
}
1003+
if (template.type === 'hitCount') {
1004+
this.debugService.updateDataBreakpoint(id, { hitCondition: inputBox.value });
1005+
}
1006+
} else {
1007+
this.view.renderInputBox(undefined);
1008+
}
1009+
} finally {
1010+
template.updating = false;
1011+
}
1012+
};
1013+
1014+
toDispose.push(dom.addStandardDisposableListener(inputBox.inputElement, 'keydown', (e: IKeyboardEvent) => {
1015+
const isEscape = e.equals(KeyCode.Escape);
1016+
const isEnter = e.equals(KeyCode.Enter);
1017+
if (isEscape || isEnter) {
1018+
e.preventDefault();
1019+
e.stopPropagation();
1020+
wrapUp(isEnter);
1021+
}
1022+
}));
1023+
toDispose.push(dom.addDisposableListener(inputBox.inputElement, 'blur', () => {
1024+
if (!template.updating) {
1025+
wrapUp(!!inputBox.value);
1026+
}
1027+
}));
1028+
1029+
template.inputBox = inputBox;
1030+
template.toDispose = toDispose;
1031+
return template;
1032+
}
1033+
1034+
renderElement(dataBreakpoint: DataBreakpoint, _index: number, data: IDataBreakpointInputTemplateData): void {
1035+
data.breakpoint = dataBreakpoint;
1036+
data.type = this.view.inputBoxData?.type || 'condition'; // If there is no type set take the 'condition' as the default
1037+
const { icon, message } = getBreakpointMessageAndIcon(this.debugService.state, this.debugService.getModel().areBreakpointsActivated(), dataBreakpoint, this.labelService);
1038+
1039+
data.icon.className = ThemeIcon.asClassName(icon);
1040+
data.icon.title = message ? message : '';
1041+
data.checkbox.checked = dataBreakpoint.enabled;
1042+
data.checkbox.disabled = true;
1043+
data.inputBox.value = '';
1044+
let placeholder = '';
1045+
let ariaLabel = '';
1046+
if (data.type === 'condition') {
1047+
data.inputBox.value = dataBreakpoint.condition || '';
1048+
placeholder = localize('dataBreakpointExpressionPlaceholder', "Break when expression evaluates to true");
1049+
ariaLabel = localize('dataBreakPointExpresionAriaLabel', "Type expression. Data breakpoint will break when expression evaluates to true");
1050+
} else if (data.type === 'hitCount') {
1051+
data.inputBox.value = dataBreakpoint.hitCondition || '';
1052+
placeholder = localize('dataBreakpointHitCountPlaceholder', "Break when hit count is met");
1053+
ariaLabel = localize('dataBreakPointHitCountAriaLabel', "Type hit count. Data breakpoint will break when hit count is met.");
1054+
}
1055+
data.inputBox.setAriaLabel(ariaLabel);
1056+
data.inputBox.setPlaceHolder(placeholder);
1057+
1058+
setTimeout(() => {
1059+
data.inputBox.focus();
1060+
data.inputBox.select();
1061+
}, 0);
1062+
}
1063+
1064+
disposeTemplate(templateData: IDataBreakpointInputTemplateData): void {
1065+
dispose(templateData.toDispose);
1066+
}
1067+
}
1068+
9251069
class ExceptionBreakpointInputRenderer implements IListRenderer<IExceptionBreakpoint, IExceptionBreakpointInputTemplateData> {
9261070

9271071
constructor(
@@ -1109,7 +1253,7 @@ export function getBreakpointMessageAndIcon(state: State, breakpointsActivated:
11091253
const messages: string[] = [];
11101254
messages.push(breakpoint.message || localize('functionBreakpoint', "Function Breakpoint"));
11111255
if (breakpoint.condition) {
1112-
messages.push(localize('expression', "Expression condition: {0}", breakpoint.condition));
1256+
messages.push(localize('expression', "Condition: {0}", breakpoint.condition));
11131257
}
11141258
if (breakpoint.hitCondition) {
11151259
messages.push(localize('hitCount', "Hit Count: {0}", breakpoint.hitCondition));
@@ -1161,7 +1305,7 @@ export function getBreakpointMessageAndIcon(state: State, breakpointsActivated:
11611305
messages.push(localize('logMessage', "Log Message: {0}", breakpoint.logMessage));
11621306
}
11631307
if (breakpoint.condition) {
1164-
messages.push(localize('expression', "Expression condition: {0}", breakpoint.condition));
1308+
messages.push(localize('expression', "Condition: {0}", breakpoint.condition));
11651309
}
11661310
if (breakpoint.hitCondition) {
11671311
messages.push(localize('hitCount', "Hit Count: {0}", breakpoint.hitCondition));
@@ -1410,7 +1554,7 @@ registerAction2(class extends ViewAction<BreakpointsView> {
14101554
});
14111555
}
14121556

1413-
async runInView(accessor: ServicesAccessor, view: BreakpointsView, breakpoint: ExceptionBreakpoint | Breakpoint | FunctionBreakpoint): Promise<void> {
1557+
async runInView(accessor: ServicesAccessor, view: BreakpointsView, breakpoint: ExceptionBreakpoint | Breakpoint | FunctionBreakpoint | DataBreakpoint): Promise<void> {
14141558
const debugService = accessor.get(IDebugService);
14151559
const editorService = accessor.get(IEditorService);
14161560
if (breakpoint instanceof Breakpoint) {
@@ -1472,7 +1616,7 @@ registerAction2(class extends ViewAction<BreakpointsView> {
14721616
id: MenuId.DebugBreakpointsContext,
14731617
group: 'navigation',
14741618
order: 20,
1475-
when: CONTEXT_BREAKPOINT_ITEM_TYPE.isEqualTo('functionBreakpoint')
1619+
when: ContextKeyExpr.or(CONTEXT_BREAKPOINT_ITEM_TYPE.isEqualTo('functionBreakpoint'), CONTEXT_BREAKPOINT_ITEM_TYPE.isEqualTo('dataBreakpoint'))
14761620
}]
14771621
});
14781622
}

src/vs/workbench/contrib/debug/browser/debugService.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,12 @@ export class DebugService implements IDebugService {
10431043
this.debugStorage.storeBreakpoints(this.model);
10441044
}
10451045

1046+
async updateDataBreakpoint(id: string, update: { hitCondition?: string; condition?: string }): Promise<void> {
1047+
this.model.updateDataBreakpoint(id, update);
1048+
this.debugStorage.storeBreakpoints(this.model);
1049+
await this.sendDataBreakpoints();
1050+
}
1051+
10461052
async removeDataBreakpoints(id?: string): Promise<void> {
10471053
this.model.removeDataBreakpoints(id);
10481054
this.debugStorage.storeBreakpoints(this.model);

src/vs/workbench/contrib/debug/browser/debugSession.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { mainWindow } from 'vs/base/browser/window';
76
import * as aria from 'vs/base/browser/ui/aria/aria';
87
import { distinct } from 'vs/base/common/arrays';
98
import { Queue, RunOnceScheduler } from 'vs/base/common/async';
@@ -40,6 +39,8 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
4039
import { IHostService } from 'vs/workbench/services/host/browser/host';
4140
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
4241
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
42+
import { getActiveWindow } from 'vs/base/browser/dom';
43+
import { mainWindow } from 'vs/base/browser/window';
4344

4445
export class DebugSession implements IDebugSession, IDisposable {
4546
parentSession: IDebugSession | undefined;
@@ -1018,7 +1019,7 @@ export class DebugSession implements IDebugSession, IDisposable {
10181019
await this.paneCompositeService.openPaneComposite(VIEWLET_ID, ViewContainerLocation.Sidebar);
10191020
}
10201021

1021-
if (this.configurationService.getValue<IDebugConfiguration>('debug').focusWindowOnBreak && !this.workbenchEnvironmentService.extensionTestsLocationURI) {
1022+
if (this.configurationService.getValue<IDebugConfiguration>('debug').focusWindowOnBreak && !this.workbenchEnvironmentService.extensionTestsLocationURI && !getActiveWindow()) {
10221023
await this.hostService.focus(mainWindow, { force: true /* Application may not be active */ });
10231024
}
10241025
}

src/vs/workbench/contrib/debug/browser/media/debugViewlet.css

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,12 @@
312312
justify-content: center;
313313
}
314314

315-
.debug-pane .debug-breakpoints .breakpoint > .access-type,
315+
.debug-pane .debug-breakpoints .breakpoint > .access-type {
316+
opacity: 0.7;
317+
margin-left: 0.9em;
318+
text-overflow: ellipsis;
319+
overflow: hidden;
320+
}
316321
.debug-pane .debug-breakpoints .breakpoint > .file-path,
317322
.debug-pane .debug-breakpoints .breakpoint > .condition {
318323
opacity: 0.7;

src/vs/workbench/contrib/debug/common/debug.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,12 @@ export interface IDebugService {
10921092
*/
10931093
addDataBreakpoint(label: string, dataId: string, canPersist: boolean, accessTypes: DebugProtocol.DataBreakpointAccessType[] | undefined, accessType: DebugProtocol.DataBreakpointAccessType): Promise<void>;
10941094

1095+
/**
1096+
* Updates an already existing data breakpoint.
1097+
* Notifies debug adapter of breakpoint changes.
1098+
*/
1099+
updateDataBreakpoint(id: string, update: { hitCondition?: string; condition?: string }): Promise<void>;
1100+
10951101
/**
10961102
* Removes all data breakpoints. If id is passed only removes the data breakpoint with the passed id.
10971103
* Notifies debug adapter of breakpoint changes.

0 commit comments

Comments
 (0)