Table of contents
Intro
This post is continuation of the previous post, which you can see here
Restrict Editable Area in Monaco Editor
Pranom Vignesh ・ Aug 17 '20
What's new?
This time granular editing
is made possible by giving set of instructions to the script, which then creates a regex
in runtime to validate the output
Process is simple; if regex is matched , output will be left as such, if not then content will be set to its previous state (undo operation)
Demo - click here
Instructions
There are 2 types of instructions that can provided to the script
- editableArea - space defined to edit a portion of single line
- multiLineEditableArea - space defined to edit multiple lines
Fallback Content
This content can be given as so that when the output is rendered default content will be present in place of the editable area comment
eg : /* editableArea=fallbackContent */
ID
This id can be used to reference the output and whenever the editor content changes, a mapping object is generated
eg : /* editableArea#id */
This fallback content and id is applicable for both single line and multiline editable
Thus, places other than the editable area are not allowed to be edited by the user
Under the hood
function restrictEditArea (value) {
const editable = (() => {
const regexObjects = {};
const labels = [];
const generateRegexUsing = (label, consumeSpace = false) => new RegExp((consumeSpace?"\\^\\s*":"")+"\\/\\*\\s*(" + label + ")(#([^#]+?))?\\s*(=\\s*(.+?))?\\s*\\*\\/"+(consumeSpace?"\\s*\\$"+"\\"+"\\n":""), "g")
return {
add: (name, label, regexReplacer, { consumeSpace } = {}) => {
regexObjects[name] = {
valueRegex : generateRegexUsing(label),
regex: generateRegexUsing(label, consumeSpace),
idIndex: 3,
fallbackContentIndex: 5,
regexReplacer: regexReplacer
}
labels.indexOf(label) === -1 && labels.push(label);
return regexObjects[name];
},
getAll: () => regexObjects,
getIdReplacerRegex: () => generateRegexUsing(labels.join('|'))
}
})();
editable.add('singleLine', 'editableArea', '(.*?)')
editable.add('multiLine', 'multiLineEditableArea', '(^.*?$\\n)*', { consumeSpace: true })
const generateRegexFromValue = (string, {
singleLine,
multiLine
}, idReplacer) => {
let valueToSet = string;
let regexString = string;
let map = {};
let matchCount = 0;
const regexFor = {
brackets: /(\(|\)|\{|\}|\[|\])/g,
newLine: /\n/g,
blankSpace: /\s/g
}
valueToSet = valueToSet.replace(singleLine.valueRegex, "$" + singleLine.fallbackContentIndex)
valueToSet = valueToSet.replace(multiLine.valueRegex, "$" + multiLine.fallbackContentIndex)
regexString = regexString.replace(regexFor.brackets, '\\$1'); //! This order matters
regexString = '^'+regexString.split(regexFor.newLine).join('$\\n^')+'$';
regexString = regexString.replace(singleLine.regex, singleLine.regexReplacer)
regexString = regexString.replace(multiLine.regex, multiLine.regexReplacer)
string.replace(idReplacer, function (...matches) {
map[matchCount++] = matches[3];
})
return {
valueToSet: valueToSet,
regexForValidation: new RegExp(regexString, 'm'),
map: map
}
}
return generateRegexFromValue(value, editable.getAll(), editable.getIdReplacerRegex())
}
This can be a workaround to solve this issue
Provide ability to block editing specific lines #953
Monaco is a great editor for providing programmatic interfaces for users to an application.
One feature that'd significantly help with the user experience is to make specific lines read-only, such that user can enter their code within a specific block (e.g., between a function block).
Would it be possible to include this as a core features/API of the editor?
Future ideas
Will try to publish this as an npm package
so that it will be accessible for everyone
Actual Code available in
Top comments (0)