Skip to content
This repository has been archived by the owner on Jan 26, 2022. It is now read-only.

Display more variables during expand variable like Class #125

Merged
merged 18 commits into from
Nov 13, 2019
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/breakpoints/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
import { Toolbar, ToolbarButton } from '@jupyterlab/apputils';
import { IDisposable } from '@phosphor/disposable';
import { Signal } from '@phosphor/signaling';

import { Panel, PanelLayout, Widget } from '@phosphor/widgets';

import { DebugProtocol } from 'vscode-debugprotocol';

import { IDebugger } from '../tokens';

import { Body } from './body';

export class Breakpoints extends Panel {
Expand Down
24 changes: 24 additions & 0 deletions src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ export class DebugService implements IDebugger {
}

this._model.callstackModel.currentFrameChanged.connect(this.onChangeFrame);
this._model.variablesModel.variableExpanded.connect(this.getVariable);
};

onChangeFrame = (_: Callstack.Model, update: Callstack.IFrame) => {
Expand Down Expand Up @@ -328,6 +329,29 @@ export class DebugService implements IDebugger {
return reply.body.scopes;
};

getVariable = async (_: any, variable: DebugProtocol.Variable) => {
const reply = await this.session.sendRequest('variables', {
variablesReference: variable.variablesReference
});
let newVariable = { ...variable, haveMoreDetails: Symbol('haveDetails') };

reply.body.variables.forEach((variable: DebugProtocol.Variable) => {
newVariable = { [variable.name]: variable, ...newVariable };
});

const newScopes = this._model.variablesModel.scopes.map(scope => {
const findIndex = scope.variables.findIndex(
ele => ele.variablesReference === variable.variablesReference
);
scope.variables[findIndex] = newVariable;
return { ...scope };
});

this._model.variablesModel.scopes = [...newScopes];

return reply.body.variables;
};

getVariables = async (scopes: DebugProtocol.Scope[]) => {
if (!scopes || scopes.length === 0) {
return;
Expand Down
111 changes: 100 additions & 11 deletions src/variables/body/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@

import { Variables } from '../index';

import { ITheme, ObjectInspector, ObjectLabel } from 'react-inspector';
import { ITheme, ObjectInspector, ObjectRootLabel } from 'react-inspector';

import { ReactWidget } from '@jupyterlab/apputils';

import { ArrayExt } from '@phosphor/algorithm';

import React, { useEffect, useState } from 'react';

export class Body extends ReactWidget {
Expand All @@ -27,12 +28,64 @@ export class Body extends ReactWidget {
const VariableComponent = ({ model }: { model: Variables.Model }) => {
const [data, setData] = useState(model.scopes);

const filterVariable = (
variable: Variables.IVariable,
isObject?: boolean,
keyObj?: string
): Object => {
const tableKey = ['name', 'value', 'type'];
const filteredObj = Object.keys(variable)
.filter(
key =>
(isObject ? key === 'value' : tableKey.includes(key)) ||
(key !== 'presentationHint' &&
typeof (variable as any)[key] === 'object')
)
.reduce((res, key) => {
let valueOfKey =
key === 'value' ? convertType(variable) : (variable as any)[key];
if (typeof valueOfKey === 'object') {
return Object.assign(
res,
filterVariable(valueOfKey, true, key) as Object
);
}
if (isObject) {
return Object.assign(res, {
[keyObj]: valueOfKey
});
}

return Object.assign(res, {
[key]: valueOfKey
});
}, {});

return filteredObj;
};

const convertForObjectInspector = (scopes: Variables.IScope[]) => {
return scopes.map(scope => {
const newVariable = scope.variables.map(variable => {
if (variable.haveMoreDetails || variable.variablesReference === 0) {
return { ...filterVariable(variable) };
} else {
return {
expandVariable: () => model.expandVariable(variable),
...filterVariable(variable)
};
}
});
return { name: scope.name, variables: newVariable };
});
};

useEffect(() => {
const updateScopes = () => {
if (ArrayExt.shallowEqual(data, model.scopes)) {
const updateScopes = (self: Variables.Model) => {
if (ArrayExt.shallowEqual(data, self.scopes)) {
return;
}
setData(model.scopes);
setData(self.scopes);
};

model.changed.connect(updateScopes);
Expand All @@ -44,11 +97,11 @@ const VariableComponent = ({ model }: { model: Variables.Model }) => {

const List = () => (
<>
{data.map(scopes => (
{convertForObjectInspector(data).map(scope => (
<ObjectInspector
key={scopes.name}
data={scopes.variables}
name={scopes.name}
key={scope.name}
data={scope.variables}
name={scope.name}
nodeRenderer={defaultNodeRenderer}
theme={THEME}
expandLevel={1}
Expand All @@ -60,6 +113,24 @@ const VariableComponent = ({ model }: { model: Variables.Model }) => {
return <>{List()}</>;
};

const convertType = (variable: Variables.IVariable) => {
const type = variable.type;
let value: any = variable.value;
if (type === 'int' || type === 'float') {
return value * 1;
}
if (type === 'bool') {
return value === 'False' ? false : true;
}
if (type === 'str') {
return (value as string)
.split('')
.slice(1, value.length - 1)
.join('');
}
jtpio marked this conversation as resolved.
Show resolved Hide resolved
return value;
};

const defaultNodeRenderer = ({
depth,
name,
Expand All @@ -75,8 +146,26 @@ const defaultNodeRenderer = ({
expanded: boolean;
theme?: string | Partial<ITheme>;
}) => {
const types = ['bool', 'str', 'int', 'float'];
const label = data.name === '' || data.name == null ? name : data.name;
const value = data.value;
const value = types.includes(data.type)
? data.value
: data.type === 'type'
? 'class'
: data.type;

useEffect(() => {
if (expanded) {
if (data.expandVariable) {
data.expandVariable();
// for not node without rest variables,props
void requestAnimationFrame(() => {
return;
});
return;
}
}
});

return depth === 0 ? (
<span>
Expand All @@ -88,10 +177,10 @@ const defaultNodeRenderer = ({
<span>
<span style={{ color: THEME.OBJECT_NAME_COLOR }}>{label}</span>
<span>: </span>
<span>{value}</span>
<span style={{ color: THEME.OBJECT_VALUE_STRING_COLOR }}>{value}</span>
</span>
) : (
<ObjectLabel name={label} data={data} isNonenumerable={isNonenumerable} />
<ObjectRootLabel name={name} data={data} />
);
};

Expand Down
36 changes: 9 additions & 27 deletions src/variables/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ class VariablesHeader extends Widget {
}

export namespace Variables {
export interface IVariable extends DebugProtocol.Variable {}
export interface IVariable extends DebugProtocol.Variable {
getMoreDetails?: any;
haveMoreDetails?: Symbol;
}

export interface IScope {
name: string;
Expand All @@ -68,18 +71,6 @@ export namespace Variables {
return this._changed;
}

get currentVariable(): IVariable {
return this._currentVariable;
}

set currentVariable(variable: IVariable) {
if (this._currentVariable === variable) {
return;
}
this._currentVariable = variable;
this._currentVariableChanged.emit(variable);
}

get scopes(): IScope[] {
return this._state;
}
Expand All @@ -89,26 +80,17 @@ export namespace Variables {
this._changed.emit();
}

get variables(): IVariable[] {
return this._currentScope ? this._currentScope.variables : [];
get variableExpanded(): ISignal<this, IVariable> {
return this._variableExpanded;
}

set variables(variables: IVariable[]) {
this._currentScope.variables = variables;
this._changed.emit();
}

getCurrentVariables(): IVariable[] {
return this.variables;
expandVariable(variable: IVariable) {
this._variableExpanded.emit(variable);
}

protected _state: IScope[];

private _currentVariable: IVariable;
private _currentScope: IScope;

private _variableExpanded = new Signal<this, IVariable>(this);
private _changed = new Signal<this, void>(this);
private _currentVariableChanged = new Signal<this, IVariable>(this);
}

export interface IOptions extends Panel.IOptions {
Expand Down