debian-mirror-gitlab/app/assets/javascripts/ide/lib/editor.js

245 lines
6 KiB
JavaScript
Raw Normal View History

2020-04-22 19:07:51 +05:30
import { debounce } from 'lodash';
2020-06-23 00:09:42 +05:30
import { editor as monacoEditor, KeyCode, KeyMod, Range } from 'monaco-editor';
2018-05-09 12:01:36 +05:30
import DecorationsController from './decorations/controller';
import DirtyDiffController from './diff/controller';
import Disposable from './common/disposable';
import ModelManager from './common/model_manager';
2020-06-23 00:09:42 +05:30
import { editorOptions, defaultEditorOptions, defaultDiffEditorOptions } from './editor_options';
2020-03-13 15:44:24 +05:30
import { themes } from './themes';
2020-05-24 23:13:21 +05:30
import languages from './languages';
2020-07-28 23:09:34 +05:30
import schemas from './schemas';
2018-10-15 14:42:47 +05:30
import keymap from './keymap.json';
2020-03-13 15:44:24 +05:30
import { clearDomElement } from '~/editor/utils';
2020-07-28 23:09:34 +05:30
import { registerLanguages, registerSchemas } from '../utils';
2018-05-09 12:01:36 +05:30
2020-03-13 15:44:24 +05:30
function setupThemes() {
themes.forEach(theme => {
monacoEditor.defineTheme(theme.name, theme.data);
});
2018-11-08 19:23:39 +05:30
}
2018-05-09 12:01:36 +05:30
export default class Editor {
2020-10-24 23:57:45 +05:30
static create(...args) {
2018-11-08 19:23:39 +05:30
if (!this.editorInstance) {
2020-10-24 23:57:45 +05:30
this.editorInstance = new Editor(...args);
2018-11-08 19:23:39 +05:30
}
2018-05-09 12:01:36 +05:30
return this.editorInstance;
}
2020-10-24 23:57:45 +05:30
constructor(store, options = {}) {
2018-05-09 12:01:36 +05:30
this.currentModel = null;
this.instance = null;
this.dirtyDiffController = null;
this.disposable = new Disposable();
2018-11-08 19:23:39 +05:30
this.modelManager = new ModelManager();
2018-05-09 12:01:36 +05:30
this.decorationsController = new DecorationsController(this);
2020-03-13 15:44:24 +05:30
this.options = {
...defaultEditorOptions,
...options,
};
2020-06-23 00:09:42 +05:30
this.diffOptions = {
...defaultDiffEditorOptions,
...options,
};
2020-10-24 23:57:45 +05:30
this.store = store;
2018-05-09 12:01:36 +05:30
2020-03-13 15:44:24 +05:30
setupThemes();
2020-05-24 23:13:21 +05:30
registerLanguages(...languages);
2018-05-09 12:01:36 +05:30
2020-07-28 23:09:34 +05:30
if (gon.features?.schemaLinting) {
registerSchemas(...schemas);
}
2020-04-22 19:07:51 +05:30
this.debouncedUpdate = debounce(() => {
2018-05-09 12:01:36 +05:30
this.updateDimensions();
}, 200);
}
createInstance(domElement) {
if (!this.instance) {
clearDomElement(domElement);
this.disposable.add(
2018-11-08 19:23:39 +05:30
(this.instance = monacoEditor.create(domElement, {
2020-03-13 15:44:24 +05:30
...this.options,
2018-05-09 12:01:36 +05:30
})),
(this.dirtyDiffController = new DirtyDiffController(
this.modelManager,
this.decorationsController,
)),
);
2018-10-15 14:42:47 +05:30
this.addCommands();
2018-05-09 12:01:36 +05:30
window.addEventListener('resize', this.debouncedUpdate, false);
}
}
2020-06-23 00:09:42 +05:30
createDiffInstance(domElement) {
2018-05-09 12:01:36 +05:30
if (!this.instance) {
clearDomElement(domElement);
this.disposable.add(
2018-11-08 19:23:39 +05:30
(this.instance = monacoEditor.createDiffEditor(domElement, {
2020-06-23 00:09:42 +05:30
...this.diffOptions,
2018-05-09 12:01:36 +05:30
renderSideBySide: Editor.renderSideBySide(domElement),
})),
);
2018-10-15 14:42:47 +05:30
this.addCommands();
2018-05-09 12:01:36 +05:30
window.addEventListener('resize', this.debouncedUpdate, false);
}
}
2018-10-15 14:42:47 +05:30
createModel(file, head = null) {
return this.modelManager.addModel(file, head);
2018-05-09 12:01:36 +05:30
}
attachModel(model) {
if (this.isDiffEditorType) {
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);
}
attachMergeRequestModel(model) {
this.instance.setModel({
original: model.getBaseModel(),
modified: model.getModel(),
});
2018-11-08 19:23:39 +05:30
monacoEditor.createDiffNavigator(this.instance, {
2018-05-09 12:01:36 +05:30
alwaysRevealFirst: true,
});
}
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();
this.updateDiffView();
}
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)));
}
updateDiffView() {
if (!this.isDiffEditorType) return;
this.instance.updateOptions({
renderSideBySide: Editor.renderSideBySide(this.instance.getDomNode()),
});
}
2020-06-23 00:09:42 +05:30
replaceSelectedText(text) {
let selection = this.instance.getSelection();
const range = new Range(
selection.startLineNumber,
selection.startColumn,
selection.endLineNumber,
selection.endColumn,
);
this.instance.executeEdits('', [{ range, text }]);
selection = this.instance.getSelection();
this.instance.setPosition({ lineNumber: selection.endLineNumber, column: selection.endColumn });
}
2018-05-09 12:01:36 +05:30
get isDiffEditorType() {
return this.instance.getEditorType() === 'vs.editor.IDiffEditor';
}
static renderSideBySide(domElement) {
return domElement.offsetWidth >= 700;
}
2018-10-15 14:42:47 +05:30
addCommands() {
2020-10-24 23:57:45 +05:30
const { store } = this;
2018-10-15 14:42:47 +05:30
const getKeyCode = key => {
const monacoKeyMod = key.indexOf('KEY_') === 0;
2018-11-08 19:23:39 +05:30
return monacoKeyMod ? KeyCode[key] : KeyMod[key];
2018-10-15 14:42:47 +05:30
};
keymap.forEach(command => {
const keybindings = command.bindings.map(binding => {
const keys = binding.split('+');
// eslint-disable-next-line no-bitwise
return keys.length > 1 ? getKeyCode(keys[0]) | getKeyCode(keys[1]) : getKeyCode(keys[0]);
});
this.instance.addAction({
id: command.id,
label: command.label,
keybindings,
run() {
store.dispatch(command.action.name, command.action.params);
return null;
},
});
});
}
2018-05-09 12:01:36 +05:30
}