import { ILabShell , ILayoutRestorer , JupyterFrontEnd , JupyterFrontEndPlugin } from '@jupyterlab/application' ; import { ICommandPalette , IThemeManager , MainAreaWidget , WidgetTracker } from '@jupyterlab/apputils' ; import { IEditorServices } from '@jupyterlab/codeeditor' ; import { ConsolePanel , IConsoleTracker } from '@jupyterlab/console' ; import { PageConfig , PathExt } from '@jupyterlab/coreutils' ; import { DocumentWidget } from '@jupyterlab/docregistry' ; import { FileEditor , IEditorTracker } from '@jupyterlab/fileeditor' ; import { INotebookTracker , NotebookPanel } from '@jupyterlab/notebook' ; import { Session } from '@jupyterlab/services' ; import { ISettingRegistry } from '@jupyterlab/settingregistry' ; import { continueIcon , stepIntoIcon , stepOutIcon , stepOverIcon , terminateIcon , variableIcon } from './icons' ; import { Debugger } from './debugger' ; import { DebuggerHandler } from './handler' ; import { EditorHandler } from './handlers/editor' ; import { IDebugger , IDebuggerConfig , IDebuggerSources , IDebuggerSidebar } from './tokens' ; import { ReadOnlyEditorFactory } from './panels/sources/factory' ; import { VariablesBodyGrid } from './panels/variables/grid' ; export { IDebugger , IDebuggerSidebar } from './tokens' ; /**
 * The command IDs used by the debugger plugin.
 */ export namespace CommandIDs { export const debugContinue = 'debugger:continue' ; export const terminate = 'debugger:terminate' ; export const next = 'debugger:next' ; export const stepIn = 'debugger:stepIn' ; export const stepOut = 'debugger:stepOut' ; export const inspectVariable = 'debugger:inspect-variable' ; } /**
 * A plugin that provides visual debugging support for consoles.
 */ const consoles = { id : '@jupyterlab/debugger:consoles' , autoStart : true , requires : [ IDebugger , IConsoleTracker ] , optional : [ ILabShell ] , activate : ( app , debug , consoleTracker , labShell ) => { const handler = new DebuggerHandler ( { type : 'console' , shell : app . shell , service : debug } ) ; const updateHandlerAndCommands = async ( widget ) : Promise < void > => { const { sessionContext } = widget ; await sessionContext . ready ; await handler . updateContext ( widget , sessionContext ) ; app . commands . notifyCommandChanged ( ) ; } ; if ( labShell ) { labShell . currentChanged . connect ( async ( _ , update ) => { const widget = update . newValue ; if ( ! ( widget instanceof ConsolePanel ) ) { return ; } await updateHandlerAndCommands ( widget ) ; } ) ; return ; } consoleTracker . currentChanged . connect ( async ( _ , consolePanel ) => { await updateHandlerAndCommands ( consolePanel ) ; } ) ; } } ; /**
 * A plugin that provides visual debugging support for file editors.
 */ const files = { id : '@jupyterlab/debugger:files' , autoStart : true , requires : [ IDebugger , IEditorTracker ] , optional : [ ILabShell ] , activate : ( app , debug , editorTracker , labShell ) => { const handler = new DebuggerHandler ( { type : 'file' , shell : app . shell , service : debug } ) ; const activeSessions = { } ; const updateHandlerAndCommands = async ( widget ) : Promise < void > => { const sessions = app . serviceManager . sessions ; try { const model = await sessions . findByPath ( widget . context . path ) ; let session = activeSessions [ model . id ] ; if ( ! session ) { session = sessions . connectTo ( { model } ) ; activeSessions [ model . id ] = session ; } await handler . update ( widget , session ) ; app . commands . notifyCommandChanged ( ) ; } catch { return ; } } ; if ( labShell ) { labShell . currentChanged . connect ( async ( _ , update ) => { const widget = update . newValue ; if ( ! ( widget instanceof DocumentWidget ) ) { return ; } const content = widget . content ; if ( ! ( content instanceof FileEditor ) ) { return ; } await updateHandlerAndCommands ( widget ) ; } ) ; } editorTracker . currentChanged . connect ( async ( _ , documentWidget ) => { await updateHandlerAndCommands ( ( documentWidget as unknown ) as DocumentWidget ) ; } ) ; } } ; /**
 * A plugin that provides visual debugging support for notebooks.
 */ const notebooks = { id : '@jupyterlab/debugger:notebooks' , autoStart : true , requires : [ IDebugger , INotebookTracker ] , optional : [ ILabShell ] , activate : ( app , service , notebookTracker , labShell ) => { const handler = new DebuggerHandler ( { type : 'notebook' , shell : app . shell , service } ) ; const updateHandlerAndCommands = async ( widget ) : Promise < void > => { const { sessionContext } = widget ; await sessionContext . ready ; await handler . updateContext ( widget , sessionContext ) ; app . commands . notifyCommandChanged ( ) ; } ; if ( labShell ) { labShell . currentChanged . connect ( async ( _ , update ) => { const widget = update . newValue ; if ( ! ( widget instanceof NotebookPanel ) ) { return ; } await updateHandlerAndCommands ( widget ) ; } ) ; return ; } notebookTracker . currentChanged . connect ( async ( _ , notebookPanel ) => { await updateHandlerAndCommands ( notebookPanel ) ; } ) ; } } ; /**
 * A plugin that provides a debugger service.
 */ const service = { id : '@jupyterlab/debugger:service' , autoStart : true , provides : IDebugger , requires : [ IDebuggerConfig ] , optional : [ IDebuggerSources ] , activate : ( app , config , debuggerSources ) => new Debugger . Service ( { config , debuggerSources , specsManager : app . serviceManager . kernelspecs } ) } ; /**
 * A plugin that provides a configuration with hash method.
 */ const configuration = { id : '@jupyterlab/debugger:config' , provides : IDebuggerConfig , autoStart : true , activate : ( ) => new Debugger . Config ( ) } ; /**
 * A plugin that provides source/editor functionality for debugging.
 */ const sources = { id : '@jupyterlab/debugger:sources' , autoStart : true , provides : IDebuggerSources , requires : [ IDebuggerConfig , IEditorServices ] , optional : [ INotebookTracker , IConsoleTracker , IEditorTracker ] , activate : ( app , config , editorServices , notebookTracker , consoleTracker , editorTracker ) : IDebugger . ISources => { return new Debugger . Sources ( { config , shell : app . shell , editorServices , notebookTracker , consoleTracker , editorTracker } ) ; } } ; const variables = { id : '@jupyterlab/debugger:variables' , autoStart : true , requires : [ IDebugger ] , optional : [ IThemeManager ] , activate : ( app , service , themeManager ) => { const { commands , shell } = app ; const tracker = new WidgetTracker < MainAreaWidget < VariablesBodyGrid > > ( { namespace : 'debugger/inspect-variable' } ) ; commands . addCommand ( CommandIDs . inspectVariable , { label : 'Inspect Variable' , caption : 'Inspect Variable' , execute : async ( args ) => { const { variableReference } = args ; if ( ! variableReference || variableReference === 0 ) { return ; } const variables = await service . inspectVariable ( variableReference as number ) ; const title = args . title as string ; const id = `jp-debugger-variable-${ title }` ; if ( ! variables || variables . length === 0 || tracker . find ( widget => widget . id === id ) ) { return ; } const model = service . model . variables ; const widget = new MainAreaWidget < VariablesBodyGrid > ( { content : new VariablesBodyGrid ( { model , commands , scopes : [ { name : title , variables } ] , themeManager } ) } ) ; widget . addClass ( 'jp-DebuggerVariables' ) ; widget . id = id ; widget . title . icon = variableIcon ; widget . title . label = `${ service . session ?. connection ?. name } - ${ title }` ; void tracker . add ( widget ) ; model . changed . connect ( ( ) => widget . dispose ( ) ) ; shell . add ( widget , 'main' , { mode : tracker . currentWidget ? 'split-right' : 'split-bottom' } ) ; } } ) ; } } ; /**
 * Debugger sidebar provider plugin.
 */ const sidebar = { id : '@jupyterlab/debugger-extension:sidebar' , provides : IDebuggerSidebar , requires : [ IDebugger , IEditorServices ] , optional : [ IThemeManager , ISettingRegistry ] , autoStart : true , activate : async ( app , service , editorServices , themeManager , settingRegistry ) : Promise < IDebugger . ISidebar > => { const { commands } = app ; const callstackCommands = { registry : commands , continue : CommandIDs . debugContinue , terminate : CommandIDs . terminate , next : CommandIDs . next , stepIn : CommandIDs . stepIn , stepOut : CommandIDs . stepOut } ; const sidebar = new Debugger . Sidebar ( { service , callstackCommands , editorServices , themeManager } ) ; if ( settingRegistry ) { const setting = await settingRegistry . load ( main . id ) ; const updateSettings = ( ) : void => { const filters = setting . get ( 'variableFilters' ) . composite as { [ key ] : string [ ] ; } ; const kernel = service . session ?. connection ?. kernel ?. name ?? '' ; if ( kernel && filters [ kernel ] ) { sidebar . variables . filter = new Set < string > ( filters [ kernel ] ) ; } } ; updateSettings ( ) ; setting . changed . connect ( updateSettings ) ; service . sessionChanged . connect ( updateSettings ) ; } return sidebar ; } } ; /**
 * The main debugger UI plugin.
 */ const main = { id : '@jupyterlab/debugger:main' , requires : [ IDebugger , IEditorServices , IDebuggerSidebar ] , optional : [ ILabShell , ILayoutRestorer , ICommandPalette , IDebuggerSources ] , autoStart : true , activate : async ( app , service , editorServices , sidebar , labShell , restorer , palette , debuggerSources ) : Promise < void > => { const { commands , shell , serviceManager } = app ; const { kernelspecs } = serviceManager ; const alwaysShowDebuggerExtension = PageConfig . getOption ( 'alwaysShowDebuggerExtension' ) . toLowerCase ( ) === 'true' ; if ( ! alwaysShowDebuggerExtension ) { await kernelspecs . ready ; const specs = kernelspecs . specs . kernelspecs ; const enabled = Object . keys ( specs ) . some ( name => ! ! ( specs [ name ] . metadata ?. [ 'debugger' ] ?? false ) ) ; if ( ! enabled ) { return ; } } commands . addCommand ( CommandIDs . debugContinue , { label : 'Continue' , caption : 'Continue' , icon : continueIcon , isEnabled : ( ) => { return service . hasStoppedThreads ( ) ; } , execute : async ( ) => { await service . continue ( ) ; commands . notifyCommandChanged ( ) ; } } ) ; commands . addCommand ( CommandIDs . terminate , { label : 'Terminate' , caption : 'Terminate' , icon : terminateIcon , isEnabled : ( ) => { return service . hasStoppedThreads ( ) ; } , execute : async ( ) => { await service . restart ( ) ; commands . notifyCommandChanged ( ) ; } } ) ; commands . addCommand ( CommandIDs . next , { label : 'Next' , caption : 'Next' , icon : stepOverIcon , isEnabled : ( ) => { return service . hasStoppedThreads ( ) ; } , execute : async ( ) => { await service . next ( ) ; } } ) ; commands . addCommand ( CommandIDs . stepIn , { label : 'StepIn' , caption : 'Step In' , icon : stepIntoIcon , isEnabled : ( ) => { return service . hasStoppedThreads ( ) ; } , execute : async ( ) => { await service . stepIn ( ) ; } } ) ; commands . addCommand ( CommandIDs . stepOut , { label : 'StepOut' , caption : 'Step Out' , icon : stepOutIcon , isEnabled : ( ) => { return service . hasStoppedThreads ( ) ; } , execute : async ( ) => { await service . stepOut ( ) ; } } ) ; service . eventMessage . connect ( ( _ , event ) : void => { commands . notifyCommandChanged ( ) ; if ( labShell && event . event === 'initialized' ) { labShell . expandRight ( ) ; } } ) ; service . sessionChanged . connect ( _ => { commands . notifyCommandChanged ( ) ; } ) ; if ( restorer ) { restorer . add ( sidebar , 'debugger-sidebar' ) ; } shell . add ( sidebar , 'right' ) ; if ( palette ) { const category = 'Debugger' ; [ CommandIDs . debugContinue , CommandIDs . terminate , CommandIDs . next , CommandIDs . stepIn , CommandIDs . stepOut ] . forEach ( command => { palette . addItem ( { command , category } ) ; } ) ; } if ( debuggerSources ) { const { model } = service ; const readOnlyEditorFactory = new ReadOnlyEditorFactory ( { editorServices } ) ; const onCurrentFrameChanged = ( _ , frame ) : void => { debuggerSources . find ( { focus : true , kernel : service . session ?. connection ?. kernel ?. name , path : service . session ?. connection ?. path , source : frame ?. source . path ?? null } ) . forEach ( editor => { requestAnimationFrame ( ( ) => { EditorHandler . showCurrentLine ( editor , frame . line ) ; } ) ; } ) ; } ; const onCurrentSourceOpened = ( _ , source ) : void => { if ( ! source ) { return ; } const { content , mimeType , path } = source ; const results = debuggerSources . find ( { focus : true , kernel : service . session ?. connection ?. kernel . name , path : service . session ?. connection ?. path , source : path } ) ; if ( results . length > 0 ) { return ; } const editorWrapper = readOnlyEditorFactory . createNewEditor ( { content , mimeType , path } ) ; const editor = editorWrapper . editor ; const editorHandler = new EditorHandler ( { debuggerService : service , editor , path } ) ; editorWrapper . disposed . connect ( ( ) => editorHandler . dispose ( ) ) ; debuggerSources . open ( { label : PathExt . basename ( path ) , caption : path , editorWrapper } ) ; const frame = service . model . callstack . frame ; if ( frame ) { EditorHandler . showCurrentLine ( editor , frame . line ) ; } } ; model . callstack . currentFrameChanged . connect ( onCurrentFrameChanged ) ; model . sources . currentSourceOpened . connect ( onCurrentSourceOpened ) ; model . breakpoints . clicked . connect ( async ( _ , breakpoint ) => { const path = breakpoint . source . path ; const source = await service . getSource ( { sourceReference : 0 , path } ) ; onCurrentSourceOpened ( null , source ) ; } ) ; } } } ; /**
 * Export the plugins as default.
 */ const plugins = [ service , consoles , files , notebooks , variables , sidebar , main , sources , configuration ] ; export default plugins ;