debian-mirror-gitlab/app/assets/javascripts/editor/extensions/source_editor_webide_ext.js
2022-01-26 12:08:38 +05:30

187 lines
5 KiB
JavaScript

/**
* A WebIDE Extension options for Source Editor
* @typedef {Object} WebIDEExtensionOptions
* @property {Object} modelManager The root manager for WebIDE models
* @property {Object} store The state store for communication
* @property {Object} file
* @property {Object} options The Monaco editor options
*/
import { debounce } from 'lodash';
import { KeyCode, KeyMod, Range } from 'monaco-editor';
import { EDITOR_TYPE_DIFF } from '~/editor/constants';
import Disposable from '~/ide/lib/common/disposable';
import { editorOptions } from '~/ide/lib/editor_options';
import keymap from '~/ide/lib/keymap.json';
const isDiffEditorType = (instance) => {
return instance.getEditorType() === EDITOR_TYPE_DIFF;
};
export const UPDATE_DIMENSIONS_DELAY = 200;
const defaultOptions = {
modelManager: undefined,
store: undefined,
file: undefined,
options: {},
};
const addActions = (instance, store) => {
const getKeyCode = (key) => {
const monacoKeyMod = key.indexOf('KEY_') === 0;
return monacoKeyMod ? KeyCode[key] : KeyMod[key];
};
keymap.forEach((command) => {
const { bindings, id, label, action } = command;
const keybindings = 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]);
});
instance.addAction({
id,
label,
keybindings,
run() {
store.dispatch(action.name, action.params);
return null;
},
});
});
};
const renderSideBySide = (domElement) => {
return domElement.offsetWidth >= 700;
};
const updateInstanceDimensions = (instance) => {
instance.layout();
if (isDiffEditorType(instance)) {
instance.updateOptions({
renderSideBySide: renderSideBySide(instance.getDomNode()),
});
}
};
export class EditorWebIdeExtension {
static get extensionName() {
return 'EditorWebIde';
}
/**
* Set up the WebIDE extension for Source Editor
* @param {module:source_editor_instance~EditorInstance} instance - The Source Editor instance
* @param {WebIDEExtensionOptions} setupOptions
*/
onSetup(instance, setupOptions = defaultOptions) {
this.modelManager = setupOptions.modelManager;
this.store = setupOptions.store;
this.file = setupOptions.file;
this.options = setupOptions.options;
this.disposable = new Disposable();
this.debouncedUpdate = debounce(() => {
updateInstanceDimensions(instance);
}, UPDATE_DIMENSIONS_DELAY);
addActions(instance, setupOptions.store);
}
onUse(instance) {
window.addEventListener('resize', this.debouncedUpdate, false);
instance.onDidDispose(() => {
this.onUnuse();
});
}
onUnuse() {
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();
} catch (e) {
if (process.env.NODE_ENV !== 'test') {
// eslint-disable-next-line no-console
console.error(e);
}
}
}
provides() {
return {
createModel: (instance, file, head = null) => {
return this.modelManager.addModel(file, head);
},
attachModel: (instance, model) => {
if (isDiffEditorType(instance)) {
instance.setModel({
original: model.getOriginalModel(),
modified: model.getModel(),
});
return;
}
instance.setModel(model.getModel());
instance.updateOptions(
editorOptions.reduce((acc, obj) => {
Object.keys(obj).forEach((key) => {
Object.assign(acc, {
[key]: obj[key](model),
});
});
return acc;
}, {}),
);
},
attachMergeRequestModel: (instance, model) => {
instance.setModel({
original: model.getBaseModel(),
modified: model.getModel(),
});
},
updateDimensions: (instance) => updateInstanceDimensions(instance),
setPos: (instance, { lineNumber, column }) => {
instance.revealPositionInCenter({
lineNumber,
column,
});
instance.setPosition({
lineNumber,
column,
});
},
onPositionChange: (instance, cb) => {
if (typeof instance.onDidChangeCursorPosition !== 'function') {
return;
}
this.disposable.add(instance.onDidChangeCursorPosition((e) => cb(instance, e)));
},
replaceSelectedText: (instance, text) => {
let selection = instance.getSelection();
const range = new Range(
selection.startLineNumber,
selection.startColumn,
selection.endLineNumber,
selection.endColumn,
);
instance.executeEdits('', [{ range, text }]);
selection = instance.getSelection();
instance.setPosition({ lineNumber: selection.endLineNumber, column: selection.endColumn });
},
};
}
}