Explorar o código

work in progress

Afshin Darian %!s(int64=8) %!d(string=hai) anos
pai
achega
49649a7583
Modificáronse 3 ficheiros con 237 adicións e 30 borrados
  1. 202 0
      src/tooltip/model.ts
  2. 27 5
      src/tooltip/plugin.ts
  3. 8 25
      src/tooltip/widget.ts

+ 202 - 0
src/tooltip/model.ts

@@ -0,0 +1,202 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import {
+  Kernel, KernelMessage
+} from '@jupyterlab/services';
+
+import {
+  IDisposable
+} from 'phosphor/lib/core/disposable';
+
+import {
+  clearSignalData, defineSignal, ISignal
+} from 'phosphor/lib/core/signaling';
+
+import {
+  Widget
+} from 'phosphor/lib/ui/widget';
+
+import {
+  CodeEditor
+} from '../codeeditor';
+
+import {
+  IRenderMime, RenderMime
+} from '../rendermime';
+
+
+/**
+ * The data model for a tooltip widget.
+ */
+export
+class TooltipModel implements IDisposable {
+  /**
+   * Construct a new tooltip model.
+   */
+  constructor(options: TooltipModel.IOptions) {
+    this.editor = options.editor;
+    this.kernel = options.kernel;
+    this.rendermime = options.rendermime;
+  }
+
+  /**
+   * A signal emitted when the model content is changed.
+   */
+  readonly contentChanged: ISignal<this, void>;
+
+  /**
+   * A signal emitted when the model is disposed.
+   */
+  readonly disposed: ISignal<this, void>;
+
+  /**
+   * The editor referent of the tooltip model.
+   */
+  readonly editor: CodeEditor.IEditor;
+
+  /**
+   * The kernel for the tooltip model.
+   */
+  readonly kernel: Kernel.IKernel;
+
+  /**
+   * The rendermime instance used by the tooltip model.
+   */
+  readonly rendermime: IRenderMime;
+
+  /**
+   * The tooltip model's content.
+   */
+  get content(): Widget {
+    return this._content;
+  }
+
+  /**
+   * The detail level of API requests.
+   *
+   * #### Notes
+   * The only acceptable values are 0 and 1.
+   * @see http://jupyter-client.readthedocs.io/en/latest/messaging.html#introspection
+   */
+  get detailLevel(): 0 | 1 {
+    return this._detailLevel;
+  }
+  set detailLevel(level: 0 | 1) {
+    if (this._detailLevel !== level) {
+      this._detailLevel = level;
+      this.fetch();
+    }
+  }
+
+  /**
+   * Get whether the tooltip model is disposed.
+   *
+   * #### Notes
+   * This is a read-only property.
+   */
+  get isDisposed(): boolean {
+    return this._isDisposed;
+  }
+
+  /**
+   * Dispose of the resources used by the model.
+   */
+  dispose(): void {
+    if (this._isDisposed) {
+      return;
+    }
+    this._isDisposed = true;
+    this.disposed.emit(void 0);
+    clearSignalData(this);
+  }
+
+  /**
+   * Fetch a tooltip's content from the API server.
+   */
+  fetch(): void {
+    let editor = this.editor;
+    let kernel = this.kernel;
+    let code = editor.model.value.text;
+    let position = editor.getCursorPosition();
+    let offset = editor.getOffsetAt(position);
+
+    // Clear hints if the new text value is empty or kernel is unavailable.
+    if (!code || !this.kernel) {
+      return;
+    }
+
+    let contents: KernelMessage.IInspectRequest = {
+      code,
+      cursor_pos: offset,
+      detail_level: this._detailLevel
+    };
+    let pending = ++this._pending;
+
+    kernel.requestInspect(contents).then(msg => {
+      let value = msg.content;
+
+      // If model has been disposed, bail.
+      if (this._isDisposed) {
+        return;
+      }
+
+      // If a newer text change has created a pending request, bail.
+      if (pending !== this._pending) {
+        return;
+      }
+
+      // Hint request failures or negative results fail silently.
+      if (value.status !== 'ok' || !value.found) {
+        return;
+      }
+
+      // Set the content to a rendered widget.
+      this._content = this.rendermime.render({
+        bundle: value.data as RenderMime.MimeMap<string>,
+        trusted: true
+      });
+
+      // Notify listeners of content change.
+      this.contentChanged.emit(void 0);
+    });
+  }
+
+  private _content: Widget = null;
+  private _detailLevel: 0 | 1 = 0;
+  private _isDisposed = false;
+  private _pending = 0;
+}
+
+
+// Define the signals for the `TooltipModel` class.
+defineSignal(TooltipModel.prototype, 'contentChanged');
+defineSignal(TooltipModel.prototype, 'disposed');
+
+
+/**
+ * A namespace for tooltip model statics.
+ */
+export
+namespace TooltipModel {
+  /**
+   * The instantiation options for a tooltip model.
+   */
+  export
+  interface IOptions {
+    /**
+     * The editor referent of the tooltip model.
+     */
+    editor: CodeEditor.IEditor;
+
+    /**
+     * The kernel for the tooltip model.
+     */
+    kernel: Kernel.IKernel;
+
+    /**
+     * The rendermime instance used by the tooltip model.
+     */
+    rendermime: IRenderMime;
+  }
+}

+ 27 - 5
src/tooltip/plugin.ts

@@ -25,9 +25,17 @@ import {
   INotebookTracker
 } from '../notebook';
 
+import {
+  IRenderMime
+} from '../rendermime';
+
+import {
+  TooltipModel
+} from './model';
+
 import {
   TooltipWidget
-} from './index';
+} from './widget';
 
 
 /**
@@ -56,6 +64,7 @@ function activate(app: JupyterLab, consoles: IConsoleTracker, notebooks: INotebo
   const keymap = app.keymap;
   const registry = app.commands;
   let tooltip: TooltipWidget = null;
+  let model: TooltipModel = null;
   let id = 0;
 
   // Add tooltip launch command.
@@ -64,28 +73,41 @@ function activate(app: JupyterLab, consoles: IConsoleTracker, notebooks: INotebo
       let notebook = args['notebook'] as boolean;
       let editor: CodeEditor.IEditor = null;
       let kernel: Kernel.IKernel = null;
+      let rendermime: IRenderMime = null;
+      let extant = !!tooltip;
+      let ready = false;
+
       if (notebook) {
         let widget = notebooks.currentWidget;
         if (widget) {
           editor = widget.notebook.activeCell.editor;
           kernel = widget.kernel;
+          rendermime = widget.rendermime;
+          ready = !!editor && !!kernel && !!rendermime;
         }
       } else {
         let widget = consoles.currentWidget;
         if (widget) {
           editor = widget.console.prompt.editor;
           kernel = widget.console.session.kernel;
+          rendermime = widget.console.rendermime;
+          ready = !!editor && !!kernel && !!rendermime;
         }
       }
-      if (tooltip) {
+
+      // Dispose extant tooltip and model.
+      if (extant) {
         tooltip.dispose();
+        model.dispose();
       }
-      if (editor) {
-        tooltip = new TooltipWidget({ editor, kernel });
+
+      // If all components necessary for rendering exist, create a tooltip.
+      if (ready) {
+        model = new TooltipModel({ editor, kernel, rendermime });
+        tooltip = new TooltipWidget({ model });
         tooltip.id = `tooltip-${++id}`;
         Widget.attach(tooltip, document.body);
         tooltip.activate();
-        console.log('add tooltip for ' + (notebook ? 'notebook' : 'console'));
       }
     }
   });

+ 8 - 25
src/tooltip/index.ts → src/tooltip/widget.ts

@@ -1,10 +1,6 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
 
-import {
-  Kernel
-} from '@jupyterlab/services';
-
 import {
   Message
 } from 'phosphor/lib/core/messaging';
@@ -14,8 +10,8 @@ import {
 } from 'phosphor/lib/ui/widget';
 
 import {
-  CodeEditor
-} from '../codeeditor';
+  TooltipModel
+} from './model';
 
 
 /**
@@ -34,26 +30,19 @@ class TooltipWidget extends Widget {
    */
   constructor(options: TooltipWidget.IOptions) {
     super();
-    this.editor = options.editor;
-    this.kernel = options.kernel;
+    this.model = options.model;
     this.addClass(TOOLTIP_CLASS);
   }
 
   /**
-   * The editor referent of the tooltip widget.
-   */
-  readonly editor: CodeEditor.IEditor;
-
-  /**
-   * The kernel for the tooltip widget.
+   * The tooltip widget's data model.
    */
-  readonly kernel: Kernel.IKernel;
+  readonly model: TooltipModel;
 
   /**
    * Handle `'activate-request'` messages.
    */
   protected onActivateRequest(msg: Message): void {
-    console.log('activate-request');
     this.node.tabIndex = -1;
     this.node.focus();
   }
@@ -62,14 +51,13 @@ class TooltipWidget extends Widget {
    * Handle `'after-attach'` messages.
    */
   protected onAfterAttach(msg: Message): void {
-    console.log('after-attach');
+    this.model.fetch();
   }
 
   /**
    * Handle `'update-request'` messages.
    */
   protected onUpdateRequest(msg: Message): void {
-    console.log('update-request');
     super.onUpdateRequest(msg);
   }
 }
@@ -85,13 +73,8 @@ namespace TooltipWidget {
   export
   interface IOptions {
     /**
-     * The editor referent of the tooltip widget.
-     */
-    editor: CodeEditor.IEditor;
-
-    /**
-     * The kernel for the tooltip widget.
+     * The data model for the tooltip widget.
      */
-    kernel: Kernel.IKernel;
+    model: TooltipModel;
   }
 }