stdlib icon indicating copy to clipboard operation
stdlib copied to clipboard

[RFC]: add support for bracketed paste in the REPL

Open kgryte opened this issue 10 months ago • 9 comments

Description

This RFC proposes adding support for bracketed paste in the REPL. Currently, if you were to copy

console.log( 'foo' );
console.log( 'bar' );

into the REPL, you'd get

In [36]: console.log( 'foo' );
foo
console.log( 'bar' );
bar

where, if the pasted content contains a newline character, the expressions will be automatically evaluated.

The idea behind bracketed paste is to recognize pasted content so that a user can inspect and potentially edit pasted content before explicitly executing.

Enabling bracketed paste should be a matter of using escape sequences and then checking for a paste start sequence before executing content and then waiting for the paste to stop by checking for the stop sequence.

Once the REPL exits, we should disable bracketed paste.

Additionally, we should add an option which can be set during REPL instantiation (via the REPL constructor) for enabling/disabling bracketed paste, with the default behavior being enabled.

Related Issues

  • Multi-line editing is a related concern and would be nice to have in order to edit pasted content: https://github.com/stdlib-js/stdlib/issues/2060

Questions

  • Given that bracketed paste is global to a terminal window, do we need to test whether it is already enabled? And if so, avoid disabling on exit? Is this detection even possible?

Other

  • Discussion: https://cirw.in/blog/bracketed-paste

Checklist

  • [X] I have read and understood the Code of Conduct.
  • [X] Searched for existing issues and pull requests.
  • [X] The issue name begins with RFC:.

kgryte avatar Mar 27 '24 07:03 kgryte

Following up on this, now that the REPL supports auto-closing of paired symbols, the ability to paste expressions into the REPL is broken, as auto-closing attempts to automatically insert paired symbols as the expression's character sequence is written to the output stream.

kgryte avatar Apr 22 '24 03:04 kgryte

@Snehil-Shah What's your opinion on how easy this will be to implement?

Atm, attempting to paste multi-line expressions is broken, and it would be nice to, e.g., copy-paste an entire function definition from a file directly into the REPL.

kgryte avatar Jun 21 '24 20:06 kgryte

@kgryte As bracketed paste mode is something terminals support, I think it should be pretty straightforward. We enable bracketed paste. If we receive the escape sequences, we trigger our manual multiline handler till we receive the closing sequence and it's done, but it's all in my head, so I'm not yet aware of the real challenges (if any). And also as you mentioned in OP, we might have to find a way to detect if they already had their terminal in bracketed paste mode.

Snehil-Shah avatar Jun 21 '24 21:06 Snehil-Shah

TMK there isn't a clear way to test or detect if bracketed-paste mode is enabled or not in the terminal. Bracketed paste is supported by the 'terminal' application and so I don't think we can access or even simulate pasting content onto the terminal to test the existing status of bracketed-paste mode.

Here is how other REPLs do it:

  • ipython: They have a magic command called %paste which directly takes text that is currently on the user's clipboard and inserts it onto their input. And they follow all sorts of hacks to achieve this. IMO this is unreliable and might not work all the time.

  • node: They don't have an explicit paste mode, but their .editor command (which we have discussed before) can achieve this. Btw .editor command doesn't actually allow you to go back to previous lines and "edit" them, all it does is override the ENTER keypress to add a new line instead of executing the expression.

  • python's new REPL (3.13): It uses bracketed paste mode here. Now I don't understand much of the code but it seems like they enable bracketed paste when starting the Console class and disable it when exiting. There is no detection of any sort. I am not entirely sure, but this test confirms my understanding ig. It also has a "paste mode", but honestly it's pretty much the same as node's .editor mode. You press F3 to turn it on and you enter paste mode, where ENTER keypresses are overriden to add a new line. The only difference is python supports multiline editing so you can edit. To exit "paste mode" you press F3 again. Python's paste mode can be pretty much used as a multiline editor command.

Snehil-Shah avatar Jun 28 '24 20:06 Snehil-Shah

I wonder if we could detect by silently testing whether bracketed paste works by attempting to paste and checking against expected output. I would imagine that the REPL should behave one way if bracketed paste is enabled and another if disabled. Maybe we could rely on heuristics?

kgryte avatar Jun 29 '24 01:06 kgryte

That's the thing, I don't think there is a way to simulate the action of pasting into the terminal if that's what you are suggesting..

Snehil-Shah avatar Jun 29 '24 01:06 Snehil-Shah

Yeah, that was what I was wondering. Hmm. Okay, maybe we should have a setting which a user can set to explicitly enable/disable bracketed paste.

Additionally, we should add an option which can be set during REPL instantiation (via the REPL constructor) for enabling/disabling bracketed paste, with the default behavior being enabled.

kgryte avatar Jun 29 '24 02:06 kgryte

I think it would be better if we don't have a default for this setting as we don't want to automatically/magically mess with their terminal's global state unless they specifically want it to?

Although python 3.13 REPL does enable it by default judging from their code and the test I linked above.

Snehil-Shah avatar Jun 29 '24 02:06 Snehil-Shah

My sense is that it is preferable that things just work out of the box. In which case, at least in TTY, we should enable by default. A user can explicitly opt-out during instantiation. We still need to add CLI configurability, but this can be addressed when we add CLI option support for other REPL settings.

kgryte avatar Jun 29 '24 08:06 kgryte