diff --git a/Cargo.toml b/Cargo.toml
index 0893b0304..d550917d7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,7 +26,8 @@ all-features = true
# Features
#
[features]
-default = []
+default = ["bracketed-paste"]
+bracketed-paste = []
event-stream = ["futures-core"]
#
diff --git a/examples/event-match-modifiers.rs b/examples/event-match-modifiers.rs
index 183109dea..c3f75e95d 100644
--- a/examples/event-match-modifiers.rs
+++ b/examples/event-match-modifiers.rs
@@ -2,7 +2,7 @@
//!
//! cargo run --example event-match-modifiers
-use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
+use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
fn match_event(read_event: Event) {
match read_event {
diff --git a/examples/event-read.rs b/examples/event-read.rs
index 2a32cefba..fa84c14ba 100644
--- a/examples/event-read.rs
+++ b/examples/event-read.rs
@@ -8,8 +8,8 @@ use crossterm::event::poll;
use crossterm::{
cursor::position,
event::{
- read, DisableFocusChange, DisableMouseCapture, EnableFocusChange, EnableMouseCapture,
- Event, KeyCode,
+ read, DisableBracketedPaste, DisableFocusChange, DisableMouseCapture, EnableBracketedPaste,
+ EnableFocusChange, EnableMouseCapture, Event, KeyCode,
},
execute,
terminal::{disable_raw_mode, enable_raw_mode},
@@ -34,9 +34,9 @@ fn print_events() -> Result<()> {
println!("Cursor position: {:?}\r", position());
}
- if let Event::Resize(_, _) = event {
- let (original_size, new_size) = flush_resize_events(event);
- println!("Resize from: {:?}, to: {:?}", original_size, new_size);
+ if let Event::Resize(x, y) = event {
+ let (original_size, new_size) = flush_resize_events((x, y));
+ println!("Resize from: {:?}, to: {:?}\r", original_size, new_size);
}
if event == Event::Key(KeyCode::Esc.into()) {
@@ -50,18 +50,15 @@ fn print_events() -> Result<()> {
// Resize events can occur in batches.
// With a simple loop they can be flushed.
// This function will keep the first and last resize event.
-fn flush_resize_events(event: Event) -> ((u16, u16), (u16, u16)) {
- if let Event::Resize(x, y) = event {
- let mut last_resize = (x, y);
- while let Ok(true) = poll(Duration::from_millis(50)) {
- if let Ok(Event::Resize(x, y)) = read() {
- last_resize = (x, y);
- }
+fn flush_resize_events(first_resize: (u16, u16)) -> ((u16, u16), (u16, u16)) {
+ let mut last_resize = first_resize;
+ while let Ok(true) = poll(Duration::from_millis(50)) {
+ if let Ok(Event::Resize(x, y)) = read() {
+ last_resize = (x, y);
}
-
- return ((x, y), last_resize);
}
- ((0, 0), (0, 0))
+
+ return (first_resize, last_resize);
}
fn main() -> Result<()> {
@@ -70,13 +67,23 @@ fn main() -> Result<()> {
enable_raw_mode()?;
let mut stdout = stdout();
- execute!(stdout, EnableFocusChange, EnableMouseCapture)?;
+ execute!(
+ stdout,
+ EnableBracketedPaste,
+ EnableFocusChange,
+ EnableMouseCapture
+ )?;
if let Err(e) = print_events() {
println!("Error: {:?}\r", e);
}
- execute!(stdout, DisableFocusChange, DisableMouseCapture)?;
+ execute!(
+ stdout,
+ DisableBracketedPaste,
+ DisableFocusChange,
+ DisableMouseCapture
+ )?;
disable_raw_mode()
}
diff --git a/src/event.rs b/src/event.rs
index e32ea9515..40b437ff6 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -38,6 +38,7 @@
//! Event::FocusLost => println!("FocusLost"),
//! Event::Key(event) => println!("{:?}", event),
//! Event::Mouse(event) => println!("{:?}", event),
+//! Event::Paste(data) => println!("{:?}", data),
//! Event::Resize(width, height) => println!("New size {}x{}", width, height),
//! }
//! }
@@ -63,6 +64,7 @@
//! Event::FocusLost => println!("FocusLost"),
//! Event::Key(event) => println!("{:?}", event),
//! Event::Mouse(event) => println!("{:?}", event),
+//! Event::Paste(data) => println!("Pasted {:?}", data),
//! Event::Resize(width, height) => println!("New size {}x{}", width, height),
//! }
//! } else {
@@ -416,6 +418,8 @@ impl Command for PopKeyboardEnhancementFlags {
/// A command that enables focus event emission.
///
+/// It should be paired with [`DisableFocusChange`] at the end of execution.
+///
/// Focus events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EnableFocusChange;
@@ -433,8 +437,6 @@ impl Command for EnableFocusChange {
}
/// A command that disables focus event emission.
-///
-/// Focus events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DisableFocusChange;
@@ -450,9 +452,52 @@ impl Command for DisableFocusChange {
}
}
+/// A command that enables [bracketed paste mode](https://en.wikipedia.org/wiki/Bracketed-paste).
+///
+/// It should be paired with [`DisableBracketedPaste`] at the end of execution.
+///
+/// This is not supported in older Windows terminals without
+/// [virtual terminal sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences).
+#[cfg(feature = "bracketed-paste")]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct EnableBracketedPaste;
+
+#[cfg(feature = "bracketed-paste")]
+impl Command for EnableBracketedPaste {
+ fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
+ f.write_str(csi!("?2004h"))
+ }
+
+ #[cfg(windows)]
+ fn execute_winapi(&self) -> Result<()> {
+ Err(io::Error::new(
+ io::ErrorKind::Unsupported,
+ "Bracketed paste not implemented in the legacy Windows API.",
+ ))
+ }
+}
+
+/// A command that disables bracketed paste mode.
+#[cfg(feature = "bracketed-paste")]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct DisableBracketedPaste;
+
+#[cfg(feature = "bracketed-paste")]
+impl Command for DisableBracketedPaste {
+ fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
+ f.write_str(csi!("?2004l"))
+ }
+
+ #[cfg(windows)]
+ fn execute_winapi(&self) -> Result<()> {
+ Ok(())
+ }
+}
+
/// Represents an event.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
-#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)]
+#[cfg_attr(not(feature = "bracketed-paste"), derive(Copy))]
+#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Hash)]
pub enum Event {
/// The terminal gained focus
FocusGained,
@@ -462,6 +507,10 @@ pub enum Event {
Key(KeyEvent),
/// A single mouse event with additional pressed modifiers.
Mouse(MouseEvent),
+ /// A string that was pasted into the terminal. Only emitted if bracketed paste has been
+ /// enabled.
+ #[cfg(feature = "bracketed-paste")]
+ Paste(String),
/// An resize event with new dimensions after resize (columns, rows).
/// **Note** that resize events can be occur in batches.
Resize(u16, u16),
diff --git a/src/event/sys/unix/parse.rs b/src/event/sys/unix/parse.rs
index 37d5ecf70..483144f08 100644
--- a/src/event/sys/unix/parse.rs
+++ b/src/event/sys/unix/parse.rs
@@ -176,11 +176,15 @@ pub(crate) fn parse_csi(buffer: &[u8]) -> Result