|
@@ -36,10 +36,7 @@ class CodeMirrorModel implements CodeEditor.IModel {
|
|
|
*/
|
|
|
constructor(doc: CodeMirror.Doc = new CodeMirror.Doc('')) {
|
|
|
this._doc = doc;
|
|
|
- CodeMirror.on(this.doc, 'change', (instance, change) => {
|
|
|
- this._onDocChange(instance, change);
|
|
|
- });
|
|
|
- this._value.changed.connect(this._onValueChanged, this);
|
|
|
+ this._value = new Private.ObservableDoc(doc);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -63,26 +60,6 @@ class CodeMirrorModel implements CodeEditor.IModel {
|
|
|
return this._doc;
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 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);
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* A mime type of the model.
|
|
|
*/
|
|
@@ -109,10 +86,30 @@ class CodeMirrorModel implements CodeEditor.IModel {
|
|
|
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 {
|
|
|
+ getLine(line: number): string | undefined {
|
|
|
return this._doc.getLine(line);
|
|
|
}
|
|
|
|
|
@@ -155,41 +152,11 @@ class CodeMirrorModel implements CodeEditor.IModel {
|
|
|
this._doc.clearHistory();
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Handle value changes.
|
|
|
- */
|
|
|
- private _onValueChanged(value: IObservableString, change: ObservableString.IChangedArgs): void {
|
|
|
- if (this._changeGuard) {
|
|
|
- return;
|
|
|
- }
|
|
|
- let doc = this._doc;
|
|
|
- switch (change.type) {
|
|
|
- case 'set':
|
|
|
- doc.setValue(change.value);
|
|
|
- break;
|
|
|
- default:
|
|
|
- let from = doc.posFromIndex(change.start);
|
|
|
- let to = doc.posFromIndex(change.end);
|
|
|
- doc.replaceRange(change.value, from, to);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Handles document changes.
|
|
|
- */
|
|
|
- protected _onDocChange(doc: CodeMirror.Doc, change: CodeMirror.EditorChange) {
|
|
|
- if (change.origin !== 'setValue') {
|
|
|
- this._changeGuard = true;
|
|
|
- this._value.text = doc.getValue();
|
|
|
- this._changeGuard = false;
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- private _mimetype = '';
|
|
|
- private _value = new ObservableString();
|
|
|
+ private _mimetype = 'text/plain';
|
|
|
+ private _value: Private.ObservableDoc;
|
|
|
private _isDisposed = false;
|
|
|
private _doc: CodeMirror.Doc;
|
|
|
- private _changeGuard = false;
|
|
|
private _selections = new CodeEditor.Selections();
|
|
|
}
|
|
|
|
|
@@ -198,3 +165,157 @@ class CodeMirrorModel implements CodeEditor.IModel {
|
|
|
* 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');
|
|
|
+}
|