Prechádzať zdrojové kódy

Added interface for service, moved session into service

Johan Mabille 5 rokov pred
rodič
commit
f263d64619
8 zmenil súbory, kde vykonal 127 pridanie a 81 odobranie
  1. 3 35
      src/debugger.ts
  2. 7 3
      src/handlers/cell.ts
  3. 6 0
      src/handlers/console.ts
  4. 7 0
      src/handlers/notebook.ts
  5. 21 21
      src/index.ts
  6. 40 17
      src/service.ts
  7. 5 4
      src/session.ts
  8. 38 1
      src/tokens.ts

+ 3 - 35
src/debugger.ts

@@ -5,8 +5,6 @@ import { CodeEditor } from '@jupyterlab/codeeditor';
 
 import { DebugService } from './service';
 
-import { DebugSession } from './session';
-
 import { DebuggerEditors } from './editors';
 
 import { DebuggerSidebar } from './sidebar';
@@ -40,6 +38,8 @@ export class Debugger extends SplitPanel {
     this.sidebar = new DebuggerSidebar(this.model);
     this.model.sidebar = this.sidebar;
 
+    this.service = new DebugService(this.model);
+
     const { editorFactory } = options;
     this.editors = new DebuggerEditors({ editorFactory });
     this.addWidget(this.editors);
@@ -50,6 +50,7 @@ export class Debugger extends SplitPanel {
   readonly editors: DebuggerEditors;
   readonly model: Debugger.Model;
   readonly sidebar: DebuggerSidebar;
+  readonly service: DebugService;
 
   dispose(): void {
     if (this.isDisposed) {
@@ -79,12 +80,6 @@ export namespace Debugger {
   export class Model implements IDisposable {
     constructor(options: Debugger.Model.IOptions) {
       this.connector = options.connector || null;
-      // Avoids setting session with invalid client
-      // session should be set only when a notebook or
-      // a console get the focus.
-      // TODO: also checks that the notebook or console
-      // runs a kernel with debugging ability
-      this.session = null;
       this.id = options.id;
       void this._populate();
     }
@@ -116,30 +111,6 @@ export namespace Debugger {
       return this._modeChanged;
     }
 
-    get session(): IDebugger.ISession {
-      return this._session;
-    }
-
-    set session(session: IDebugger.ISession | null) {
-      if (this._session === session) {
-        return;
-      }
-      if (this._session) {
-        this._session.dispose();
-      }
-      this._session = session;
-      this._service.session = session as DebugSession;
-      this._sessionChanged.emit(undefined);
-    }
-
-    get service(): DebugService {
-      return this._service;
-    }
-
-    get sessionChanged(): ISignal<this, void> {
-      return this._sessionChanged;
-    }
-
     get isDisposed(): boolean {
       return this._isDisposed;
     }
@@ -169,9 +140,6 @@ export namespace Debugger {
     private _isDisposed = false;
     private _mode: IDebugger.Mode;
     private _modeChanged = new Signal<this, IDebugger.Mode>(this);
-    private _session: IDebugger.ISession | null;
-    private _sessionChanged = new Signal<this, void>(this);
-    private _service = new DebugService(null, this);
   }
 
   export namespace Model {

+ 7 - 3
src/handlers/cell.ts

@@ -9,12 +9,14 @@ import { Editor, Doc } from 'codemirror';
 
 import { Breakpoints, SessionTypes } from '../breakpoints';
 import { Debugger } from '../debugger';
+import { IDebugger } from '../tokens';
 import { IDisposable } from '@phosphor/disposable';
 import { Signal } from '@phosphor/signaling';
 
 export class CellManager implements IDisposable {
   constructor(options: CellManager.IOptions) {
     this._debuggerModel = options.debuggerModel;
+    this._debuggerService = options.debuggerService;
     this.breakpointsModel = options.breakpointsModel;
     this.activeCell = options.activeCell;
     this._type = options.type;
@@ -31,6 +33,7 @@ export class CellManager implements IDisposable {
   private _previousCell: CodeCell;
   private previousLineCount: number;
   private _debuggerModel: Debugger.Model;
+  private _debuggerService: IDebugger.IService;
   private _type: SessionTypes;
   private breakpointsModel: Breakpoints.Model;
   private _activeCell: CodeCell;
@@ -81,8 +84,8 @@ export class CellManager implements IDisposable {
       this.activeCell &&
       this.activeCell.isAttached &&
       this.activeCell.editor &&
-      this._debuggerModel &&
-      this._debuggerModel.session
+      this._debuggerService &&
+      this._debuggerService.session
     ) {
       if (this.previousCell && !this.previousCell.isDisposed) {
         this.removeListener(this.previousCell);
@@ -135,7 +138,7 @@ export class CellManager implements IDisposable {
       this.breakpointsModel.removeBreakpoint(info as ILineInfo);
     } else {
       this.breakpointsModel.addBreakpoint(
-        this._debuggerModel.session.client.name,
+        this._debuggerService.session.client.name,
         this.getEditorId(),
         info as ILineInfo
       );
@@ -178,6 +181,7 @@ export class CellManager implements IDisposable {
 export namespace CellManager {
   export interface IOptions {
     debuggerModel: Debugger.Model;
+    debuggerService: IDebugger.IService;
     breakpointsModel: Breakpoints.Model;
     activeCell?: CodeCell;
     type: SessionTypes;

+ 6 - 0
src/handlers/console.ts

@@ -9,6 +9,8 @@ import { CodeCell } from '@jupyterlab/cells';
 
 import { Breakpoints } from '../breakpoints';
 
+import { IDebugger } from '../tokens';
+
 import { Debugger } from '../debugger';
 import { IDisposable } from '@phosphor/disposable';
 import { Signal } from '@phosphor/signaling';
@@ -22,6 +24,7 @@ export class DebuggerConsoleHandler implements IDisposable {
       activeCell: this.consoleTracker.currentWidget.console.promptCell,
       breakpointsModel: this.breakpoints,
       debuggerModel: this.debuggerModel,
+      debuggerService: this.debuggerService,
       type: 'console'
     });
     this.consoleTracker.currentWidget.console.promptCellCreated.connect(
@@ -32,6 +35,7 @@ export class DebuggerConsoleHandler implements IDisposable {
 
   private consoleTracker: IConsoleTracker;
   private debuggerModel: Debugger.Model;
+  private debuggerService: IDebugger.IService;
   private breakpoints: Breakpoints.Model;
   private cellManager: CellManager;
   isDisposed: boolean;
@@ -54,6 +58,7 @@ export class DebuggerConsoleHandler implements IDisposable {
         activeCell: update,
         breakpointsModel: this.breakpoints,
         debuggerModel: this.debuggerModel,
+        debuggerService: this.debuggerService,
         type: 'console'
       });
     }
@@ -63,6 +68,7 @@ export class DebuggerConsoleHandler implements IDisposable {
 export namespace DebuggerConsoleHandler {
   export interface IOptions {
     debuggerModel: Debugger.Model;
+    debuggerService: IDebugger.IService;
     tracker: IConsoleTracker;
   }
 }

+ 7 - 0
src/handlers/notebook.ts

@@ -9,6 +9,8 @@ import { CellManager } from './cell';
 
 import { Debugger } from '../debugger';
 
+import { IDebugger } from '../tokens';
+
 import { Breakpoints } from '../breakpoints';
 
 import { IDisposable } from '@phosphor/disposable';
@@ -18,6 +20,7 @@ import { Signal } from '@phosphor/signaling';
 export class DebuggerNotebookHandler implements IDisposable {
   constructor(options: DebuggerNotebookHandler.IOptions) {
     this.debuggerModel = options.debuggerModel;
+    this.debuggerService = options.debuggerService;
     this.notebookTracker = options.tracker;
     this.breakpoints = this.debuggerModel.sidebar.breakpoints.model;
     this.notebookTracker.activeCellChanged.connect(this.onNewCell, this);
@@ -25,12 +28,14 @@ export class DebuggerNotebookHandler implements IDisposable {
       breakpointsModel: this.breakpoints,
       activeCell: this.notebookTracker.activeCell as CodeCell,
       debuggerModel: this.debuggerModel,
+      debuggerService: this.debuggerService,
       type: 'notebook'
     });
   }
 
   private notebookTracker: INotebookTracker;
   private debuggerModel: Debugger.Model;
+  private debuggerService: IDebugger.IService;
   private breakpoints: Breakpoints.Model;
   private cellManager: CellManager;
   isDisposed: boolean;
@@ -53,6 +58,7 @@ export class DebuggerNotebookHandler implements IDisposable {
         breakpointsModel: this.breakpoints,
         activeCell: codeCell,
         debuggerModel: this.debuggerModel,
+        debuggerService: this.debuggerService,
         type: 'notebook'
       });
     }
@@ -62,6 +68,7 @@ export class DebuggerNotebookHandler implements IDisposable {
 export namespace DebuggerNotebookHandler {
   export interface IOptions {
     debuggerModel: Debugger.Model;
+    debuggerService: IDebugger.IService;
     tracker: INotebookTracker;
   }
 }

+ 21 - 21
src/index.ts

@@ -86,7 +86,8 @@ class HandlerTracker<
     if (debug.tracker.currentWidget && !this.handlers[widget.id]) {
       const handler = new this.builder({
         tracker: tracker,
-        debuggerModel: debug.tracker.currentWidget.content.model
+        debuggerModel: debug.tracker.currentWidget.content.model,
+        debuggerService: debug.tracker.currentWidget.content.service
       });
       this.handlers[widget.id] = handler;
       widget.disposed.connect(() => {
@@ -234,6 +235,12 @@ const main: JupyterFrontEndPlugin<IDebugger> = {
       return tracker.currentWidget ? tracker.currentWidget.content.model : null;
     };
 
+    const getService = () => {
+      return tracker.currentWidget
+        ? tracker.currentWidget.content.service
+        : null;
+    };
+
     commands.addCommand(CommandIDs.mount, {
       execute: args => {
         if (!widget) {
@@ -275,14 +282,11 @@ const main: JupyterFrontEndPlugin<IDebugger> = {
     commands.addCommand(CommandIDs.stop, {
       label: 'Stop',
       isEnabled: () => {
-        const debuggerModel = getModel();
-        return (debuggerModel &&
-          debuggerModel.session !== null &&
-          debuggerModel.session.isStarted) as boolean;
+        const service = getService();
+        return service && service.isStarted();
       },
       execute: async () => {
-        const debuggerModel = getModel();
-        await debuggerModel.session.stop();
+        await getService().session.stop();
         commands.notifyCommandChanged();
       }
     });
@@ -290,14 +294,11 @@ const main: JupyterFrontEndPlugin<IDebugger> = {
     commands.addCommand(CommandIDs.start, {
       label: 'Start',
       isEnabled: () => {
-        const debuggerModel = getModel();
-        return (debuggerModel &&
-          debuggerModel.session !== null &&
-          !debuggerModel.session.isStarted) as boolean;
+        const service = getService();
+        return service && service.canStart();
       },
       execute: async () => {
-        const debuggerModel = getModel();
-        await debuggerModel.session.start();
+        await getService().session.start();
         commands.notifyCommandChanged();
       }
     });
@@ -305,14 +306,13 @@ const main: JupyterFrontEndPlugin<IDebugger> = {
     commands.addCommand(CommandIDs.debugNotebook, {
       label: 'Launch',
       isEnabled: () => {
-        const debuggerModel = getModel();
-        return (debuggerModel &&
-          debuggerModel.session !== null &&
-          debuggerModel.session.isStarted) as boolean;
+        const service = getService();
+        return service && service.isStarted();
       },
       execute: async () => {
-        const debuggerModel = getModel();
-        await debuggerModel.service.launch(debuggerModel.codeValue.text);
+        await tracker.currentWidget.content.service.launch(
+          getModel().codeValue.text
+        );
       }
     });
 
@@ -402,11 +402,11 @@ const main: JupyterFrontEndPlugin<IDebugger> = {
         },
         session: {
           get: (): IDebugger.ISession | null => {
-            return widget ? widget.content.model.session : null;
+            return widget ? widget.content.service.session : null;
           },
           set: (src: IDebugger.ISession | null) => {
             if (widget) {
-              widget.content.model.session = src;
+              widget.content.service.session = src;
             }
           }
         },

+ 40 - 17
src/service.ts

@@ -1,4 +1,4 @@
-import { DebugSession } from './session';
+import { ISignal, Signal } from '@phosphor/signaling';
 
 import { DebugProtocol } from 'vscode-debugprotocol';
 
@@ -10,37 +10,55 @@ import { Variables } from './variables';
 
 import { Callstack } from './callstack';
 
-export class DebugService {
-  constructor(session: DebugSession | null, debuggerModel: Debugger.Model) {
-    this.session = session;
+export class DebugService implements IDebugger.IService {
+  constructor(debuggerModel: Debugger.Model) {
+    // Avoids setting session with invalid client
+    // session should be set only when a notebook or
+    // a console get the focus.
+    // TODO: also checks that the notebook or console
+    // runs a kernel with debugging ability
+    this._session = null;
     this._model = debuggerModel;
   }
 
-  private _session: DebugSession;
-  private _model: Debugger.Model;
-  private frames: Frame[];
-
-  set session(session: DebugSession) {
+  set session(session: IDebugger.ISession) {
+    if (this._session === session) {
+      return;
+    }
+    if (this._session) {
+      this._session.dispose();
+    }
     this._session = session;
+    this._sessionChanged.emit(session);
   }
 
   get session() {
     return this._session;
   }
 
+  canStart(): boolean {
+    return this._session !== null && !this._session.isStarted;
+  }
+
+  isStarted(): boolean {
+    return this._session !== null && this._session.isStarted;
+  }
+
+  get sessionChanged(): ISignal<IDebugger.IService, IDebugger.ISession> {
+    return this._sessionChanged;
+  }
+
   // this will change for after execute cell
   async launch(code: string): Promise<void> {
     let threadId: number = 1;
     this.frames = [];
-    this.session.eventMessage.connect(
-      (sender: DebugSession, event: IDebugger.ISession.Event) => {
-        const eventName = event.event;
-        if (eventName === 'thread') {
-          const msg = event as DebugProtocol.ThreadEvent;
-          threadId = msg.body.threadId;
-        }
+    this.session.eventMessage.connect((_, event: IDebugger.ISession.Event) => {
+      const eventName = event.event;
+      if (eventName === 'thread') {
+        const msg = event as DebugProtocol.ThreadEvent;
+        threadId = msg.body.threadId;
       }
-    );
+    });
 
     const breakpoints: DebugProtocol.SourceBreakpoint[] = this.setBreakpoints();
     const reply = await this.session.sendRequest('dumpCell', {
@@ -139,6 +157,11 @@ export class DebugService {
       };
     });
   };
+
+  private _session: IDebugger.ISession;
+  private _sessionChanged = new Signal<this, IDebugger.ISession>(this);
+  private _model: Debugger.Model;
+  private frames: Frame[];
 }
 
 export type Frame = {

+ 5 - 4
src/session.ts

@@ -169,7 +169,7 @@ export class DebugSession implements IDebugger.ISession {
   /**
    * Signal emitted for debug event messages.
    */
-  get eventMessage(): ISignal<DebugSession, IDebugger.ISession.Event> {
+  get eventMessage(): ISignal<IDebugger.ISession, IDebugger.ISession.Event> {
     return this._eventMessage;
   }
 
@@ -213,9 +213,10 @@ export class DebugSession implements IDebugger.ISession {
   private _disposed = new Signal<this, void>(this);
   private _isDisposed: boolean = false;
   private _isStarted: boolean = false;
-  private _eventMessage = new Signal<DebugSession, IDebugger.ISession.Event>(
-    this
-  );
+  private _eventMessage = new Signal<
+    IDebugger.ISession,
+    IDebugger.ISession.Event
+  >(this);
   private _seq: number = 0;
 }
 

+ 38 - 1
src/tokens.ts

@@ -9,14 +9,17 @@ import {
 
 import { CodeEditor } from '@jupyterlab/codeeditor';
 
+import { Session } from '@jupyterlab/services';
+
 import { Token } from '@phosphor/coreutils';
 
 import { IObservableDisposable } from '@phosphor/disposable';
 
+import { ISignal } from '@phosphor/signaling';
+
 import { DebugProtocol } from 'vscode-debugprotocol';
 
 import { Debugger } from './debugger';
-import { Session } from '@jupyterlab/services';
 
 /**
  * An interface describing an application's visual debugger.
@@ -84,6 +87,40 @@ export namespace IDebugger {
      * Restore the state of a debug session.
      */
     restoreState(): Promise<void>;
+
+    /**
+     * Send a debug request to the kernel.
+     */
+    sendRequest<K extends keyof IDebugger.ISession.Request>(
+      command: K,
+      args: IDebugger.ISession.Request[K]
+    ): Promise<IDebugger.ISession.Response[K]>;
+
+    eventMessage: ISignal<IDebugger.ISession, IDebugger.ISession.Event>;
+  }
+
+  export interface IService {
+    /**
+     * The API debugger session to connect to a debugger
+     */
+    session: IDebugger.ISession;
+
+    /**
+     * Whether the debugger can start.
+     */
+    canStart(): boolean;
+
+    /**
+     * Whether the current debugger is started.
+     */
+    isStarted(): boolean;
+
+    /**
+     * For testing purpose only, to be removed.
+     */
+    launch(code: string): Promise<void>;
+
+    sessionChanged: ISignal<IDebugger.IService, IDebugger.ISession>;
   }
 
   export namespace ISession {