diff options
Diffstat (limited to 'app/assets/javascripts/ide/lib/editor.js')
-rw-r--r-- | app/assets/javascripts/ide/lib/editor.js | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/app/assets/javascripts/ide/lib/editor.js b/app/assets/javascripts/ide/lib/editor.js new file mode 100644 index 00000000000..38de2fe2b27 --- /dev/null +++ b/app/assets/javascripts/ide/lib/editor.js @@ -0,0 +1,164 @@ +import _ from 'underscore'; +import DecorationsController from './decorations/controller'; +import DirtyDiffController from './diff/controller'; +import Disposable from './common/disposable'; +import ModelManager from './common/model_manager'; +import editorOptions, { defaultEditorOptions } from './editor_options'; +import gitlabTheme from './themes/gl_theme'; + +export const clearDomElement = el => { + if (!el || !el.firstChild) return; + + while (el.firstChild) { + el.removeChild(el.firstChild); + } +}; + +export default class Editor { + static create(monaco) { + if (this.editorInstance) return this.editorInstance; + + this.editorInstance = new Editor(monaco); + + return this.editorInstance; + } + + constructor(monaco) { + this.monaco = monaco; + this.currentModel = null; + this.instance = null; + this.dirtyDiffController = null; + this.disposable = new Disposable(); + this.modelManager = new ModelManager(this.monaco); + this.decorationsController = new DecorationsController(this); + + this.setupMonacoTheme(); + + this.debouncedUpdate = _.debounce(() => { + this.updateDimensions(); + }, 200); + } + + createInstance(domElement) { + if (!this.instance) { + clearDomElement(domElement); + + this.disposable.add( + (this.instance = this.monaco.editor.create(domElement, { + ...defaultEditorOptions, + })), + (this.dirtyDiffController = new DirtyDiffController( + this.modelManager, + this.decorationsController, + )), + ); + + window.addEventListener('resize', this.debouncedUpdate, false); + } + } + + createDiffInstance(domElement) { + if (!this.instance) { + clearDomElement(domElement); + + this.disposable.add( + (this.instance = this.monaco.editor.createDiffEditor(domElement, { + ...defaultEditorOptions, + readOnly: true, + })), + ); + + window.addEventListener('resize', this.debouncedUpdate, false); + } + } + + createModel(file) { + return this.modelManager.addModel(file); + } + + attachModel(model) { + if (this.instance.getEditorType() === 'vs.editor.IDiffEditor') { + this.instance.setModel({ + original: model.getOriginalModel(), + modified: model.getModel(), + }); + + return; + } + + this.instance.setModel(model.getModel()); + if (this.dirtyDiffController) this.dirtyDiffController.attachModel(model); + + this.currentModel = model; + + this.instance.updateOptions( + editorOptions.reduce((acc, obj) => { + Object.keys(obj).forEach(key => { + Object.assign(acc, { + [key]: obj[key](model), + }); + }); + return acc; + }, {}), + ); + + if (this.dirtyDiffController) this.dirtyDiffController.reDecorate(model); + } + + setupMonacoTheme() { + this.monaco.editor.defineTheme( + gitlabTheme.themeName, + gitlabTheme.monacoTheme, + ); + + this.monaco.editor.setTheme('gitlab'); + } + + clearEditor() { + if (this.instance) { + this.instance.setModel(null); + } + } + + dispose() { + window.removeEventListener('resize', this.debouncedUpdate); + + // catch any potential errors with disposing the error + // this is mainly for tests caused by elements not existing + try { + this.disposable.dispose(); + + this.instance = null; + } catch (e) { + this.instance = null; + + if (process.env.NODE_ENV !== 'test') { + // eslint-disable-next-line no-console + console.error(e); + } + } + } + + updateDimensions() { + this.instance.layout(); + } + + setPosition({ lineNumber, column }) { + this.instance.revealPositionInCenter({ + lineNumber, + column, + }); + this.instance.setPosition({ + lineNumber, + column, + }); + } + + onPositionChange(cb) { + if (!this.instance.onDidChangeCursorPosition) return; + + this.disposable.add( + this.instance.onDidChangeCursorPosition(e => cb(this.instance, e)), + ); + } +} |