浏览代码

Clean up completion logic, add defensive checks.

A. Darian 8 年之前
父节点
当前提交
6cc66725b7
共有 2 个文件被更改,包括 31 次插入21 次删除
  1. 1 3
      src/console/widget.ts
  2. 30 18
      src/notebook/completion/model.ts

+ 1 - 3
src/console/widget.ts

@@ -432,9 +432,7 @@ class ConsoleWidget extends Widget {
       model.current = change;
     } else {
       // If final character is whitespace, reset completion.
-      model.options = null;
-      model.original = null;
-      model.cursor = null;
+      model.reset();
     }
     // Displaying completion widget overrides displaying tooltip.
     if (hasCompletion) {

+ 30 - 18
src/notebook/completion/model.ts

@@ -111,11 +111,6 @@ interface ICompletionModel extends IDisposable {
    */
   current: ITextChange;
 
-  /**
-   * The cursor details that the API has used to return matching options.
-   */
-  cursor: ICursorSpan;
-
   /**
    * The list of visible items in the completion menu.
    */
@@ -172,16 +167,6 @@ class CompletionModel implements ICompletionModel {
     return Private.stateChangedSignal.bind(this);
   }
 
-  /**
-   * The cursor details that the API has used to return matching options.
-   */
-  get cursor(): ICursorSpan {
-    return this._cursor;
-  }
-  set cursor(cursor: ICursorSpan) {
-    this._cursor = cursor;
-  }
-
   /**
    * The list of visible items in the completion menu.
    *
@@ -236,8 +221,27 @@ class CompletionModel implements ICompletionModel {
     if (deepEqual(newValue, this._current)) {
       return;
     }
+
+    // Original request must always be set before a text change. If it isn't
+    // the model fails silently.
+    if (!this.original) {
+      return;
+    }
+
+    // Cursor must always be set before a text change. This happens
+    // automatically in the API response but since `current` is a public
+    // attribute, this defensive check is necessary.
+    if (!this._cursor) {
+      return;
+    }
+
     this._current = newValue;
 
+    if (!this.current) {
+      this.stateChanged.emit(void 0);
+      return;
+    }
+
     let original = this._original;
     let current = this._current;
     let originalLine = original.currentValue.split('\n')[original.line];
@@ -283,9 +287,10 @@ class CompletionModel implements ICompletionModel {
       if (value.status !== 'ok') {
         return;
       }
-      // Update the state.
+      // Update the options.
       this.options = value.matches;
-      this.cursor = { start: value.cursor_start, end: value.cursor_end };
+      // Update the cursor.
+      this.setCursor({ start: value.cursor_start, end: value.cursor_end });
     }).then(() => { this.original = request; });
   }
 
@@ -364,6 +369,13 @@ class CompletionModel implements ICompletionModel {
     this.stateChanged.emit(void 0);
   }
 
+  /**
+   * Set the cursor details that the API has used to return matching options.
+   */
+  protected setCursor(cursor: ICursorSpan): void {
+    this._cursor = cursor;
+  }
+
   /**
    * Apply the query to the complete options list to return the matching subset.
    */
@@ -393,7 +405,7 @@ class CompletionModel implements ICompletionModel {
   private _original: ICompletionRequest = null;
   private _current: ITextChange = null;
   private _query = '';
-  private _cursor: { start: number, end: number } = null;
+  private _cursor: ICursorSpan = null;
   private _pendingComplete = 0;
 }