DEV Community

Pranom Vignesh
Pranom Vignesh

Posted on

Restrict Editable Area in Monaco Editor - Part 2

Table of contents

Intro

This post is continuation of the previous post, which you can see here

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

Demo of Playground

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())
}
Enter fullscreen mode Exit fullscreen mode

This can be a workaround to solve this issue

Provide ability to block editing specific lines #953

sinaa avatar
sinaa posted on

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

GitHub logo Pranomvignesh / constrained-editor-plugin

This project is to restrict the editable area in the monaco-editor

Top comments (0)