Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advance Debugging #5774

Merged
merged 12 commits into from
Jan 1, 2020
4 changes: 4 additions & 0 deletions packages/core/src/browser/icons/add-inverse.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions packages/core/src/browser/icons/add.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion packages/core/src/browser/icons/circle-bright.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion packages/core/src/browser/icons/circle-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions packages/core/src/browser/icons/close-all-bright.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions packages/core/src/browser/icons/close-all-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion packages/core/src/browser/icons/close-bright.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion packages/core/src/browser/icons/close-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion packages/core/src/browser/icons/collapse.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion packages/core/src/browser/icons/expand.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion packages/core/src/browser/shell/tab-bar-toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,10 @@ export class TabBarToolbar extends ReactWidget {
if (iconClass) {
classNames.push(iconClass);
}
const tooltip = item.tooltip || (command && command.label);
return <div key={item.id} className={`${TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM}${command && this.commandIsEnabled(command.id) ? ' enabled' : ''}`}
onMouseDown={this.onMouseDownEvent} onMouseUp={this.onMouseUpEvent} onMouseOut={this.onMouseUpEvent} >
<div id={item.id} className={classNames.join(' ')} onClick={this.executeCommand} title={item.tooltip}>{innerText}</div>
<div id={item.id} className={classNames.join(' ')} onClick={this.executeCommand} title={tooltip}>{innerText}</div>
</div>;
}

Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/browser/source-tree/source-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ export class SourceTree extends TreeImpl {
const updated = existing && <TreeElementNode>Object.assign(existing, { element, parent });
if (CompositeTreeElement.hasElements(element)) {
if (updated) {
if (!ExpandableTreeNode.is(updated)) {
Object.assign(updated, { expanded: false });
}
if (!CompositeTreeNode.is(updated)) {
Object.assign(updated, { children: [] });
}
return updated;
}
return {
Expand All @@ -65,6 +71,12 @@ export class SourceTree extends TreeImpl {
delete updated.children;
}
if (updated) {
if (ExpandableTreeNode.is(updated)) {
delete updated.expanded;
}
if (CompositeTreeNode.is(updated)) {
delete updated.children;
}
return updated;
}
return {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/browser/source-tree/tree-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// tslint:disable:no-any

import { ReactNode } from 'react';
import { injectable } from 'inversify';
import { injectable, unmanaged } from 'inversify';
import { Emitter, Event } from '../../common/event';
import { MaybePromise } from '../../common/types';
import { Disposable, DisposableCollection } from '../../common/disposable';
Expand Down Expand Up @@ -57,7 +57,7 @@ export abstract class TreeSource implements Disposable {
readonly id: string | undefined;
readonly placeholder: string | undefined;

constructor(options: TreeSourceOptions = {}) {
constructor(@unmanaged() options: TreeSourceOptions = {}) {
this.id = options.id;
this.placeholder = options.placeholder;
}
Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/browser/style/icons.css
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,15 @@
height: var(--theia-icon-size);
background: var(--theia-icon-open-json) no-repeat;
}

.theia-collapse-all-icon {
background: var(--theia-icon-collapse-all) center center no-repeat;
}

.theia-remove-all-icon {
background: var(--theia-icon-remove-all) center center no-repeat;
}

.theia-add-icon {
background: var(--theia-icon-add) center center no-repeat;
}
2 changes: 2 additions & 0 deletions packages/core/src/browser/style/variables-bright.useable.css
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ is not optimized for dense, information rich UIs.
--theia-icon-close-all: url(../icons/close-all-bright.svg);
--theia-icon-collapse: url(../icons/collapse.svg);
--theia-icon-collapse-all: url(../icons/CollapseAll.svg);
--theia-icon-remove-all: url(../icons/remove-all.svg);
--theia-icon-add: url(../icons/add.svg);
--theia-icon-clear: url(../icons/clear-search-results.svg);
--theia-icon-replace: url(../icons/replace.svg);
--theia-icon-replace-all: url(../icons/replace-all.svg);
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/browser/style/variables-dark.useable.css
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ is not optimized for dense, information rich UIs.
--theia-icon-close-all: url(../icons/close-all-dark.svg);
--theia-icon-collapse: url(../icons/collapse.svg);
--theia-icon-collapse-all: url(../icons/CollapseAll_inverse.svg);
--theia-icon-remove-all: url(../icons/remove-all-inverse.svg);
--theia-icon-add: url(../icons/add-inverse.svg);
--theia-icon-clear: url(../icons/clear-search-results-dark.svg);
--theia-icon-replace: url(../icons/replace-inverse.svg);
--theia-icon-replace-all: url(../icons/replace-all-inverse.svg);
Expand Down
140 changes: 128 additions & 12 deletions packages/debug/src/browser/breakpoint/breakpoint-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,29 @@
********************************************************************************/

import { injectable, inject } from 'inversify';
import { Emitter, Event } from '@theia/core/lib/common';
import { Emitter } from '@theia/core/lib/common';
import { StorageService } from '@theia/core/lib/browser';
import { Marker } from '@theia/markers/lib/common/marker';
import { MarkerManager } from '@theia/markers/lib/browser/marker-manager';
import URI from '@theia/core/lib/common/uri';
import { SourceBreakpoint, BREAKPOINT_KIND } from './breakpoint-marker';
import { SourceBreakpoint, BREAKPOINT_KIND, ExceptionBreakpoint, FunctionBreakpoint, BaseBreakpoint } from './breakpoint-marker';

export interface BreakpointsChangeEvent {
export interface BreakpointsChangeEvent<T extends BaseBreakpoint> {
uri: URI
added: SourceBreakpoint[]
removed: SourceBreakpoint[]
changed: SourceBreakpoint[]
added: T[]
removed: T[]
changed: T[]
}
export type SourceBreakpointsChangeEvent = BreakpointsChangeEvent<SourceBreakpoint>;
export type FunctionBreakpointsChangeEvent = BreakpointsChangeEvent<FunctionBreakpoint>;

@injectable()
export class BreakpointManager extends MarkerManager<SourceBreakpoint> {

static EXCEPTION_URI = new URI('debug:exception://');

static FUNCTION_URI = new URI('debug:function://');

protected readonly owner = 'breakpoint';

@inject(StorageService)
Expand All @@ -41,8 +47,11 @@ export class BreakpointManager extends MarkerManager<SourceBreakpoint> {
return BREAKPOINT_KIND;
}

protected readonly onDidChangeBreakpointsEmitter = new Emitter<BreakpointsChangeEvent>();
readonly onDidChangeBreakpoints: Event<BreakpointsChangeEvent> = this.onDidChangeBreakpointsEmitter.event;
protected readonly onDidChangeBreakpointsEmitter = new Emitter<SourceBreakpointsChangeEvent>();
readonly onDidChangeBreakpoints = this.onDidChangeBreakpointsEmitter.event;

protected readonly onDidChangeFunctionBreakpointsEmitter = new Emitter<FunctionBreakpointsChangeEvent>();
readonly onDidChangeFunctionBreakpoints = this.onDidChangeFunctionBreakpointsEmitter.event;

setMarkers(uri: URI, owner: string, newMarkers: SourceBreakpoint[]): Marker<SourceBreakpoint>[] {
const result = super.setMarkers(uri, owner, newMarkers);
Expand All @@ -68,10 +77,17 @@ export class BreakpointManager extends MarkerManager<SourceBreakpoint> {
return result;
}

getBreakpoint(uri: URI, line: number): SourceBreakpoint | undefined {
const marker = this.findMarkers({
getLineBreakpoints(uri: URI, line: number): SourceBreakpoint[] {
return this.findMarkers({
uri,
dataFilter: breakpoint => breakpoint.raw.line === line
}).map(({ data }) => data);
}

getInlineBreakpoint(uri: URI, line: number, column: number): SourceBreakpoint | undefined {
const marker = this.findMarkers({
uri,
dataFilter: breakpoint => breakpoint.raw.line === line && breakpoint.raw.column === column
})[0];
return marker && marker.data;
}
Expand All @@ -81,13 +97,13 @@ export class BreakpointManager extends MarkerManager<SourceBreakpoint> {
}

setBreakpoints(uri: URI, breakpoints: SourceBreakpoint[]): void {
this.setMarkers(uri, this.owner, breakpoints.sort((a, b) => a.raw.line - b.raw.line));
this.setMarkers(uri, this.owner, breakpoints.sort((a, b) => (a.raw.line - b.raw.line) || ((a.raw.column || 0) - (b.raw.column || 0))));
}

addBreakpoint(breakpoint: SourceBreakpoint): boolean {
const uri = new URI(breakpoint.uri);
const breakpoints = this.getBreakpoints(uri);
const newBreakpoints = breakpoints.filter(({ raw }) => raw.line !== breakpoint.raw.line);
const newBreakpoints = breakpoints.filter(({ raw }) => !(raw.line === breakpoint.raw.line && raw.column === breakpoint.raw.column));
if (breakpoints.length === newBreakpoints.length) {
newBreakpoints.push(breakpoint);
this.setBreakpoints(uri, newBreakpoints);
Expand All @@ -111,6 +127,17 @@ export class BreakpointManager extends MarkerManager<SourceBreakpoint> {
this.fireOnDidChangeMarkers(uri);
}
}
let didChangeFunction = false;
for (const breakpoint of this.getFunctionBreakpoints()) {
if (breakpoint.enabled !== enabled) {
breakpoint.enabled = enabled;
didChangeFunction = true;

}
}
if (didChangeFunction) {
this.fireOnDidChangeMarkers(BreakpointManager.FUNCTION_URI);
}
}

protected _breakpointsEnabled = true;
Expand All @@ -123,9 +150,84 @@ export class BreakpointManager extends MarkerManager<SourceBreakpoint> {
for (const uri of this.getUris()) {
this.fireOnDidChangeMarkers(new URI(uri));
}
this.fireOnDidChangeMarkers(BreakpointManager.FUNCTION_URI);
}
}

protected readonly exceptionBreakpoints = new Map<string, ExceptionBreakpoint>();

getExceptionBreakpoint(filter: string): ExceptionBreakpoint | undefined {
return this.exceptionBreakpoints.get(filter);
}

getExceptionBreakpoints(): IterableIterator<ExceptionBreakpoint> {
return this.exceptionBreakpoints.values();
}

setExceptionBreakpoints(exceptionBreakpoints: ExceptionBreakpoint[]): void {
const toRemove = new Set(this.exceptionBreakpoints.keys());
for (const exceptionBreakpoint of exceptionBreakpoints) {
const filter = exceptionBreakpoint.raw.filter;
toRemove.delete(filter);
this.exceptionBreakpoints.set(filter, exceptionBreakpoint);
}
for (const filter of toRemove) {
this.exceptionBreakpoints.delete(filter);
}
if (toRemove.size || exceptionBreakpoints.length) {
this.fireOnDidChangeMarkers(BreakpointManager.EXCEPTION_URI);
}
}

toggleExceptionBreakpoint(filter: string): void {
const breakpoint = this.getExceptionBreakpoint(filter);
if (breakpoint) {
breakpoint.enabled = !breakpoint.enabled;
this.fireOnDidChangeMarkers(BreakpointManager.EXCEPTION_URI);
}
}

protected functionBreakpoints: FunctionBreakpoint[] = [];

getFunctionBreakpoints(): FunctionBreakpoint[] {
return this.functionBreakpoints;
}

setFunctionBreakpoints(functionBreakpoints: FunctionBreakpoint[]): void {
const oldBreakpoints = new Map(this.functionBreakpoints.map(b => [b.id, b] as [string, FunctionBreakpoint]));

this.functionBreakpoints = functionBreakpoints;
this.fireOnDidChangeMarkers(BreakpointManager.FUNCTION_URI);

const added: FunctionBreakpoint[] = [];
const removed: FunctionBreakpoint[] = [];
const changed: FunctionBreakpoint[] = [];
const ids = new Set<string>();
for (const newBreakpoint of functionBreakpoints) {
ids.add(newBreakpoint.id);
if (oldBreakpoints.has(newBreakpoint.id)) {
changed.push(newBreakpoint);
} else {
added.push(newBreakpoint);
}
}
for (const [id, breakpoint] of oldBreakpoints.entries()) {
if (!ids.has(id)) {
removed.push(breakpoint);
}
}
this.onDidChangeFunctionBreakpointsEmitter.fire({ uri: BreakpointManager.FUNCTION_URI, added, removed, changed });
}

hasBreakpoints(): boolean {
return !!this.getUris().next().value || !!this.functionBreakpoints.length;
}

removeBreakpoints(): void {
this.cleanAllMarkers();
this.setFunctionBreakpoints([]);
}

async load(): Promise<void> {
const data = await this.storage.getData<BreakpointManager.Data>('breakpoints', {
breakpointsEnabled: true,
Expand All @@ -136,6 +238,12 @@ export class BreakpointManager extends MarkerManager<SourceBreakpoint> {
for (const uri in data.breakpoints) {
this.setBreakpoints(new URI(uri), data.breakpoints[uri]);
}
if (data.functionBreakpoints) {
this.setFunctionBreakpoints(data.functionBreakpoints);
}
if (data.exceptionBreakpoints) {
this.setExceptionBreakpoints(data.exceptionBreakpoints);
}
}

save(): void {
Expand All @@ -147,6 +255,12 @@ export class BreakpointManager extends MarkerManager<SourceBreakpoint> {
for (const uri of uris) {
data.breakpoints[uri] = this.findMarkers({ uri: new URI(uri) }).map(marker => marker.data);
}
if (this.functionBreakpoints.length) {
data.functionBreakpoints = this.functionBreakpoints;
}
if (this.exceptionBreakpoints.size) {
data.exceptionBreakpoints = [...this.exceptionBreakpoints.values()];
}
this.storage.setData('breakpoints', data);
}

Expand All @@ -157,5 +271,7 @@ export namespace BreakpointManager {
breakpoints: {
[uri: string]: SourceBreakpoint[]
}
exceptionBreakpoints?: ExceptionBreakpoint[]
functionBreakpoints?: FunctionBreakpoint[]
}
}
Loading