import { IThemeManager } from '@jupyterlab/apputils' ; import { CommandRegistry } from '@lumino/commands' ; import { BasicKeyHandler , BasicMouseHandler , BasicSelectionModel , DataGrid , DataModel , TextRenderer } from '@lumino/datagrid' ; import { ISignal , Signal } from '@lumino/signaling' ; import { Panel } from '@lumino/widgets' ; import { CommandIDs } from '../../' ; import { IDebugger } from '../../tokens' ; import { VariablesModel } from './model' ; /**
 * A Panel to show variables in a datagrid.
 */ export class VariablesBodyGrid extends Panel { param options constructor ( options ) { super ( ) ; 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 ) : void => { this . _update ( ) ; } , this ) ; this . _grid . dataModel . setData ( scopes ?? [ ] ) ; this . addWidget ( this . _grid ) ; this . addClass ( 'jp-DebuggerVariables-body' ) ; } param filter set filter ( filter ) { ( this . _grid . dataModel as GridModel ) . filter = filter ; this . _update ( ) ; } param scope set scope ( scope ) { ( this . _grid . dataModel as GridModel ) . scope = scope ; this . _update ( ) ; } /**
     * Update the underlying data model
     */ private _update ( ) { this . _grid . dataModel . setData ( this . _model . scopes ?? [ ] ) ; } private _grid : Grid ; private _model : IDebugger . Model . IVariables ; } /**
 * A namespace for VariableBodyGrid `statics`.
 */ export namespace VariablesBodyGrid { /**
     * Instantiation options for `VariablesBodyGrid`.
     */ export interface IOptions { /**
         * The variables model.
         */ model : IDebugger . Model . IVariables ; /**
         * The commands registry.
         */ commands : CommandRegistry ; /**
         * The optional initial scopes data.
         */ scopes ? : IDebugger . IScope [ ] ; /**
         * An optional application theme manager to detect theme changes.
         */ themeManager ? : IThemeManager | null ; } } /**
 * A class wrapping the underlying variables datagrid.
 */ class Grid extends Panel { param options constructor ( options ) { super ( ) ; const { commands , themeManager } = options ; const dataModel = new GridModel ( ) ; const grid = new DataGrid ( ) ; const mouseHandler = new Private . MouseHandler ( ) ; mouseHandler . doubleClicked . connect ( ( _ , hit ) => commands . execute ( CommandIDs . inspectVariable , { variableReference : dataModel . getVariableReference ( hit . row ) , title : dataModel . getVariableName ( hit . 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 ; if ( themeManager ) { themeManager . themeChanged . connect ( this . _updateStyles , this ) ; } this . addWidget ( grid ) ; } param filter set filter ( filter ) { ( this . _grid . dataModel as GridModel ) . filter = filter ; this . update ( ) ; } param scope set scope ( scope ) { ( this . _grid . dataModel as GridModel ) . scope = scope ; this . update ( ) ; } /**
     * Get the data model for the data grid.
     */ get dataModel ( ) : GridModel { return this . _grid . dataModel as GridModel ; } param message protected onAfterAttach ( message ) { super . onAfterAttach ( message ) ; this . _updateStyles ( ) ; } /**
     * Update the computed style for the data grid on theme change.
     */ private _updateStyles ( ) { const { style , textRenderer } = Private . computeStyle ( ) ; this . _grid . cellRenderers . update ( { } , textRenderer ) ; this . _grid . style = style ; } private _grid : DataGrid ; } /**
 * A namespace for VariablesGrid `statics`.
 */ namespace Grid { /**
     * Instantiation options for `VariablesGrid`.
     */ export interface IOptions { /**
         * The commands registry.
         */ commands : CommandRegistry ; /**
         * An optional application theme manager to detect theme changes.
         */ themeManager ? : IThemeManager | null ; } } /**
 * A data grid model for variables.
 */ class GridModel extends DataModel { /**
     * Set the variable filter list.
     */ set filter ( filter ) { this . _filter = filter ; } /**
     * Get the current scope for the variables.
     */ get scope ( ) : string { return this . _scope ; } /**
     * Set the variable scope
     */ set scope ( scope ) { this . _scope = scope ; } param region rowCount ( region ) { return region === 'body' ? this . _data . name . length : 1 ; } param region columnCount ( region ) { return region === 'body' ? 2 : 1 ; } param region param row param column data ( region , row , column ) { if ( region === 'row-header' ) { return this . _data . name [ row ] ; } if ( region === 'column-header' ) { return column === 1 ? 'Value' : 'Type' ; } if ( region === 'corner-header' ) { return 'Name' ; } return column === 1 ? this . _data . value [ row ] : this . _data . type [ row ] ; } param row getVariableReference ( row ) { return this . _data . variablesReference [ row ] ; } param row getVariableName ( row ) { return this . _data . name [ row ] ; } param scopes setData ( scopes ) { this . _clearData ( ) ; this . emitChanged ( { type : 'model-reset' , region : 'body' } ) ; 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 } ) ; } /**
     * Clear all the data in the datagrid.
     */ private _clearData ( ) { this . _data = { name : [ ] , type : [ ] , value : [ ] , variablesReference : [ ] } ; } private _filter = new Set < string > ( ) ; private _scope = '' ; private _data : { name : string [ ] ; type : string [ ] ; value : string [ ] ; variablesReference : number [ ] ; } = { name : [ ] , type : [ ] , value : [ ] , variablesReference : [ ] } ; } /**
 * A namespace for private data.
 */ namespace 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.
     */ export 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 ) : string => i % 2 === 0 ? voidColor : backgroundColor , selectionFillColor } , textRenderer : new TextRenderer ( { font : '12px sans-serif' , textColor , backgroundColor : '' , verticalAlignment : 'center' , horizontalAlignment : 'left' } ) } ; } /**
     * A custom click handler to handle clicks on the variables grid.
     */ export class MouseHandler extends BasicMouseHandler { /**
         * A signal emitted when the variables grid is double clicked.
         */ get doubleClicked ( ) : ISignal < this , DataGrid . HitTestResult > { return this . _doubleClicked ; } param grid param event onMouseDoubleClick ( grid , event ) { const hit = grid . hitTest ( event . clientX , event . clientY ) ; this . _doubleClicked . emit ( hit ) ; } private _doubleClicked = new Signal < this , DataGrid . HitTestResult > ( this ) ; } }