added disposable manager
added model manager [ci skip]
This commit is contained in:
parent
c90b520d79
commit
eb8a609519
8 changed files with 152 additions and 80 deletions
|
@ -3,13 +3,15 @@
|
|||
import { mapGetters, mapActions } from 'vuex';
|
||||
import flash from '../../flash';
|
||||
import monacoLoader from '../monaco_loader';
|
||||
import editor from '../lib/editor';
|
||||
import Editor from '../lib/editor';
|
||||
|
||||
export default {
|
||||
destroyed() {
|
||||
editor.dispose();
|
||||
this.editor.dispose();
|
||||
},
|
||||
mounted() {
|
||||
this.editor = Editor.create();
|
||||
|
||||
if (this.monaco) {
|
||||
this.initMonaco();
|
||||
} else {
|
||||
|
@ -26,11 +28,11 @@ export default {
|
|||
initMonaco() {
|
||||
if (this.shouldHideEditor) return;
|
||||
|
||||
editor.clearEditor();
|
||||
this.editor.clearEditor();
|
||||
|
||||
this.getRawFileData(this.activeFile)
|
||||
.then(() => {
|
||||
editor.createInstance(this.$el);
|
||||
this.editor.createInstance(this.$el);
|
||||
})
|
||||
.then(() => this.setupEditor())
|
||||
.catch(() => flash('Error setting up monaco. Please try again.'));
|
||||
|
@ -38,9 +40,9 @@ export default {
|
|||
setupEditor() {
|
||||
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) => {
|
||||
this.changeFileContent({
|
||||
file: this.activeFile,
|
||||
|
|
14
app/assets/javascripts/repo/lib/common/disposable.js
Normal file
14
app/assets/javascripts/repo/lib/common/disposable.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
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();
|
||||
}
|
||||
}
|
|
@ -1,26 +1,59 @@
|
|||
/* global monaco */
|
||||
import Disposable from './disposable';
|
||||
|
||||
export default class Model {
|
||||
constructor(file) {
|
||||
this.disposable = new Disposable();
|
||||
this.file = file;
|
||||
this.content = file.content !== '' ? file.content : file.raw;
|
||||
this.originalModel = monaco.editor.createModel(
|
||||
this.content,
|
||||
undefined,
|
||||
new monaco.Uri(null, null, `original/${this.file.path}`),
|
||||
|
||||
this.disposable.add(
|
||||
this.originalModel = monaco.editor.createModel(
|
||||
this.content,
|
||||
undefined,
|
||||
new monaco.Uri(null, null, `original/${this.file.path}`),
|
||||
),
|
||||
this.model = monaco.editor.createModel(
|
||||
this.content,
|
||||
undefined,
|
||||
new monaco.Uri(null, null, this.file.path),
|
||||
),
|
||||
);
|
||||
this.model = monaco.editor.createModel(
|
||||
this.content,
|
||||
undefined,
|
||||
new monaco.Uri(null, null, this.file.path),
|
||||
);
|
||||
this.disposers = new Map();
|
||||
|
||||
this.attachedToWorker = false;
|
||||
this.events = new Map();
|
||||
}
|
||||
|
||||
get url() {
|
||||
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() {
|
||||
return this.model;
|
||||
}
|
||||
|
@ -29,18 +62,21 @@ export default class Model {
|
|||
return this.originalModel;
|
||||
}
|
||||
|
||||
setAttachedToWorker(val) {
|
||||
this.attachedToWorker = val;
|
||||
}
|
||||
|
||||
onChange(cb) {
|
||||
this.disposers.set(
|
||||
this.events.set(
|
||||
this.file.path,
|
||||
this.model.onDidChangeContent(e => cb(this.model, e)),
|
||||
);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.model.dispose();
|
||||
this.originalModel.dispose();
|
||||
this.disposable.dispose();
|
||||
|
||||
this.disposers.forEach(disposer => disposer.dispose());
|
||||
this.disposers.clear();
|
||||
this.events.forEach(disposer => disposer.dispose());
|
||||
this.events.clear();
|
||||
}
|
||||
}
|
||||
|
|
31
app/assets/javascripts/repo/lib/common/model_manager.js
Normal file
31
app/assets/javascripts/repo/lib/common/model_manager.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
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 {
|
|||
|
||||
this.editorDecorations.set(
|
||||
model.url,
|
||||
editor.instance.deltaDecorations(oldDecorations, decorations),
|
||||
editor.editorInstance.instance.deltaDecorations(oldDecorations, decorations),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* global monaco */
|
||||
import Disposable from '../common/disposable';
|
||||
import DirtyDiffWorker from './worker';
|
||||
import decorationsController from '../decorations/controller';
|
||||
|
||||
|
@ -32,27 +33,21 @@ export const decorate = (model, changes) => {
|
|||
};
|
||||
|
||||
export default class DirtyDiffController {
|
||||
constructor() {
|
||||
constructor(modelManager) {
|
||||
this.disposable = new Disposable();
|
||||
this.editorSimpleWorker = null;
|
||||
this.models = new Map();
|
||||
this.worker = new DirtyDiffWorker();
|
||||
this.modelManager = modelManager;
|
||||
this.disposable.add(this.worker = new DirtyDiffWorker());
|
||||
}
|
||||
|
||||
attachModel(model) {
|
||||
if (this.models.has(model.getModel().uri.toString())) return;
|
||||
if (model.attachedToWorker) return;
|
||||
|
||||
[model.getModel(), model.getOriginalModel()].forEach((iModel) => {
|
||||
this.worker.attachModel({
|
||||
url: iModel.uri.toString(),
|
||||
versionId: iModel.getVersionId(),
|
||||
lines: iModel.getLinesContent(),
|
||||
EOL: '\n',
|
||||
});
|
||||
[model.getModel(), model.getOriginalModel()].forEach(() => {
|
||||
this.worker.attachModel(model);
|
||||
});
|
||||
|
||||
model.onChange((_, e) => this.computeDiff(model, e));
|
||||
|
||||
this.models.set(model.getModel().uri.toString(), model);
|
||||
}
|
||||
|
||||
computeDiff(model, e) {
|
||||
|
@ -66,8 +61,6 @@ export default class DirtyDiffController {
|
|||
}
|
||||
|
||||
dispose() {
|
||||
this.models.clear();
|
||||
this.worker.dispose();
|
||||
decorationsController.dispose();
|
||||
this.disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
/* global monaco */
|
||||
import Disposable from '../common/disposable';
|
||||
|
||||
export default class DirtyDiffWorker {
|
||||
constructor() {
|
||||
this.editorSimpleWorker = null;
|
||||
this.models = new Map();
|
||||
this.disposable = new Disposable();
|
||||
this.actions = new Set();
|
||||
|
||||
// eslint-disable-next-line promise/catch-or-return
|
||||
monaco.editor.createWebWorker({
|
||||
moduleId: 'vs/editor/common/services/editorSimpleWorker',
|
||||
}).getProxy().then((editorSimpleWorker) => {
|
||||
this.editorSimpleWorker = editorSimpleWorker;
|
||||
this.disposable.add(this.editorSimpleWorker = editorSimpleWorker);
|
||||
this.ready();
|
||||
});
|
||||
}
|
||||
|
@ -26,10 +28,11 @@ export default class DirtyDiffWorker {
|
|||
}
|
||||
|
||||
attachModel(model) {
|
||||
if (this.editorSimpleWorker && !this.models.has(model.url)) {
|
||||
this.editorSimpleWorker.acceptNewModel(model);
|
||||
if (this.editorSimpleWorker && !model.attachedToWorker) {
|
||||
this.editorSimpleWorker.acceptNewModel(model.diffModel);
|
||||
this.editorSimpleWorker.acceptNewModel(model.originalDiffModel);
|
||||
|
||||
this.models.set(model.url, model);
|
||||
model.setAttachedToWorker(true);
|
||||
} else if (!this.editorSimpleWorker) {
|
||||
this.actions.add({
|
||||
attachModel: [model],
|
||||
|
@ -40,7 +43,7 @@ export default class DirtyDiffWorker {
|
|||
modelChanged(model, e) {
|
||||
if (this.editorSimpleWorker) {
|
||||
this.editorSimpleWorker.acceptModelChanged(
|
||||
model.getModel().uri.toString(),
|
||||
model.url,
|
||||
e,
|
||||
);
|
||||
} else {
|
||||
|
@ -52,27 +55,23 @@ export default class DirtyDiffWorker {
|
|||
|
||||
compute(model, cb) {
|
||||
if (this.editorSimpleWorker) {
|
||||
// eslint-disable-next-line promise/catch-or-return
|
||||
this.editorSimpleWorker.computeDiff(
|
||||
model.getOriginalModel().uri.toString(),
|
||||
model.getModel().uri.toString(),
|
||||
return this.editorSimpleWorker.computeDiff(
|
||||
model.originalUrl,
|
||||
model.url,
|
||||
).then(cb);
|
||||
} else {
|
||||
this.actions.add({
|
||||
compute: [model, cb],
|
||||
});
|
||||
}
|
||||
|
||||
this.actions.add({
|
||||
compute: [model, cb],
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.models.forEach(model =>
|
||||
this.editorSimpleWorker.acceptRemovedModel(model.url),
|
||||
);
|
||||
this.models.clear();
|
||||
|
||||
this.actions.clear();
|
||||
|
||||
this.editorSimpleWorker.dispose();
|
||||
this.disposable.dispose();
|
||||
this.editorSimpleWorker = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,24 @@
|
|||
/* global monaco */
|
||||
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() {
|
||||
this.models = new Map();
|
||||
this.diffComputers = new Map();
|
||||
this.currentModel = null;
|
||||
this.instance = null;
|
||||
this.dirtyDiffController = null;
|
||||
this.modelManager = new ModelManager();
|
||||
this.disposable = new Disposable();
|
||||
|
||||
this.disposable.add(this.modelManager);
|
||||
}
|
||||
|
||||
createInstance(domElement) {
|
||||
|
@ -20,19 +30,14 @@ class Editor {
|
|||
scrollBeyondLastLine: false,
|
||||
});
|
||||
|
||||
this.dirtyDiffController = new DirtyDiffController();
|
||||
this.dirtyDiffController = new DirtyDiffController(this.modelManager);
|
||||
|
||||
this.disposable.add(this.dirtyDiffController, this.instance);
|
||||
}
|
||||
}
|
||||
|
||||
createModel(file) {
|
||||
if (this.models.has(file.path)) {
|
||||
return this.models.get(file.path);
|
||||
}
|
||||
|
||||
const model = new Model(file);
|
||||
this.models.set(file.path, model);
|
||||
|
||||
return model;
|
||||
return this.modelManager.addModel(file);
|
||||
}
|
||||
|
||||
attachModel(model) {
|
||||
|
@ -51,19 +56,11 @@ class Editor {
|
|||
}
|
||||
|
||||
dispose() {
|
||||
this.disposable.dispose();
|
||||
|
||||
// dispose main monaco instance
|
||||
if (this.instance) {
|
||||
this.instance.dispose();
|
||||
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();
|
||||
|
|
Loading…
Reference in a new issue