Преглед изворни кода

Finish implementing the context manager

Steven Silvester пре 8 година
родитељ
комит
5c2b648c27
3 измењених фајлова са 92 додато и 46 уклоњено
  1. 1 1
      package.json
  2. 60 35
      src/docmanager/context.ts
  3. 31 10
      src/docmanager/index.ts

+ 1 - 1
package.json

@@ -8,7 +8,7 @@
     "ansi_up": "^1.3.0",
     "backbone": "^1.2.0",
     "codemirror": "^5.12.0",
-    "jupyter-js-services": "^0.9.2",
+    "jupyter-js-services": "^0.10.0",
     "jupyter-js-utils": "^0.4.0",
     "jupyter-js-widgets": "0.0.17",
     "marked": "^0.3.5",

+ 60 - 35
src/docmanager/context.ts

@@ -4,12 +4,12 @@
 
 import {
   IKernelId, IKernel, IKernelSpecIds, IContentsManager,
-  INotebookSessionManager, INotebookSession, ISessionId
+  INotebookSessionManager, INotebookSession, ISessionId,
+  IContentsOpts, ISessionOptions
 } from 'jupyter-js-services';
 
-import {
-  uuid
-} from 'jupyter-js-utils';
+import * as utils
+  from 'jupyter-js-utils';
 
 import {
   IDisposable, DisposableDelegate
@@ -45,7 +45,7 @@ class Context implements IDocumentContext {
    */
   constructor(manager: ContextManager) {
     this._manager = manager;
-    this._id = uuid();
+    this._id = utils.uuid();
   }
 
   /**
@@ -186,7 +186,7 @@ class ContextManager {
   /**
    * Construct a new context manager.
    */
-  constructor(contentsManager: IContentsManager, sessionManager: INotebookSessionManager, opener: IWidgetOpener) {
+  constructor(contentsManager: IContentsManager, sessionManager: INotebookSessionManager, opener: (id: string, widget: Widget) => IDisposable) {
     this._contentsManager = contentsManager;
     this._sessionManager = sessionManager;
     this._opener = opener;
@@ -199,12 +199,13 @@ class ContextManager {
   /**
    * Create a new context.
    */
-  createNew(path: string, model: IDocumentModel): IDocumentContext {
+  createNew(path: string, model: IDocumentModel, options: IContentsOpts): IDocumentContext {
     let context = new Context(this);
     let id = context.id;
     this._paths[id] = path;
     this._contexts[id] = context;
     this._models[id] = model;
+    this._options[id] = options;
     return context;
   }
 
@@ -242,37 +243,34 @@ class ContextManager {
    */
   changeKernel(id: string, options: IKernelId): Promise<IKernel> {
     let session = this._sessions[id];
-    let context = this._contexts[id];
     if (!session) {
       let path = this._paths[id];
       let sOptions = {
         notebook: { path },
         kernel: { options }
       }
-      return this._sessionManager.startNew(sOptions).then(session => {
-        this._sessions[id] = session;
-        context.kernelChanged.emit(session.kernel);
-        return session.kernel;
-      });
+      return this._startSession(id, sOptions);
     } else {
-      return session.changeKernel(options).then(kernel => {
-        context.kernelChanged.emit(kernel);
-        return kernel;
-      });
+      return session.changeKernel(options);
     }
   }
 
   /**
    * Update the path of an open document.
    *
-   * @param oldPath - The previous path.
+   * @param id - The id of the context.
    *
    * @param newPath - The new path.
    */
-  rename(oldPath: string, newPath: string): Promise<void> {
-    // Find all contexts for that path
-    // Update the existing sessions
-    return void 0;
+  rename(id: string, newPath: string): Promise<void> {
+    let session = this._sessions[id];
+    if (session) {
+      return session.renameNotebook(newPath);
+    }
+    let context = this._contexts[id];
+    this._paths[id] = newPath;
+    context.pathChanged.emit(newPath);
+    return Promise.resolve(void 0);
   }
 
   /**
@@ -285,16 +283,27 @@ class ContextManager {
   /**
    * Save the document contents to disk.
    */
-  save(path: string): Promise<void> {
-    // This is a problem, because *which* one do we save?
-    return void 0;
+  save(id: string): Promise<void> {
+    let opts = utils.copy(this._options[id]);
+    let path = this._paths[id];
+    let model = this._models[id];
+    opts.content = model.serialize();
+    return this._contentsManager.save(path, opts).then(() => {
+      model.dirty = false;
+    });
   }
 
   /**
    * Revert the contents of a path.
    */
-  revert(path: string): Promise<void> {
-    return void 0;
+  revert(id: string): Promise<void> {
+    let opts = utils.copy(this._options[id]);
+    let path = this._paths[id];
+    let model = this._models[id];
+    return this._contentsManager.get(path, opts).then(contents => {
+      model.deserialize(contents.content);
+      model.dirty = false;
+    });
   }
 
   /**
@@ -307,13 +316,28 @@ class ContextManager {
   /**
    * Add a sibling widget to the document manager.
    */
-  addSibling(path: string, widget: Widget): IDisposable {
-   // TODO: Add the widget to the list of siblings
-   // This needs to go back to the document manager to set the
-   // context and factory properties.
-   this._opener.open(widget);
-   // TODO: return a disposable
-   return void 0;
+  addSibling(id: string, widget: Widget): IDisposable {
+    let opener = this._opener;
+    return opener(id, widget);
+  }
+
+  /**
+   * Start a session and set up its signals.
+   */
+  private _startSession(id: string, options: ISessionOptions): Promise<IKernel> {
+    let context = this._contexts[id];
+    return this._sessionManager.startNew(options).then(session => {
+      this._sessions[id] = session;
+      context.kernelChanged.emit(session.kernel);
+      session.notebookPathChanged.connect((s, path) => {
+        this._paths[id] = path;
+        context.pathChanged.emit(path);
+      });
+      session.kernelChanged.connect((s, kernel) => {
+        context.kernelChanged.emit(kernel);
+      });
+      return session.kernel;
+    });
   }
 
   private _contentsManager: IContentsManager = null;
@@ -322,6 +346,7 @@ class ContextManager {
   private _contexts: { [key: string]: IDocumentContext } = Object.create(null);
   private _models: { [key: string]: IDocumentModel } = Object.create(null);
   private _sessions: { [key: string]: INotebookSession } = Object.create(null);
-  private _opener: IWidgetOpener = null;
+  private _opener: (id: string, widget: Widget) => IDisposable = null;
+  private _options: { [key: string]: IContentsOpts } = Object.create(null);
   private _paths: { [key: string]: string } = Object.create(null);
 }

+ 31 - 10
src/docmanager/index.ts

@@ -309,7 +309,15 @@ class DocumentManager {
   constructor(contentsManager: IContentsManager, sessionManager: INotebookSessionManager, opener: IWidgetOpener) {
     this._contentsManager = contentsManager;
     this._sessionManager = sessionManager;
-    this._contextManager = new ContextManager(contentsManager, sessionManager, opener);
+    this._contextManager = new ContextManager(contentsManager, sessionManager, (id: string, widget: Widget) => {
+      let parent = new Widget();
+      this._attachChild(parent, widget);
+      Private.contextProperty.set(widget, id);
+      opener.open(parent);
+      return new DisposableDelegate(() => {
+        parent.dispose();
+      });
+    });
   }
 
   /**
@@ -466,10 +474,11 @@ class DocumentManager {
     }
     let lang = mFactoryEx.factory.preferredLanguage(path);
     let model = mFactoryEx.factory.createNew(lang);
-    manager.get(path, mFactoryEx.contentsOptions).then(contents => {
+    let opts = mFactoryEx.contentsOptions;
+    manager.get(path, opts).then(contents => {
       model.deserialize(contents.content);
       model.dirty = false;
-      this._createWidget(path, model, widgetName, widget, kernel);
+      this._createWidget(path, opts, model, widgetName, widget, kernel);
     });
     installMessageFilter(widget, this);
     Private.factoryProperty.set(widget, widgetName);
@@ -503,7 +512,7 @@ class DocumentManager {
     let opts = mFactoryEx.contentsOptions;
     opts.content = model.serialize();
     manager.save(path, opts).then(content => {
-      this._createWidget(path, model, widgetName, widget, kernel);
+      this._createWidget(path, opts, model, widgetName, widget, kernel);
     });
     installMessageFilter(widget, this);
     Private.factoryProperty.set(widget, widgetName);
@@ -533,6 +542,7 @@ class DocumentManager {
       let model = this._contextManager.getModel(id);
       let context = this._contextManager.getContext(id);
       let factoryName = Private.factoryProperty.get(widget);
+      factoryName = factoryName || this._defaultWidgetFactory;
       let factory = this._widgetFactories[factoryName].factory;
       if (!model.dirty) {
         factory.beforeClose(model, context, child).then(result => {
@@ -584,14 +594,18 @@ class DocumentManager {
    * Save the document contents to disk.
    */
   saveFile(path: string): Promise<void> {
-    return this._contextManager.save(path);
+    // TODO: find the appropriate context.
+    //return this._contextManager.save(id);
+    return void 0;
   }
 
   /**
    * Revert the document contents to disk contents.
    */
   revertFile(path: string): Promise<void> {
-    return this._contextManager.revert(path);
+    // TODO: find the appropriate context.
+    //return this._contextManager.revert(id);
+    return void 0;
   }
 
   /**
@@ -611,13 +625,20 @@ class DocumentManager {
   /**
    * Create a context and a widget.
    */
-  private _createWidget(path: string, model: IDocumentModel, widgetName: string, parent: Widget, kernel?:IKernelId): void {
+  private _createWidget(path: string, options: IContentsOpts, model: IDocumentModel, widgetName: string, parent: Widget, kernel?:IKernelId): void {
     let wFactoryEx = this._getWidgetFactoryEx(widgetName);
-    parent.layout = new PanelLayout();
-    let context = this._contextManager.createNew(path, model);
+    let context = this._contextManager.createNew(path, model, options);
     Private.contextProperty.set(parent, context.id);
     // Create the child widget using the factory.
     let child = wFactoryEx.factory.createNew(model, context, kernel);
+    this._attachChild(parent, child);
+  }
+
+  /**
+   * Attach a child widget to a parent container.
+   */
+  private _attachChild(parent: Widget, child: Widget) {
+    parent.layout = new PanelLayout();
     parent.title.closable = true;
     parent.title.text = child.title.text;
     parent.title.icon = child.title.icon;
@@ -628,7 +649,7 @@ class DocumentManager {
       child.parent.title.icon = child.title.icon;
       child.parent.title.className = child.title.className;
     });
-    // Add the child widget to the parent widget and emit opened.
+    // Add the child widget to the parent widget.
     (parent.layout as PanelLayout).addChild(child);
   }