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

Commit

Permalink
Handle multiple scopes (backport PR 9346)
Browse files Browse the repository at this point in the history
  • Loading branch information
jtpio committed Dec 10, 2020
1 parent 54b0263 commit 216adf5
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 40 deletions.
1 change: 1 addition & 0 deletions schema/main.json
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
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
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
@@ -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
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

0 comments on commit 216adf5

Please sign in to comment.