Skip to content

Commit

Permalink
Merge branch 'main' into prickly-earthworm
Browse files Browse the repository at this point in the history
  • Loading branch information
yiliang114 authored Nov 28, 2023
2 parents 1f40cff + a3d5787 commit 38e7cd1
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 30 deletions.
4 changes: 2 additions & 2 deletions src/vs/workbench/browser/parts/editor/textDiffEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,9 @@ export class TextDiffEditor extends AbstractTextEditor<IDiffEditorViewState> imp
return editorConfiguration;
}

protected override getConfigurationOverrides(): IDiffEditorOptions {
protected override getConfigurationOverrides(configuration: IEditorConfiguration): IDiffEditorOptions {
return {
...super.getConfigurationOverrides(),
...super.getConfigurationOverrides(configuration),
...this.getReadonlyConfiguration(this.input?.isReadonly()),
originalEditable: this.input instanceof DiffEditorInput && !this.input.original.isReadonly(),
lineDecorationsWidth: '2ch'
Expand Down
10 changes: 6 additions & 4 deletions src/vs/workbench/browser/parts/editor/textEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ export interface IEditorConfiguration {
diffEditor?: boolean;
};
};
problems?: {
visibility?: boolean;
};
}

/**
Expand Down Expand Up @@ -116,7 +119,7 @@ export abstract class AbstractTextEditor<T extends IEditorViewState> extends Abs

// Specific editor options always overwrite user configuration
const editorConfiguration: ICodeEditorOptions = isObject(configuration.editor) ? deepClone(configuration.editor) : Object.create(null);
Object.assign(editorConfiguration, this.getConfigurationOverrides());
Object.assign(editorConfiguration, this.getConfigurationOverrides(configuration));

// ARIA label
editorConfiguration.ariaLabel = this.computeAriaLabel();
Expand Down Expand Up @@ -155,14 +158,13 @@ export abstract class AbstractTextEditor<T extends IEditorViewState> extends Abs
};
}

protected getConfigurationOverrides(): ICodeEditorOptions {
const config = this.textResourceConfigurationService.getValue(this.getActiveResource(), 'problems.visibility');
protected getConfigurationOverrides(configuration: IEditorConfiguration): ICodeEditorOptions {
return {
overviewRulerLanes: 3,
lineNumbersMinChars: 3,
fixedOverflowWidgets: true,
...this.getReadonlyConfiguration(this.input?.isReadonly()),
renderValidationDecorations: config ? 'on' : 'off'
renderValidationDecorations: configuration.problems?.visibility !== false ? 'on' : 'off'
};
}

Expand Down
160 changes: 152 additions & 8 deletions src/vs/workbench/contrib/debug/browser/breakpointsView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export function getExpandedBodySize(model: IDebugModel, sessionId: string | unde
type BreakpointItem = IBreakpoint | IFunctionBreakpoint | IDataBreakpoint | IExceptionBreakpoint | IInstructionBreakpoint;

interface InputBoxData {
breakpoint: IFunctionBreakpoint | IExceptionBreakpoint;
breakpoint: IFunctionBreakpoint | IExceptionBreakpoint | IDataBreakpoint;
type: 'condition' | 'hitCount' | 'name';
}

Expand Down Expand Up @@ -136,8 +136,9 @@ export class BreakpointsView extends ViewPane {
new ExceptionBreakpointsRenderer(this.menu, this.breakpointSupportsCondition, this.breakpointItemType, this.debugService),
new ExceptionBreakpointInputRenderer(this, this.debugService, this.contextViewService),
this.instantiationService.createInstance(FunctionBreakpointsRenderer, this.menu, this.breakpointSupportsCondition, this.breakpointItemType),
this.instantiationService.createInstance(DataBreakpointsRenderer),
new FunctionBreakpointInputRenderer(this, this.debugService, this.contextViewService, this.labelService),
this.instantiationService.createInstance(DataBreakpointsRenderer, this.menu, this.breakpointSupportsCondition, this.breakpointItemType),
new DataBreakpointInputRenderer(this, this.debugService, this.contextViewService, this.labelService),
this.instantiationService.createInstance(InstructionBreakpointsRenderer),
], {
identityProvider: { getId: (element: IEnablement) => element.getId() },
Expand Down Expand Up @@ -403,6 +404,11 @@ class BreakpointsDelegate implements IListVirtualDelegate<BreakpointItem> {
return ExceptionBreakpointsRenderer.ID;
}
if (element instanceof DataBreakpoint) {
const inputBoxBreakpoint = this.view.inputBoxData?.breakpoint;
if (inputBoxBreakpoint && inputBoxBreakpoint.getId() === element.getId()) {
return DataBreakpointInputRenderer.ID;
}

return DataBreakpointsRenderer.ID;
}
if (element instanceof InstructionBreakpoint) {
Expand Down Expand Up @@ -441,6 +447,7 @@ interface IFunctionBreakpointTemplateData extends IBaseBreakpointWithIconTemplat

interface IDataBreakpointTemplateData extends IBaseBreakpointWithIconTemplateData {
accessType: HTMLElement;
condition: HTMLElement;
}

interface IInstructionBreakpointTemplateData extends IBaseBreakpointWithIconTemplateData {
Expand All @@ -457,6 +464,16 @@ interface IFunctionBreakpointInputTemplateData {
updating?: boolean;
}

interface IDataBreakpointInputTemplateData {
inputBox: InputBox;
checkbox: HTMLInputElement;
icon: HTMLElement;
breakpoint: IDataBreakpoint;
toDispose: IDisposable[];
type: 'hitCount' | 'condition' | 'name';
updating?: boolean;
}

interface IExceptionBreakpointInputTemplateData {
inputBox: InputBox;
checkbox: HTMLInputElement;
Expand Down Expand Up @@ -657,7 +674,7 @@ class FunctionBreakpointsRenderer implements IListRenderer<FunctionBreakpoint, I
data.checkbox.checked = functionBreakpoint.enabled;
data.breakpoint.title = message ? message : '';
if (functionBreakpoint.condition && functionBreakpoint.hitCondition) {
data.condition.textContent = localize('expressionAndHitCount', "Expression: {0} | Hit Count: {1}", functionBreakpoint.condition, functionBreakpoint.hitCondition);
data.condition.textContent = localize('expressionAndHitCount', "Condition: {0} | Hit Count: {1}", functionBreakpoint.condition, functionBreakpoint.hitCondition);
} else {
data.condition.textContent = functionBreakpoint.condition || functionBreakpoint.hitCondition || '';
}
Expand Down Expand Up @@ -686,6 +703,9 @@ class FunctionBreakpointsRenderer implements IListRenderer<FunctionBreakpoint, I
class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IDataBreakpointTemplateData> {

constructor(
private menu: IMenu,
private breakpointSupportsCondition: IContextKey<boolean>,
private breakpointItemType: IContextKey<string | undefined>,
@IDebugService private readonly debugService: IDebugService,
@ILabelService private readonly labelService: ILabelService
) {
Expand Down Expand Up @@ -714,6 +734,10 @@ class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IDataBrea

data.name = dom.append(data.breakpoint, $('span.name'));
data.accessType = dom.append(data.breakpoint, $('span.access-type'));
data.condition = dom.append(data.breakpoint, $('span.condition'));

data.actionBar = new ActionBar(data.breakpoint);
data.toDispose.push(data.actionBar);

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

// Mark function breakpoints as disabled if deactivated or if debug type does not support them #9099
// Mark data breakpoints as disabled if deactivated or if debug type does not support them
const session = this.debugService.getViewModel().focusedSession;
data.breakpoint.classList.toggle('disabled', (session && !session.capabilities.supportsDataBreakpoints) || !this.debugService.getModel().areBreakpointsActivated());
if (session && !session.capabilities.supportsDataBreakpoints) {
Expand All @@ -739,6 +763,19 @@ class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IDataBrea
} else {
data.accessType.textContent = '';
}
if (dataBreakpoint.condition && dataBreakpoint.hitCondition) {
data.condition.textContent = localize('expressionAndHitCount', "Condition: {0} | Hit Count: {1}", dataBreakpoint.condition, dataBreakpoint.hitCondition);
} else {
data.condition.textContent = dataBreakpoint.condition || dataBreakpoint.hitCondition || '';
}

const primary: IAction[] = [];
this.breakpointSupportsCondition.set(!session || !!session.capabilities.supportsConditionalBreakpoints);
this.breakpointItemType.set('dataBreakpoint');
createAndFillInActionBarActions(this.menu, { arg: dataBreakpoint, shouldForwardArgs: true }, { primary, secondary: [] }, 'inline');
data.actionBar.clear();
data.actionBar.push(primary, { icon: true, label: false });
breakpointIdToActionBarDomeNode.set(dataBreakpoint.getId(), data.actionBar.domNode);
}

disposeTemplate(templateData: IBaseBreakpointWithIconTemplateData): void {
Expand Down Expand Up @@ -922,6 +959,113 @@ class FunctionBreakpointInputRenderer implements IListRenderer<IFunctionBreakpoi
}
}

class DataBreakpointInputRenderer implements IListRenderer<IDataBreakpoint, IDataBreakpointInputTemplateData> {

constructor(
private view: BreakpointsView,
private debugService: IDebugService,
private contextViewService: IContextViewService,
private labelService: ILabelService
) { }

static readonly ID = 'databreakpointinput';

get templateId() {
return DataBreakpointInputRenderer.ID;
}

renderTemplate(container: HTMLElement): IDataBreakpointInputTemplateData {
const template: IDataBreakpointInputTemplateData = Object.create(null);
const toDispose: IDisposable[] = [];

const breakpoint = dom.append(container, $('.breakpoint'));
template.icon = $('.icon');
template.checkbox = createCheckbox(toDispose);

dom.append(breakpoint, template.icon);
dom.append(breakpoint, template.checkbox);
this.view.breakpointInputFocused.set(true);
const inputBoxContainer = dom.append(breakpoint, $('.inputBoxContainer'));


const inputBox = new InputBox(inputBoxContainer, this.contextViewService, { inputBoxStyles: defaultInputBoxStyles });

const wrapUp = (success: boolean) => {
template.updating = true;
try {
this.view.breakpointInputFocused.set(false);
const id = template.breakpoint.getId();

if (success) {
if (template.type === 'condition') {
this.debugService.updateDataBreakpoint(id, { condition: inputBox.value });
}
if (template.type === 'hitCount') {
this.debugService.updateDataBreakpoint(id, { hitCondition: inputBox.value });
}
} else {
this.view.renderInputBox(undefined);
}
} finally {
template.updating = false;
}
};

toDispose.push(dom.addStandardDisposableListener(inputBox.inputElement, 'keydown', (e: IKeyboardEvent) => {
const isEscape = e.equals(KeyCode.Escape);
const isEnter = e.equals(KeyCode.Enter);
if (isEscape || isEnter) {
e.preventDefault();
e.stopPropagation();
wrapUp(isEnter);
}
}));
toDispose.push(dom.addDisposableListener(inputBox.inputElement, 'blur', () => {
if (!template.updating) {
wrapUp(!!inputBox.value);
}
}));

template.inputBox = inputBox;
template.toDispose = toDispose;
return template;
}

renderElement(dataBreakpoint: DataBreakpoint, _index: number, data: IDataBreakpointInputTemplateData): void {
data.breakpoint = dataBreakpoint;
data.type = this.view.inputBoxData?.type || 'condition'; // If there is no type set take the 'condition' as the default
const { icon, message } = getBreakpointMessageAndIcon(this.debugService.state, this.debugService.getModel().areBreakpointsActivated(), dataBreakpoint, this.labelService);

data.icon.className = ThemeIcon.asClassName(icon);
data.icon.title = message ? message : '';
data.checkbox.checked = dataBreakpoint.enabled;
data.checkbox.disabled = true;
data.inputBox.value = '';
let placeholder = '';
let ariaLabel = '';
if (data.type === 'condition') {
data.inputBox.value = dataBreakpoint.condition || '';
placeholder = localize('dataBreakpointExpressionPlaceholder', "Break when expression evaluates to true");
ariaLabel = localize('dataBreakPointExpresionAriaLabel', "Type expression. Data breakpoint will break when expression evaluates to true");
} else if (data.type === 'hitCount') {
data.inputBox.value = dataBreakpoint.hitCondition || '';
placeholder = localize('dataBreakpointHitCountPlaceholder', "Break when hit count is met");
ariaLabel = localize('dataBreakPointHitCountAriaLabel', "Type hit count. Data breakpoint will break when hit count is met.");
}
data.inputBox.setAriaLabel(ariaLabel);
data.inputBox.setPlaceHolder(placeholder);

setTimeout(() => {
data.inputBox.focus();
data.inputBox.select();
}, 0);
}

disposeTemplate(templateData: IDataBreakpointInputTemplateData): void {
dispose(templateData.toDispose);
}
}

class ExceptionBreakpointInputRenderer implements IListRenderer<IExceptionBreakpoint, IExceptionBreakpointInputTemplateData> {

constructor(
Expand Down Expand Up @@ -1109,7 +1253,7 @@ export function getBreakpointMessageAndIcon(state: State, breakpointsActivated:
const messages: string[] = [];
messages.push(breakpoint.message || localize('functionBreakpoint', "Function Breakpoint"));
if (breakpoint.condition) {
messages.push(localize('expression', "Expression condition: {0}", breakpoint.condition));
messages.push(localize('expression', "Condition: {0}", breakpoint.condition));
}
if (breakpoint.hitCondition) {
messages.push(localize('hitCount', "Hit Count: {0}", breakpoint.hitCondition));
Expand Down Expand Up @@ -1161,7 +1305,7 @@ export function getBreakpointMessageAndIcon(state: State, breakpointsActivated:
messages.push(localize('logMessage', "Log Message: {0}", breakpoint.logMessage));
}
if (breakpoint.condition) {
messages.push(localize('expression', "Expression condition: {0}", breakpoint.condition));
messages.push(localize('expression', "Condition: {0}", breakpoint.condition));
}
if (breakpoint.hitCondition) {
messages.push(localize('hitCount', "Hit Count: {0}", breakpoint.hitCondition));
Expand Down Expand Up @@ -1410,7 +1554,7 @@ registerAction2(class extends ViewAction<BreakpointsView> {
});
}

async runInView(accessor: ServicesAccessor, view: BreakpointsView, breakpoint: ExceptionBreakpoint | Breakpoint | FunctionBreakpoint): Promise<void> {
async runInView(accessor: ServicesAccessor, view: BreakpointsView, breakpoint: ExceptionBreakpoint | Breakpoint | FunctionBreakpoint | DataBreakpoint): Promise<void> {
const debugService = accessor.get(IDebugService);
const editorService = accessor.get(IEditorService);
if (breakpoint instanceof Breakpoint) {
Expand Down Expand Up @@ -1472,7 +1616,7 @@ registerAction2(class extends ViewAction<BreakpointsView> {
id: MenuId.DebugBreakpointsContext,
group: 'navigation',
order: 20,
when: CONTEXT_BREAKPOINT_ITEM_TYPE.isEqualTo('functionBreakpoint')
when: ContextKeyExpr.or(CONTEXT_BREAKPOINT_ITEM_TYPE.isEqualTo('functionBreakpoint'), CONTEXT_BREAKPOINT_ITEM_TYPE.isEqualTo('dataBreakpoint'))
}]
});
}
Expand Down
6 changes: 6 additions & 0 deletions src/vs/workbench/contrib/debug/browser/debugService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,12 @@ export class DebugService implements IDebugService {
this.debugStorage.storeBreakpoints(this.model);
}

async updateDataBreakpoint(id: string, update: { hitCondition?: string; condition?: string }): Promise<void> {
this.model.updateDataBreakpoint(id, update);
this.debugStorage.storeBreakpoints(this.model);
await this.sendDataBreakpoints();
}

async removeDataBreakpoints(id?: string): Promise<void> {
this.model.removeDataBreakpoints(id);
this.debugStorage.storeBreakpoints(this.model);
Expand Down
5 changes: 3 additions & 2 deletions src/vs/workbench/contrib/debug/browser/debugSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { mainWindow } from 'vs/base/browser/window';
import * as aria from 'vs/base/browser/ui/aria/aria';
import { distinct } from 'vs/base/common/arrays';
import { Queue, RunOnceScheduler } from 'vs/base/common/async';
Expand Down Expand Up @@ -40,6 +39,8 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
import { getActiveWindow } from 'vs/base/browser/dom';
import { mainWindow } from 'vs/base/browser/window';

export class DebugSession implements IDebugSession, IDisposable {
parentSession: IDebugSession | undefined;
Expand Down Expand Up @@ -1018,7 +1019,7 @@ export class DebugSession implements IDebugSession, IDisposable {
await this.paneCompositeService.openPaneComposite(VIEWLET_ID, ViewContainerLocation.Sidebar);
}

if (this.configurationService.getValue<IDebugConfiguration>('debug').focusWindowOnBreak && !this.workbenchEnvironmentService.extensionTestsLocationURI) {
if (this.configurationService.getValue<IDebugConfiguration>('debug').focusWindowOnBreak && !this.workbenchEnvironmentService.extensionTestsLocationURI && !getActiveWindow()) {
await this.hostService.focus(mainWindow, { force: true /* Application may not be active */ });
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,12 @@
justify-content: center;
}

.debug-pane .debug-breakpoints .breakpoint > .access-type,
.debug-pane .debug-breakpoints .breakpoint > .access-type {
opacity: 0.7;
margin-left: 0.9em;
text-overflow: ellipsis;
overflow: hidden;
}
.debug-pane .debug-breakpoints .breakpoint > .file-path,
.debug-pane .debug-breakpoints .breakpoint > .condition {
opacity: 0.7;
Expand Down
6 changes: 6 additions & 0 deletions src/vs/workbench/contrib/debug/common/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,12 @@ export interface IDebugService {
*/
addDataBreakpoint(label: string, dataId: string, canPersist: boolean, accessTypes: DebugProtocol.DataBreakpointAccessType[] | undefined, accessType: DebugProtocol.DataBreakpointAccessType): Promise<void>;

/**
* Updates an already existing data breakpoint.
* Notifies debug adapter of breakpoint changes.
*/
updateDataBreakpoint(id: string, update: { hitCondition?: string; condition?: string }): Promise<void>;

/**
* Removes all data breakpoints. If id is passed only removes the data breakpoint with the passed id.
* Notifies debug adapter of breakpoint changes.
Expand Down
Loading

0 comments on commit 38e7cd1

Please sign in to comment.