@jupyterlab/debugger
Version:
JupyterLab - Debugger Extension
361 lines • 11.7 kB
JavaScript
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
import { BasicKeyHandler, BasicMouseHandler, BasicSelectionModel, DataGrid, DataModel, TextRenderer } from '@lumino/datagrid';
import { Signal } from '@lumino/signaling';
import { Panel } from '@lumino/widgets';
import { nullTranslator } from '@jupyterlab/translation';
import { Debugger } from '../../';
/**
* A class wrapping the underlying variables datagrid.
*/
export class Grid extends Panel {
/**
* Instantiate a new VariablesGrid.
*
* @param options The instantiation options for a VariablesGrid.
*/
constructor(options) {
super();
const { commands, model, themeManager } = options;
this.model = model;
const dataModel = new GridModel(options.translator);
const grid = new DataGrid();
const mouseHandler = new Private.MouseHandler();
mouseHandler.doubleClicked.connect((_, hit) => commands.execute(Debugger.CommandIDs.inspectVariable, {
variableReference: dataModel.getVariableReference(hit.row),
name: dataModel.getVariableName(hit.row)
}));
mouseHandler.selected.connect((_, hit) => {
const { row } = hit;
this.model.selectedVariable = {
name: dataModel.getVariableName(row),
value: dataModel.data('body', row, 1),
type: dataModel.data('body', row, 2),
variablesReference: dataModel.getVariableReference(row)
};
});
grid.dataModel = dataModel;
grid.keyHandler = new BasicKeyHandler();
grid.mouseHandler = mouseHandler;
grid.selectionModel = new BasicSelectionModel({
dataModel
});
grid.stretchLastColumn = true;
grid.node.style.height = '100%';
this._grid = grid;
// Compute the grid's styles based on the current theme.
if (themeManager) {
themeManager.themeChanged.connect(this._updateStyles, this);
}
this.addWidget(grid);
}
/**
* Set the variable filter list.
*
* @param filter The variable filter to apply.
*/
set filter(filter) {
this._grid.dataModel.filter = filter;
this.update();
}
/**
* Set the scope for the variables data model.
*
* @param scope The scopes for the variables
*/
set scope(scope) {
this._grid.dataModel.scope = scope;
this.update();
}
/**
* Get the data model for the data grid.
*/
get dataModel() {
return this._grid.dataModel;
}
/**
* Handle `after-attach` messages.
*
* @param message - The `after-attach` message.
*/
onAfterAttach(message) {
super.onAfterAttach(message);
this._updateStyles();
}
/**
* Update the computed style for the data grid on theme change.
*/
_updateStyles() {
const { style, textRenderer } = Private.computeStyle();
this._grid.cellRenderers.update({}, textRenderer);
this._grid.style = style;
}
}
/**
* A data grid model for variables.
*/
export class GridModel extends DataModel {
/**
* Create grid model
* @param translator optional translator
*/
constructor(translator) {
super();
this._filter = new Set();
this._scope = '';
this._data = {
name: [],
type: [],
value: [],
variablesReference: []
};
this._trans = (translator || nullTranslator).load('jupyterlab');
}
/**
* The variable filter list.
*/
get filter() {
return this._filter;
}
set filter(filter) {
this._filter = filter;
}
/**
* The current scope for the variables.
*/
get scope() {
return this._scope;
}
set scope(scope) {
this._scope = scope;
}
/**
* Get the row count for a particular region in the data grid.
*
* @param region The datagrid region.
*/
rowCount(region) {
return region === 'body' ? this._data.name.length : 1;
}
/**
* Get the column count for a particular region in the data grid.
*
* @param region The datagrid region.
*/
columnCount(region) {
return region === 'body' ? 2 : 1;
}
/**
* Get the data count for a particular region, row and column in the data grid.
*
* @param region The datagrid region.
* @param row The datagrid row
* @param column The datagrid column
*/
data(region, row, column) {
if (region === 'row-header') {
return this._data.name[row];
}
if (region === 'column-header') {
return column === 1 ? this._trans.__('Value') : this._trans.__('Type');
}
if (region === 'corner-header') {
return this._trans.__('Name');
}
return column === 1 ? this._data.value[row] : this._data.type[row];
}
/**
* Get the variable reference for a given row
*
* @param row The row in the datagrid.
*/
getVariableReference(row) {
return this._data.variablesReference[row];
}
/**
* Get the variable name for a given row
*
* @param row The row in the datagrid.
*/
getVariableName(row) {
return this._data.name[row];
}
/**
* Set the datagrid model data from the list of variables.
*
* @param scopes The list of variables.
*/
setData(scopes) {
var _a, _b;
this._clearData();
this.emitChanged({
type: 'model-reset'
});
const scope = (_a = scopes.find(scope => scope.name === this._scope)) !== null && _a !== void 0 ? _a : scopes[0];
const variables = (_b = scope === null || scope === void 0 ? void 0 : scope.variables) !== null && _b !== void 0 ? _b : [];
const filtered = variables.filter(variable => variable.name && !this._filter.has(variable.name));
filtered.forEach((variable, index) => {
var _a;
this._data.name[index] = variable.name;
this._data.type[index] = (_a = variable.type) !== null && _a !== void 0 ? _a : '';
this._data.value[index] = variable.value;
this._data.variablesReference[index] = variable.variablesReference;
});
this.emitChanged({
type: 'rows-inserted',
region: 'body',
index: 1,
span: filtered.length
});
}
/**
* Clear all the data in the datagrid.
*/
_clearData() {
this._data = {
name: [],
type: [],
value: [],
variablesReference: []
};
}
}
/**
* A namespace for private data.
*/
var Private;
(function (Private) {
/**
* Create a color palette element.
*/
function createPalette() {
const div = document.createElement('div');
div.className = 'jp-DebuggerVariables-colorPalette';
div.innerHTML = `
<div class="jp-mod-void"></div>
<div class="jp-mod-background"></div>
<div class="jp-mod-header-background"></div>
<div class="jp-mod-grid-line"></div>
<div class="jp-mod-header-grid-line"></div>
<div class="jp-mod-selection"></div>
<div class="jp-mod-text"></div>
`;
return div;
}
/**
* Compute the style and renderer for a data grid.
*/
function computeStyle() {
const palette = createPalette();
document.body.appendChild(palette);
let node;
node = palette.querySelector('.jp-mod-void');
const voidColor = getComputedStyle(node).color;
node = palette.querySelector('.jp-mod-background');
const backgroundColor = getComputedStyle(node).color;
node = palette.querySelector('.jp-mod-header-background');
const headerBackgroundColor = getComputedStyle(node).color;
node = palette.querySelector('.jp-mod-grid-line');
const gridLineColor = getComputedStyle(node).color;
node = palette.querySelector('.jp-mod-header-grid-line');
const headerGridLineColor = getComputedStyle(node).color;
node = palette.querySelector('.jp-mod-selection');
const selectionFillColor = getComputedStyle(node).color;
node = palette.querySelector('.jp-mod-text');
const textColor = getComputedStyle(node).color;
document.body.removeChild(palette);
return {
style: {
voidColor,
backgroundColor,
headerBackgroundColor,
gridLineColor,
headerGridLineColor,
rowBackgroundColor: (i) => i % 2 === 0 ? voidColor : backgroundColor,
selectionFillColor
},
textRenderer: new TextRenderer({
font: '12px sans-serif',
textColor,
backgroundColor: '',
verticalAlignment: 'center',
horizontalAlignment: 'left'
})
};
}
Private.computeStyle = computeStyle;
/**
* A custom click handler to handle clicks on the variables grid.
*/
class MouseHandler extends BasicMouseHandler {
constructor() {
super(...arguments);
this._doubleClicked = new Signal(this);
this._selected = new Signal(this);
}
/**
* A signal emitted when the variables grid is double clicked.
*/
get doubleClicked() {
return this._doubleClicked;
}
/**
* A signal emitted when the variables grid received mouse down or context menu event.
*/
get selected() {
return this._selected;
}
/**
* Dispose of the resources held by the mouse handler.
*/
dispose() {
if (this.isDisposed) {
return;
}
Signal.disconnectSender(this);
super.dispose();
}
/**
* Handle a mouse double-click event.
*
* @param grid The datagrid clicked.
* @param event The mouse event.
*/
onMouseDoubleClick(grid, event) {
const hit = grid.hitTest(event.clientX, event.clientY);
this._doubleClicked.emit(hit);
}
/**
* Handle the mouse down event for the data grid.
*
* @param grid - The data grid of interest.
*
* @param event - The mouse down event of interest.
*/
onMouseDown(grid, event) {
// Unpack the event.
let { clientX, clientY } = event;
// Hit test the grid.
let hit = grid.hitTest(clientX, clientY);
this._selected.emit(hit);
// Propagate event to Lumino DataGrid BasicMouseHandler.
super.onMouseDown(grid, event);
}
/**
* Handle the context menu event for the data grid.
*
* @param grid - The data grid of interest.
*
* @param event - The context menu event of interest.
*/
onContextMenu(grid, event) {
// Unpack the event.
let { clientX, clientY } = event;
// Hit test the grid.
let hit = grid.hitTest(clientX, clientY);
this._selected.emit(hit);
}
}
Private.MouseHandler = MouseHandler;
})(Private || (Private = {}));
//# sourceMappingURL=gridpanel.js.map