Kaynağa Gözat

Move the codemirror model to the editor

Steven Silvester 8 yıl önce
ebeveyn
işleme
3f7197bf2f
3 değiştirilmiş dosya ile 120 ekleme ve 329 silme
  1. 1 1
      src/codeeditor/editor.ts
  2. 119 7
      src/codemirror/editor.ts
  3. 0 321
      src/codemirror/model.ts

+ 1 - 1
src/codeeditor/editor.ts

@@ -516,7 +516,7 @@ namespace CodeEditor {
 
 
     /**
-     * Get the number of lines in the model.
+     * Get the number of lines in the eidtor.
      */
     readonly lineCount: number;
 

+ 119 - 7
src/codemirror/editor.ts

@@ -68,18 +68,24 @@ class CodeMirrorEditor implements CodeEditor.IEditor {
     this.uuid = this.uuid;
     this.selectionStyle = options.selectionStyle;
 
-    this._model = new CodeMirrorModel();
+    let model = this._model = options.model;
 
     options.theme = (options.theme || DEFAULT_CODEMIRROR_THEME);
     options.value = this._model.doc;
-    this._editor = CodeMirror(host, options);
+    let editor = this._editor = CodeMirror(host, options);
+    let doc = editor.getDoc();
 
+    // Handle initial model values.
+    doc.setValue(model.value.text);
     this._onMimeTypeChanged();
     // TODO: handle initial selections.
-    this._model.mimeTypeChanged.connect(() => this._onMimeTypeChanged());
-    this._model.selections.changed.connect((selections, args) => this._onSelectionsChanged(selections, args));
 
-    CodeMirror.on(this.editor, 'keydown', (editor, event) => {
+    // Connect to changes.
+    model.value.changed.connect(this._onValueChanged, this);
+    model.mimeTypeChanged.connect(() => this._onMimeTypeChanged(), this);
+    model.selections.changed.connect((selections, args) => this._onSelectionsChanged(selections, args), this);
+
+    CodeMirror.on(editor, 'keydown', (editor, event) => {
       findIndex(this._keydownHandlers, handler => {
         if (handler(this, event) === true) {
           event.preventDefault();
@@ -87,7 +93,10 @@ class CodeMirrorEditor implements CodeEditor.IEditor {
         }
       });
     });
-    CodeMirror.on(this.editor, 'cursorActivity', () => this._onCursorActivity());
+    CodeMirror.on(editor, 'cursorActivity', () => this._onCursorActivity());
+    CodeMirror.on(editor.getDoc(), 'change', (instance, change) => {
+      this._onDocChanged(instance, change);
+    });
   }
 
   /**
@@ -121,6 +130,13 @@ class CodeMirrorEditor implements CodeEditor.IEditor {
     return this._editor;
   }
 
+  /**
+   * Get the number of lines in the editor.
+   */
+  get lineCount(): number {
+    return this._editor.getDoc().lineCount();
+  }
+
   /**
    * Control the rendering of line numbers.
    */
@@ -173,6 +189,52 @@ class CodeMirrorEditor implements CodeEditor.IEditor {
     return this._editor.defaultCharWidth();
   }
 
+  /**
+   * Returns the content for the given line number.
+   */
+  getLine(line: number): string | undefined {
+    return this._editor.getDoc().getLine(line);
+  }
+
+  /**
+   * Find an offset for the given position.
+   */
+  getOffsetAt(position: CodeEditor.IPosition): number {
+    return this._editor.getDoc().indexFromPos({
+      ch: position.column,
+      line: position.line
+    });
+  }
+
+  /**
+   * Find a position fot the given offset.
+   */
+  getPositionAt(offset: number): CodeEditor.IPosition {
+    const { ch, line } = this._editor.getDoc().posFromIndex(offset);
+    return { line, column: ch };
+  }
+
+  /**
+   * Undo one edit (if any undo events are stored).
+   */
+  undo(): void {
+    this._editor.getDoc().undo();
+  }
+
+  /**
+   * Redo one undone edit.
+   */
+  redo(): void {
+    this._editor.getDoc().redo();
+  }
+
+  /**
+   * Clear the undo history.
+   */
+  clearHistory(): void {
+    this._editor.getDoc().clearHistory();
+  }
+
   /**
    * Brings browser focus to this editor text.
    */
@@ -425,12 +487,62 @@ class CodeMirrorEditor implements CodeEditor.IEditor {
     };
   }
 
+  /**
+   * Handle model value changes.
+   */
+  private _onValueChanged(value: IObservableString, args: ObservableString.IChangedArgs): void {
+    this._changeGuard = true;
+    let doc = self._editor.getDoc();
+    switch (args.type) {
+    case 'insert':
+      let pos = doc.posFromIndex(args.start);
+      doc.replaceRange(args.value, pos, pos);
+      break;
+    case 'remove':
+      let from = doc.posFromIndex(args.start);
+      let to = doc.posFromIndex(args.end);
+      doc.replaceRange('', from, to);
+      break;
+    case 'set':
+      doc.setValue(args.value);
+      break;
+    default:
+      break;
+    }
+    this._changeGuard = false;
+  }
+
+  /**
+   * Handles document changes.
+   */
+  private _onDocChange(doc: CodeMirror.Doc, change: CodeMirror.EditorChange) {
+    if (this._changeGuard) {
+      return;
+    }
+    this._changeGuard = true;
+    let text = doc.getValue();
+    let value = this._model.value;
+
+    if (!change.origin || change.origin === 'setValue' ||
+        change.text.length > 1 || change.removed.length > 1) {
+      value.text = text;
+    }
+    let start = doc.indexFromPos(change.from);
+    let end = doc.indexFromPos(change.to);
+    if (change.origin.indexOf('delete') !== -1) {
+      value.remove(start, end);
+    } else {
+      value.insert(start, text);
+    }
+    this._changeGuard = false;
+  }
+
   private _model: CodeMirrorModel;
   private _editor: CodeMirror.Editor;
   private _isDisposed = false;
   protected selectionMarkers: { [key: string]: CodeMirror.TextMarker[] | undefined } = {};
   private _keydownHandlers = new Vector<CodeEditor.KeydownHandler>();
-
+  private _changeGuard = false;
 }
 
 /**

+ 0 - 321
src/codemirror/model.ts

@@ -1,321 +0,0 @@
-// Copyright (c) Jupyter Development Team.
-// Distributed under the terms of the Modified BSD License.
-
-import * as CodeMirror
-  from 'codemirror';
-
-import {
-  ISignal, clearSignalData, defineSignal
-} from 'phosphor/lib/core/signaling';
-
-import {
-  CodeEditor
-} from '../codeeditor/editor';
-
-import {
-  IChangedArgs
-} from '../common/interfaces';
-
-import {
-  IObservableString, ObservableString
-} from '../common/observablestring';
-
-
-/**
- * An implementation of the code editor model using code mirror.
- */
-export
-class CodeMirrorModel implements CodeEditor.IModel {
-  /**
-   * A signal emitted when a mimetype changes.
-   */
-  readonly mimeTypeChanged: ISignal<this, IChangedArgs<string>>;
-
-  /**
-   * Construct a new codemirror model.
-   */
-  constructor(doc: CodeMirror.Doc = new CodeMirror.Doc('')) {
-    this._doc = doc;
-    this._value = new Private.ObservableDoc(doc);
-  }
-
-  /**
-   * Get the value of the model.
-   */
-  get value(): IObservableString {
-    return this._value;
-  }
-
-  /**
-   * Get the selections for the model.
-   */
-  get selections(): CodeEditor.ISelections {
-    return this._selections;
-  }
-
-  /**
-   * An underying CodeMirror document.
-   */
-  get doc(): CodeMirror.Doc {
-    return this._doc;
-  }
-
-  /**
-   * A mime type of the model.
-   */
-  get mimeType(): string {
-    return this._mimetype;
-  }
-  set mimeType(newValue: string) {
-    const oldValue = this._mimetype;
-    if (oldValue === newValue) {
-      return;
-    }
-    this._mimetype = newValue;
-    this.mimeTypeChanged.emit({
-      name: 'mimeType',
-      oldValue,
-      newValue
-    });
-  }
-
-  /**
-   * Get the number of lines in the model.
-   */
-  get lineCount(): number {
-    return this._doc.lineCount();
-  }
-
-  /**
-   * Whether the model is disposed.
-   */
-  get isDisposed(): boolean {
-    return this._isDisposed;
-  }
-
-  /**
-   * Dipose of the resources used by the model.
-   */
-  dispose(): void {
-    if (this._isDisposed) {
-      return;
-    }
-    this._isDisposed = true;
-    this._selections.dispose();
-    this._value.dispose();
-    clearSignalData(this);
-  }
-
-  /**
-   * Returns the content for the given line number.
-   */
-  getLine(line: number): string | undefined {
-    return this._doc.getLine(line);
-  }
-
-  /**
-   * Find an offset for the given position.
-   */
-  getOffsetAt(position: CodeEditor.IPosition): number {
-    return this._doc.indexFromPos({
-      ch: position.column,
-      line: position.line
-    });
-  }
-
-  /**
-   * Find a position fot the given offset.
-   */
-  getPositionAt(offset: number): CodeEditor.IPosition {
-    const { ch, line } = this._doc.posFromIndex(offset);
-    return { line, column: ch };
-  }
-
-  /**
-   * Undo one edit (if any undo events are stored).
-   */
-  undo(): void {
-    this._doc.undo();
-  }
-
-  /**
-   * Redo one undone edit.
-   */
-  redo(): void {
-    this._doc.redo();
-  }
-
-  /**
-   * Clear the undo history.
-   */
-  clearHistory(): void {
-    this._doc.clearHistory();
-  }
-
-
-  private _mimetype = 'text/plain';
-  private _value: Private.ObservableDoc;
-  private _isDisposed = false;
-  private _doc: CodeMirror.Doc;
-  private _selections = new CodeEditor.Selections();
-}
-
-
-/**
- * The signals for the `CodeMirrorModel` class.
- */
-defineSignal(CodeMirrorModel.prototype, 'mimeTypeChanged');
-
-
-/**
- * The namespace for module private data.
- */
-namespace Private {
-  /**
-   * An observable string implementation wrapping a Codemirror Doc.
-   */
-  export
-  class ObservableDoc implements IObservableString {
-    /**
-     * Create a new observable doc.
-     */
-    constructor(doc: CodeMirror.Doc) {
-      this._doc = doc;
-      CodeMirror.on(doc, 'change', (instance, change) => {
-        this._onDocChange(instance, change);
-      });
-    }
-
-    /**
-     * A signal emitted when the string has changed.
-     */
-    readonly changed: ISignal<this, ObservableString.IChangedArgs>;
-
-    /**
-     * Set the value of the string.
-     */
-    set text(value: string) {
-      this._changeGuard = true;
-      this._doc.setValue(value);
-      this._changeGuard = false;
-      this.changed.emit({
-        type: 'set',
-        start: 0,
-        end: value.length,
-        value: value
-      });
-    }
-
-    /**
-     * Get the value of the string.
-     */
-    get text(): string {
-      return this._doc.getValue();
-    }
-
-    /**
-     * Insert a substring.
-     *
-     * @param index - The starting index.
-     *
-     * @param text - The substring to insert.
-     */
-    insert(index: number, text: string): void {
-      let doc = this._doc;
-      let pos = doc.posFromIndex(index);
-      doc.replaceRange(text, pos, pos);
-      this.changed.emit({
-        type: 'insert',
-        start: index,
-        end: index + text.length,
-        value: text
-      });
-    }
-
-    /**
-     * Remove a substring.
-     *
-     * @param start - The starting index.
-     *
-     * @param end - The ending index.
-     */
-    remove(start: number, end: number): void {
-      let doc = this._doc;
-      let from = doc.posFromIndex(start);
-      let to = doc.posFromIndex(end);
-      let oldValue = doc.getRange(from, to);
-      doc.replaceRange('', from, to);
-      this.changed.emit({
-        type: 'remove',
-        start: start,
-        end: end,
-        value: oldValue
-      });
-    }
-
-    /**
-     * Set the ObservableDoc to an empty string.
-     */
-    clear(): void {
-      this._doc.setValue('');
-    }
-
-    /**
-     * Test whether the string has been disposed.
-     */
-    get isDisposed(): boolean {
-      return this._isDisposed;
-    }
-
-    /**
-     * Dispose of the resources held by the string.
-     */
-    dispose(): void {
-      if (this._isDisposed) {
-        return;
-      }
-      this._isDisposed = true;
-      clearSignalData(this);
-      this._doc = null;
-    }
-
-    /**
-     * Handles document changes.
-     */
-    protected _onDocChange(doc: CodeMirror.Doc, change: CodeMirror.EditorChange) {
-      if (this._changeGuard) {
-        return;
-      }
-      let value = doc.getValue();
-      if (!change.origin || change.origin === 'setValue' ||
-          change.text.length > 1 || change.removed.length > 1) {
-        this.changed.emit({
-          type: 'set',
-          start: 0,
-          end: value.length,
-          value
-        });
-        return;
-      }
-      let start = doc.indexFromPos(change.from);
-      let end = doc.indexFromPos(change.to);
-      let changeType: ObservableString.ChangeType = 'insert';
-      if (change.origin.indexOf('delete') !== -1) {
-        changeType = 'remove';
-      }
-      this.changed.emit({
-        type: changeType,
-        start,
-        end,
-        value
-      });
-    }
-
-    private _doc: CodeMirror.Doc;
-    private _isDisposed : boolean = false;
-    private _changeGuard = false;
-  }
-
-  // Define the signals for the `ObservableDoc` class.
-  defineSignal(ObservableDoc.prototype, 'changed');
-}