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

Handle multiple scopes #570

Merged
merged 1 commit into from
Dec 10, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions schema/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"$ref": "#/definitions/variableFilters",
"default": {
"xpython": [
"debugpy",
"display",
"get_ipython",
"ptvsd",
Expand Down
80 changes: 61 additions & 19 deletions src/panels/variables/grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ export class VariablesBodyGrid extends Panel {
*/
constructor(options: VariablesBodyGrid.IOptions) {
super();
const { model, commands, scopes, themeManager } = options;
const { model, commands, themeManager, scopes } = options;
this._grid = new Grid({ commands, themeManager });
this._grid.addClass('jp-DebuggerVariables-grid');
this._model = model;
this._model.changed.connect((model: VariablesModel): void => {
this._grid.dataModel.setData(model.scopes);
this._update();
}, this);
this._grid.dataModel.setData(scopes ?? []);
this.addWidget(this._grid);
Expand All @@ -54,7 +54,24 @@ export class VariablesBodyGrid extends Panel {
*/
set filter(filter: Set<string>) {
(this._grid.dataModel as GridModel).filter = filter;
this._grid.dataModel.setData(this._model.scopes);
this._update();
}

/**
* Set the current scope.
*
* @param scope The current scope for the variables.
*/
set scope(scope: string) {
(this._grid.dataModel as GridModel).scope = scope;
this._update();
}

/**
* Update the underlying data model
*/
private _update(): void {
this._grid.dataModel.setData(this._model.scopes ?? []);
}

private _grid: Grid;
Expand Down Expand Up @@ -139,6 +156,16 @@ class Grid extends Panel {
this.update();
}

/**
* Set the scope for the variables data model.
*
* @param scope The scopes for the variables
*/
set scope(scope: string) {
(this._grid.dataModel as GridModel).scope = scope;
this.update();
}

/**
* Get the data model for the data grid.
*/
Expand Down Expand Up @@ -199,6 +226,20 @@ class GridModel extends DataModel {
this._filter = filter;
}

/**
* Get the current scope for the variables.
*/
get scope(): string {
return this._scope;
}

/**
* Set the variable scope
*/
set scope(scope: string) {
this._scope = scope;
}

/**
* Get the row count for a particular region in the data grid.
*
Expand Down Expand Up @@ -268,22 +309,22 @@ class GridModel extends DataModel {
type: 'model-reset',
region: 'body'
});
scopes.forEach(scope => {
const filtered = scope.variables.filter(
variable => !this._filter.has(variable.evaluateName)
);
filtered.forEach((variable, index) => {
this._data.name[index] = variable.evaluateName;
this._data.type[index] = variable.type;
this._data.value[index] = variable.value;
this._data.variablesReference[index] = variable.variablesReference;
});
this.emitChanged({
type: 'rows-inserted',
region: 'body',
index: 1,
span: filtered.length
});
const scope = scopes.find(scope => scope.name === this._scope) ?? scopes[0];
const variables = scope?.variables ?? [];
const filtered = variables.filter(
variable => variable.name && !this._filter.has(variable.name)
);
filtered.forEach((variable, index) => {
this._data.name[index] = variable.name;
this._data.type[index] = variable.type ?? '';
this._data.value[index] = variable.value;
this._data.variablesReference[index] = variable.variablesReference;
});
this.emitChanged({
type: 'rows-inserted',
region: 'body',
index: 1,
span: filtered.length
});
}

Expand All @@ -300,6 +341,7 @@ class GridModel extends DataModel {
}

private _filter = new Set<string>();
private _scope = '';
private _data: {
name: string[];
type: string[];
Expand Down
17 changes: 14 additions & 3 deletions src/panels/variables/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { VariablesBodyGrid } from './grid';

import { VariablesHeader } from './header';

import { ScopeSwitcher } from './scope';

import { VariablesBodyTree } from './tree';

/**
Expand All @@ -34,7 +36,7 @@ export class Variables extends Panel {
this._table = new VariablesBodyGrid({ model, commands, themeManager });
this._table.hide();

const onClick = (): void => {
const onViewChange = (): void => {
if (this._table.isHidden) {
this._tree.hide();
this._table.show();
Expand All @@ -47,11 +49,20 @@ export class Variables extends Panel {
this.update();
};

this._header.toolbar.addItem(
'scope-switcher',
new ScopeSwitcher({
model,
tree: this._tree,
grid: this._table
})
);

this._header.toolbar.addItem(
'view-VariableSwitch',
new ToolbarButton({
iconClass: 'jp-ToggleSwitch',
onClick,
onClick: onViewChange,
tooltip: 'Table / Tree View'
})
);
Expand Down Expand Up @@ -112,7 +123,7 @@ export const convertType = (variable: IDebugger.IVariable): string | number => {
case 'str':
return value.slice(1, value.length - 1);
default:
return type;
return type ?? value;
}
};

Expand Down
118 changes: 118 additions & 0 deletions src/panels/variables/scope.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { ReactWidget, UseSignal } from '@jupyterlab/apputils';

import { HTMLSelect } from '@jupyterlab/ui-components';

import React, { useState } from 'react';

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

import { VariablesBodyGrid } from './grid';

import { VariablesBodyTree } from './tree';

/**
* A React component to handle scope changes.
*
* @param {object} props The component props.
* @param props.model The variables model.
* @param props.tree The variables tree widget.
* @param props.grid The variables grid widget.
*/
const ScopeSwitcherComponent = ({
model,
tree,
grid
}: {
model: IDebugger.Model.IVariables;
tree: VariablesBodyTree;
grid: VariablesBodyGrid;
}): JSX.Element => {
const [value, setValue] = useState('-');
const scopes = model.scopes;

const onChange = (event: React.ChangeEvent<HTMLSelectElement>): void => {
const value = event.target.value;
setValue(value);
tree.scope = value;
grid.scope = value;
};

return (
<HTMLSelect
className={''}
onChange={onChange}
value={value}
aria-label={'Scope'}
>
{scopes.map(scope => (
<option key={scope.name} value={scope.name}>
{scope.name}
</option>
))}
</HTMLSelect>
);
};

/**
* A widget to switch between scopes.
*/
export class ScopeSwitcher extends ReactWidget {
/**
* Instantiate a new scope switcher.
*
* @param options The instantiation options for a ScopeSwitcher
*/
constructor(options: ScopeSwitcher.IOptions) {
super();
const { model, tree, grid } = options;
this._model = model;
this._tree = tree;
this._grid = grid;
}

/**
* Render the scope switcher.
*/
render(): JSX.Element {
return (
<UseSignal signal={this._model.changed} initialSender={this._model}>
{(): JSX.Element => (
<ScopeSwitcherComponent
model={this._model}
tree={this._tree}
grid={this._grid}
/>
)}
</UseSignal>
);
}

private _model: IDebugger.Model.IVariables;
private _tree: VariablesBodyTree;
private _grid: VariablesBodyGrid;
}

/**
* A namespace for ScopeSwitcher statics
*/
export namespace ScopeSwitcher {
/**
* The ScopeSwitcher instantiation options.
*/
export interface IOptions {
/**
* The variables model.
*/
model: IDebugger.Model.IVariables;

/**
* The variables tree viewer.
*/
tree: VariablesBodyTree;

/**
* The variables table viewer.
*/
grid: VariablesBodyGrid;
}
}
38 changes: 24 additions & 14 deletions src/panels/variables/tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import React, { useEffect, useState } from 'react';

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

import { convertType } from '.';

import { VariablesModel } from './model';

import { convertType } from '.';

/**
* The body for tree of variables.
*/
Expand All @@ -38,17 +38,18 @@ export class VariablesBodyTree extends ReactWidget {
* Render the VariablesBodyTree.
*/
render(): JSX.Element {
return (
<>
{this._scopes.map(scope => (
<VariablesComponent
key={scope.name}
service={this._service}
data={scope.variables}
filter={this._filter}
/>
))}
</>
const scope =
this._scopes.find(scope => scope.name === this._scope) ?? this._scopes[0];

return scope ? (
<VariablesComponent
key={scope.name}
service={this._service}
data={scope.variables}
filter={this._filter}
/>
) : (
<div></div>
);
}

Expand All @@ -60,6 +61,14 @@ export class VariablesBodyTree extends ReactWidget {
this.update();
}

/**
* Set the current scope
*/
set scope(scope: string) {
this._scope = scope;
this.update();
}

/**
* Update the scopes and the tree of variables.
*
Expand All @@ -73,6 +82,7 @@ export class VariablesBodyTree extends ReactWidget {
this.update();
}

private _scope = '';
private _scopes: IDebugger.IScope[] = [];
private _filter = new Set<string>();
private _service: IDebugger;
Expand Down Expand Up @@ -106,7 +116,7 @@ const VariablesComponent = ({
{variables
?.filter(variable => !filter.has(variable.evaluateName))
.map(variable => {
const key = `${variable.evaluateName}-${variable.type}-${variable.value}`;
const key = `${variable.name}-${variable.evaluateName}-${variable.type}-${variable.value}`;
return (
<VariableComponent
key={key}
Expand Down
Loading