javascriptnode.jsreadlineread-eval-print-loop

Handling auto indent in Node.js REPL when copy pasting


I need general idea how to solve my problem. I have REPL for LIPS my Scheme based LISP in JavaScript and I have node.js REPL using readline. The last thing I need to solve is to fix double indent when I'm copy paste snippet of code that already have indent.

I have code like this:

var highlight = require('../../prism-cli/index.js'); // temporary local copy
rl._writeToOutput = function _writeToOutput(stringToWrite) {
    rl.output.write(highlight(stringToWrite, 'scheme', true));
};
process.stdin.on('keypress', (c, k) => {
    setTimeout(function() {
        rl._refreshLine(); // force refresh colors
    }, 0);
});
boostrap(interp).then(function() {
    rl.on('line', function(line) {
        code += line + '\n';
        try {
            if (balanced_parenthesis(code)) {
                rl.pause();
                prev_eval = prev_eval.then(function() {
                    var result = run(code, interp);
                    code = '';
                    return result;
                }).then(function(result) {
                    if (process.stdin.isTTY) {
                        print(result);
                        if (newline) {
                            // readline don't work with not endend lines
                            // it ignore those so we end then ourselfs
                            process.stdout.write("\n");
                            newline = false;
                        }
                        if (multiline) {
                            rl.setPrompt(prompt);
                            multiline = false;
                        }
                        rl.prompt();
                    }
                    rl.resume();
                }).catch(function() {
                    if (process.stdin.isTTY) {
                        if (multiline) {
                            rl.setPrompt(prompt);
                            multiline = false;
                        }
                        rl.prompt();
                    }
                });
            } else {
                multiline = true;
                var ind = indent(code, 2, prompt.length - continuePrompt.length);
                rl.setPrompt(continuePrompt);
                rl.prompt();
                var spaces = new Array(ind + 1).join(' ');
                if (terminal) {
                    rl.write(spaces);
                } else {
                    process.stdout.write(spaces);
                    code += spaces;
                }
            }
        } catch (e) {
            console.error(e.message);
            code = '';
            rl.prompt();
        }
    });
}).catch(function() {
    console.error('Internal Error: boostrap filed');
});

indent function calculate number of spaces that need to be added in next line, this works fine when I'm typing the code by hand but when I'm copy pasting code with indent I end up with double indent.

I'm seeking solution for fixing this issue, I'm fine with the solution that edit the text in terminal stdout and rewrite each line with removing the spaces after the text is entered. I can be after each line I can correct the previous line, but don't know how.

I would also like to know if there is a way to detect if there was space typed by the user (actual keypress).

I can't check if line have spaces at the beginning because the indent happen before actual line.


Solution

  • Actually a proper way was to use Paste Bracket Mode that I've added to Node.js. It's available in:

    To use paste bracket in Node you need:

    enable the mode:

    process.stdout.write('\x1b[?2004h');
    

    And add this code:

    let cmd = '';
    const rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
      prompt
    });
    
    process.stdin.on('keypress', (c, k) => {
      if (k?.name?.match(/^paste-/)) {
        cmd += k.sequence;
      }
    });
    
    rl.on('line', function(line) {
        cmd += line;
    });
    
    

    So the paste bracketing appear in output code that you need to handle.

    The pasted text will be between: \x1b\[200~ and \x1b\[201~ ANSI Escape codes, when using Node.js readline. Note that node readline is not the same as GNU readline.

    If you want full story and more self-contained example read this article: