Repository: kkawakam/rustyline (rust)

Issue:
Pasted multiple lines read as one line
I found one strange thing when running the example.

I am running on a Linux machine, and connected via an ssh session from a windows desktop using putty. Entering text normally works as expected.

However if I have a number of lines in an editor, and copy/paste those into the terminal, somehow they are all considered a single multi-line string (with embedded newlines) rather than multiple lines. Only pressing the enter key on the keyboard terminates the line.

```
 $ cargo run --example example
    Finished dev [unoptimized + debuginfo] target(s) in 0.06s
     Running `target/debug/examples/example`
>> 1
2
3
4


Line: 1
2
3
4

>>

```

At first I thought some kind of line ending difference was causing this, but pasting into a file looks exactly the same as entering newlines manually - they are all seen as 0x0a (\n).

It seems rustyline somehow treats pasted \n characters differently to newline pressed on the keyboard. This doesn't seem to be the case when using other readline implementations.


Pull request:
Bracketed paste can be disabled
Should fix #202

Patch:
diff --git a/src/config.rs b/src/config.rs
index 39802a3..ead493d 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -32,6 +32,8 @@ pub struct Config {
     indent_size: usize,
     /// Check if cursor position is at leftmost before displaying prompt
     check_cursor_position: bool,
+    /// Bracketed paste on unix platform
+    enable_bracketed_paste: bool,
 }
 
 impl Config {
@@ -167,6 +169,13 @@ impl Config {
     pub(crate) fn set_indent_size(&mut self, indent_size: usize) {
         self.indent_size = indent_size;
     }
+
+    /// Bracketed paste on unix platform
+    ///
+    /// By default, it's enabled.
+    pub fn enable_bracketed_paste(&self) -> bool {
+        self.enable_bracketed_paste
+    }
 }
 
 impl Default for Config {
@@ -186,6 +195,7 @@ impl Default for Config {
             tab_stop: 8,
             indent_size: 2,
             check_cursor_position: false,
+            enable_bracketed_paste: true,
         }
     }
 }
@@ -397,6 +407,14 @@ impl Builder {
         self
     }
 
+    /// Enable or disable bracketed paste on unix platform
+    ///
+    /// By default, it's enabled.
+    pub fn bracketed_paste(mut self, enabled: bool) -> Self {
+        self.enable_bracketed_paste(enabled);
+        self
+    }
+
     /// Builds a `Config` with the settings specified so far.
     pub fn build(self) -> Config {
         self.p
@@ -504,4 +522,11 @@ pub trait Configurer {
     fn set_indent_size(&mut self, size: usize) {
         self.config_mut().set_indent_size(size);
     }
+
+    /// Enable or disable bracketed paste on unix platform
+    ///
+    /// By default, it's enabled.
+    fn enable_bracketed_paste(&mut self, enabled: bool) {
+        self.config_mut().enable_bracketed_paste = enabled;
+    }
 }
diff --git a/src/lib.rs b/src/lib.rs
index 1a7f4aa..62be53c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -630,6 +630,7 @@ impl<H: Helper> Editor<H> {
             config.output_stream(),
             config.tab_stop(),
             config.bell_style(),
+            config.enable_bracketed_paste(),
         );
         Self {
             term,
diff --git a/src/tty/mod.rs b/src/tty/mod.rs
index 9f9e728..b1a44b7 100644
--- a/src/tty/mod.rs
+++ b/src/tty/mod.rs
@@ -208,6 +208,7 @@ pub trait Term {
         stream: OutputStreamType,
         tab_stop: usize,
         bell_style: BellStyle,
+        enable_bracketed_paste: bool,
     ) -> Self;
     /// Check if current terminal can provide a rich line-editing user
     /// interface.
diff --git a/src/tty/unix.rs b/src/tty/unix.rs
index 9793d5b..5816805 100644
--- a/src/tty/unix.rs
+++ b/src/tty/unix.rs
@@ -1005,6 +1005,7 @@ pub struct PosixTerminal {
     stream_type: OutputStreamType,
     tab_stop: usize,
     bell_style: BellStyle,
+    enable_bracketed_paste: bool,
 }
 
 impl PosixTerminal {
@@ -1027,6 +1028,7 @@ impl Term for PosixTerminal {
         stream_type: OutputStreamType,
         tab_stop: usize,
         bell_style: BellStyle,
+        enable_bracketed_paste: bool,
     ) -> Self {
         let term = Self {
             unsupported: is_unsupported_term(),
@@ -1036,6 +1038,7 @@ impl Term for PosixTerminal {
             stream_type,
             tab_stop,
             bell_style,
+            enable_bracketed_paste,
         };
         if !term.unsupported && term.stdin_isatty && term.stdstream_isatty {
             install_sigwinch_handler();
@@ -1091,7 +1094,9 @@ impl Term for PosixTerminal {
         termios::tcsetattr(STDIN_FILENO, SetArg::TCSADRAIN, &raw)?;
 
         // enable bracketed paste
-        let out = if let Err(e) = write_and_flush(self.stream_type, BRACKETED_PASTE_ON) {
+        let out = if !self.enable_bracketed_paste {
+            None
+        } else if let Err(e) = write_and_flush(self.stream_type, BRACKETED_PASTE_ON) {
             debug!(target: "rustyline", "Cannot enable bracketed paste: {}", e);
             None
         } else {
diff --git a/src/tty/windows.rs b/src/tty/windows.rs
index 3e827f9..558cca4 100644
--- a/src/tty/windows.rs
+++ b/src/tty/windows.rs
@@ -533,6 +533,7 @@ impl Term for Console {
         stream_type: OutputStreamType,
         _tab_stop: usize,
         bell_style: BellStyle,
+        _enable_bracketed_paste: bool,
     ) -> Console {
         use std::ptr;
         let stdin_handle = get_std_handle(STDIN_FILENO);


Test patch:
diff --git a/src/tty/test.rs b/src/tty/test.rs
index 765d744..d8bed91 100644
--- a/src/tty/test.rs
+++ b/src/tty/test.rs
@@ -149,6 +149,7 @@ impl Term for DummyTerminal {
         _stream: OutputStreamType,
         _tab_stop: usize,
         bell_style: BellStyle,
+        _enable_bracketed_paste: bool,
     ) -> DummyTerminal {
         DummyTerminal {
             keys: Vec::new(),