Ace Editor: Lock or Readonly Code Segment

后端 未结 3 2026
深忆病人
深忆病人 2020-12-30 03:38

Using the Ace Code Editor can I lock or make readonly a segment of code but still allow other lines of code to be written or edited during a session?

相关标签:
3条回答
  • 2020-12-30 03:42

    Here is the start of a solution:

    $(function() {
        var editor     = ace.edit("editor1")
            , session  = editor.getSession()
            , Range    = require("ace/range").Range
            , range    = new Range(1, 4, 1, 10)
            , markerId = session.addMarker(range, "readonly-highlight");
    
        session.setMode("ace/mode/javascript");
        editor.keyBinding.addKeyboardHandler({
            handleKeyboard : function(data, hash, keyString, keyCode, event) {
                if (hash === -1 || (keyCode <= 40 && keyCode >= 37)) return false;
    
                if (intersects(range)) {
                    return {command:"null", passEvent:false};
                }
            }
        });
    
        before(editor, 'onPaste', preventReadonly);
        before(editor, 'onCut',   preventReadonly);
    
        range.start  = session.doc.createAnchor(range.start);
        range.end    = session.doc.createAnchor(range.end);
        range.end.$insertRight = true;
    
        function before(obj, method, wrapper) {
            var orig = obj[method];
            obj[method] = function() {
                var args = Array.prototype.slice.call(arguments);
                return wrapper.call(this, function(){
                    return orig.apply(obj, args);
                }, args);
            }
    
            return obj[method];
        }
    
        function intersects(range) {
            return editor.getSelectionRange().intersects(range);
        }
    
        function preventReadonly(next, args) {
            if (intersects(range)) return;
            next();
        }
    });
    

    see it working in this fiddle: http://jsfiddle.net/bzwheeler/btsxgena/

    The major working pieces are:

    1. create start and end ace anchors which track the location of a 'readonly' portion as the document around it changes.
    2. create a range to encapsulate the anchors
    3. add a custom keyhandler to check if the current impending keypress will affect the readonly range and cancel it if so.
    4. add custom paste/cut handlers to protect against right-click menu and browser menu cut/paste actions
    0 讨论(0)
  • 2020-12-30 03:55

    I suggest something else easier and more reliable to prevent range to be modified (check it!)

    var old$tryReplace = editor.$tryReplace;
    editor.$tryReplace = function(range, replacement) {
        return intersects(range)?null:old$tryReplace.apply(this, arguments);                        
    }
    var session = editor.getSession();
    var oldInsert = session.insert;
    session.insert = function(position, text) {
        return oldInsert.apply(this, [position, outsideRange(position)?text:""]);
    }
    var oldRemove = session.remove;
    session.remove = function(range) {
        return intersects(range)?false:oldRemove.apply(this, arguments);                        
    }
    var oldMoveText = session.moveText;
    session.moveText = function(fromRange, toPosition, copy) {
        if (intersects(fromRange) || !outsideRange(toPosition)) return fromRange;
        return oldMoveText.apply(this, arguments)
    }
    
    outsideRange = function (position) {
        var s0 = range.start;
        if (position.row < s0.row || (position.row == s0.row && position.column <= s0.column)) return true; // position must be before range.start
        var e0 = range.end;
        if (position.row > e0.row || (position.row == e0.row && position.column >= e0.column)) return true; // or after range.end
        return false;
    }
    intersects = function(withRange) {
        var e = withRange.end, s0 = range.start, s = withRange.start, e0 = range.end;
        if (e.row < s0.row || (e.row == s0.row && e.column <= s0.column)) return false; // withRange.end must be before range.start
        if (s.row > e0.row || (s.row == e0.row && s.column >= e0.column)) return false; // or withRange.start must be after range.end
        return true;
    }
    
    0 讨论(0)
  • 2020-12-30 03:59

    You can do it easily by listening to the exec events:

    // Prevent editing first and last line of editor
    editor.commands.on("exec", function(e) { 
      var rowCol = editor.selection.getCursor();
      if ((rowCol.row === 0) || ((rowCol.row + 1) === editor.session.getLength())) {
        e.preventDefault();
        e.stopPropagation();
      }
    });
    

    Source: https://jsfiddle.net/tripflex/y0huvc1b/

    0 讨论(0)
提交回复
热议问题