Commit eb8a6095 authored by Phil Hughes's avatar Phil Hughes

added disposable manager

added model manager

[ci skip]
parent c90b520d
...@@ -3,13 +3,15 @@ ...@@ -3,13 +3,15 @@
import { mapGetters, mapActions } from 'vuex'; import { mapGetters, mapActions } from 'vuex';
import flash from '../../flash'; import flash from '../../flash';
import monacoLoader from '../monaco_loader'; import monacoLoader from '../monaco_loader';
import editor from '../lib/editor'; import Editor from '../lib/editor';
export default { export default {
destroyed() { destroyed() {
editor.dispose(); this.editor.dispose();
}, },
mounted() { mounted() {
this.editor = Editor.create();
if (this.monaco) { if (this.monaco) {
this.initMonaco(); this.initMonaco();
} else { } else {
...@@ -26,11 +28,11 @@ export default { ...@@ -26,11 +28,11 @@ export default {
initMonaco() { initMonaco() {
if (this.shouldHideEditor) return; if (this.shouldHideEditor) return;
editor.clearEditor(); this.editor.clearEditor();
this.getRawFileData(this.activeFile) this.getRawFileData(this.activeFile)
.then(() => { .then(() => {
editor.createInstance(this.$el); this.editor.createInstance(this.$el);
}) })
.then(() => this.setupEditor()) .then(() => this.setupEditor())
.catch(() => flash('Error setting up monaco. Please try again.')); .catch(() => flash('Error setting up monaco. Please try again.'));
...@@ -38,9 +40,9 @@ export default { ...@@ -38,9 +40,9 @@ export default {
setupEditor() { setupEditor() {
if (!this.activeFile) return; if (!this.activeFile) return;
const model = editor.createModel(this.activeFile); const model = this.editor.createModel(this.activeFile);
editor.attachModel(model); this.editor.attachModel(model);
model.onChange((m) => { model.onChange((m) => {
this.changeFileContent({ this.changeFileContent({
file: this.activeFile, file: this.activeFile,
......
export default class Disposable {
constructor() {
this.disposers = new Set();
}
add(...disposers) {
disposers.forEach(disposer => this.disposers.add(disposer));
}
dispose() {
this.disposers.forEach(disposer => disposer.dispose());
this.disposers.clear();
}
}
/* global monaco */ /* global monaco */
import Disposable from './disposable';
export default class Model { export default class Model {
constructor(file) { constructor(file) {
this.disposable = new Disposable();
this.file = file; this.file = file;
this.content = file.content !== '' ? file.content : file.raw; this.content = file.content !== '' ? file.content : file.raw;
this.disposable.add(
this.originalModel = monaco.editor.createModel( this.originalModel = monaco.editor.createModel(
this.content, this.content,
undefined, undefined,
new monaco.Uri(null, null, `original/${this.file.path}`), new monaco.Uri(null, null, `original/${this.file.path}`),
); ),
this.model = monaco.editor.createModel( this.model = monaco.editor.createModel(
this.content, this.content,
undefined, undefined,
new monaco.Uri(null, null, this.file.path), new monaco.Uri(null, null, this.file.path),
),
); );
this.disposers = new Map();
this.attachedToWorker = false;
this.events = new Map();
} }
get url() { get url() {
return this.model.uri.toString(); return this.model.uri.toString();
} }
get originalUrl() {
return this.originalModel.uri.toString();
}
get path() {
return this.file.path;
}
get diffModel() {
return {
url: this.model.uri.toString(),
versionId: this.model.getVersionId(),
lines: this.model.getLinesContent(),
EOL: '\n',
};
}
get originalDiffModel() {
return {
url: this.originalModel.uri.toString(),
versionId: this.originalModel.getVersionId(),
lines: this.originalModel.getLinesContent(),
EOL: '\n',
};
}
getModel() { getModel() {
return this.model; return this.model;
} }
...@@ -29,18 +62,21 @@ export default class Model { ...@@ -29,18 +62,21 @@ export default class Model {
return this.originalModel; return this.originalModel;
} }
setAttachedToWorker(val) {
this.attachedToWorker = val;
}
onChange(cb) { onChange(cb) {
this.disposers.set( this.events.set(
this.file.path, this.file.path,
this.model.onDidChangeContent(e => cb(this.model, e)), this.model.onDidChangeContent(e => cb(this.model, e)),
); );
} }
dispose() { dispose() {
this.model.dispose(); this.disposable.dispose();
this.originalModel.dispose();
this.disposers.forEach(disposer => disposer.dispose()); this.events.forEach(disposer => disposer.dispose());
this.disposers.clear(); this.events.clear();
} }
} }
import Disposable from './disposable';
import Model from './model';
export default class ModelManager {
constructor() {
this.disposable = new Disposable();
this.models = new Map();
}
hasCachedModel(path) {
return this.models.has(path);
}
addModel(file) {
if (this.hasCachedModel(file.path)) {
return this.models.get(file.path);
}
const model = new Model(file);
this.models.set(model.path, model);
this.disposable.add(model);
return model;
}
dispose() {
// dispose of all the models
this.disposable.dispose();
this.models.clear();
}
}
...@@ -33,7 +33,7 @@ class DecorationsController { ...@@ -33,7 +33,7 @@ class DecorationsController {
this.editorDecorations.set( this.editorDecorations.set(
model.url, model.url,
editor.instance.deltaDecorations(oldDecorations, decorations), editor.editorInstance.instance.deltaDecorations(oldDecorations, decorations),
); );
} }
......
/* global monaco */ /* global monaco */
import Disposable from '../common/disposable';
import DirtyDiffWorker from './worker'; import DirtyDiffWorker from './worker';
import decorationsController from '../decorations/controller'; import decorationsController from '../decorations/controller';
...@@ -32,27 +33,21 @@ export const decorate = (model, changes) => { ...@@ -32,27 +33,21 @@ export const decorate = (model, changes) => {
}; };
export default class DirtyDiffController { export default class DirtyDiffController {
constructor() { constructor(modelManager) {
this.disposable = new Disposable();
this.editorSimpleWorker = null; this.editorSimpleWorker = null;
this.models = new Map(); this.modelManager = modelManager;
this.worker = new DirtyDiffWorker(); this.disposable.add(this.worker = new DirtyDiffWorker());
} }
attachModel(model) { attachModel(model) {
if (this.models.has(model.getModel().uri.toString())) return; if (model.attachedToWorker) return;
[model.getModel(), model.getOriginalModel()].forEach((iModel) => { [model.getModel(), model.getOriginalModel()].forEach(() => {
this.worker.attachModel({ this.worker.attachModel(model);
url: iModel.uri.toString(),
versionId: iModel.getVersionId(),
lines: iModel.getLinesContent(),
EOL: '\n',
});
}); });
model.onChange((_, e) => this.computeDiff(model, e)); model.onChange((_, e) => this.computeDiff(model, e));
this.models.set(model.getModel().uri.toString(), model);
} }
computeDiff(model, e) { computeDiff(model, e) {
...@@ -66,8 +61,6 @@ export default class DirtyDiffController { ...@@ -66,8 +61,6 @@ export default class DirtyDiffController {
} }
dispose() { dispose() {
this.models.clear(); this.disposable.dispose();
this.worker.dispose();
decorationsController.dispose();
} }
} }
/* global monaco */ /* global monaco */
import Disposable from '../common/disposable';
export default class DirtyDiffWorker { export default class DirtyDiffWorker {
constructor() { constructor() {
this.editorSimpleWorker = null; this.editorSimpleWorker = null;
this.models = new Map(); this.disposable = new Disposable();
this.actions = new Set(); this.actions = new Set();
// eslint-disable-next-line promise/catch-or-return // eslint-disable-next-line promise/catch-or-return
monaco.editor.createWebWorker({ monaco.editor.createWebWorker({
moduleId: 'vs/editor/common/services/editorSimpleWorker', moduleId: 'vs/editor/common/services/editorSimpleWorker',
}).getProxy().then((editorSimpleWorker) => { }).getProxy().then((editorSimpleWorker) => {
this.editorSimpleWorker = editorSimpleWorker; this.disposable.add(this.editorSimpleWorker = editorSimpleWorker);
this.ready(); this.ready();
}); });
} }
...@@ -26,10 +28,11 @@ export default class DirtyDiffWorker { ...@@ -26,10 +28,11 @@ export default class DirtyDiffWorker {
} }
attachModel(model) { attachModel(model) {
if (this.editorSimpleWorker && !this.models.has(model.url)) { if (this.editorSimpleWorker && !model.attachedToWorker) {
this.editorSimpleWorker.acceptNewModel(model); this.editorSimpleWorker.acceptNewModel(model.diffModel);
this.editorSimpleWorker.acceptNewModel(model.originalDiffModel);
this.models.set(model.url, model); model.setAttachedToWorker(true);
} else if (!this.editorSimpleWorker) { } else if (!this.editorSimpleWorker) {
this.actions.add({ this.actions.add({
attachModel: [model], attachModel: [model],
...@@ -40,7 +43,7 @@ export default class DirtyDiffWorker { ...@@ -40,7 +43,7 @@ export default class DirtyDiffWorker {
modelChanged(model, e) { modelChanged(model, e) {
if (this.editorSimpleWorker) { if (this.editorSimpleWorker) {
this.editorSimpleWorker.acceptModelChanged( this.editorSimpleWorker.acceptModelChanged(
model.getModel().uri.toString(), model.url,
e, e,
); );
} else { } else {
...@@ -52,27 +55,23 @@ export default class DirtyDiffWorker { ...@@ -52,27 +55,23 @@ export default class DirtyDiffWorker {
compute(model, cb) { compute(model, cb) {
if (this.editorSimpleWorker) { if (this.editorSimpleWorker) {
// eslint-disable-next-line promise/catch-or-return return this.editorSimpleWorker.computeDiff(
this.editorSimpleWorker.computeDiff( model.originalUrl,
model.getOriginalModel().uri.toString(), model.url,
model.getModel().uri.toString(),
).then(cb); ).then(cb);
} else { }
this.actions.add({ this.actions.add({
compute: [model, cb], compute: [model, cb],
}); });
}
return null;
} }
dispose() { dispose() {
this.models.forEach(model =>
this.editorSimpleWorker.acceptRemovedModel(model.url),
);
this.models.clear();
this.actions.clear(); this.actions.clear();
this.editorSimpleWorker.dispose(); this.disposable.dispose();
this.editorSimpleWorker = null; this.editorSimpleWorker = null;
} }
} }
/* global monaco */ /* global monaco */
import DirtyDiffController from './diff/controller'; import DirtyDiffController from './diff/controller';
import Model from './common/model'; import Disposable from './common/disposable';
import ModelManager from './common/model_manager';
export default class Editor {
static create() {
this.editorInstance = new Editor();
return this.editorInstance;
}
class Editor {
constructor() { constructor() {
this.models = new Map();
this.diffComputers = new Map(); this.diffComputers = new Map();
this.currentModel = null; this.currentModel = null;
this.instance = null; this.instance = null;
this.dirtyDiffController = null; this.dirtyDiffController = null;
this.modelManager = new ModelManager();
this.disposable = new Disposable();
this.disposable.add(this.modelManager);
} }
createInstance(domElement) { createInstance(domElement) {
...@@ -20,19 +30,14 @@ class Editor { ...@@ -20,19 +30,14 @@ class Editor {
scrollBeyondLastLine: false, scrollBeyondLastLine: false,
}); });
this.dirtyDiffController = new DirtyDiffController(); this.dirtyDiffController = new DirtyDiffController(this.modelManager);
this.disposable.add(this.dirtyDiffController, this.instance);
} }
} }
createModel(file) { createModel(file) {
if (this.models.has(file.path)) { return this.modelManager.addModel(file);
return this.models.get(file.path);
}
const model = new Model(file);
this.models.set(file.path, model);
return model;
} }
attachModel(model) { attachModel(model) {
...@@ -51,19 +56,11 @@ class Editor { ...@@ -51,19 +56,11 @@ class Editor {
} }
dispose() { dispose() {
this.disposable.dispose();
// dispose main monaco instance // dispose main monaco instance
if (this.instance) { if (this.instance) {
this.instance.dispose();
this.instance = null; this.instance = null;
} }
// dispose of all the models
this.models.forEach(model => model.dispose());
this.models.clear();
this.dirtyDiffController.dispose();
this.dirtyDiffController = null;
} }
} }
export default new Editor();
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment