From 00ca758d45b546fb167403e286be82c4ff5eedb7 Mon Sep 17 00:00:00 2001
From: Alexandre Bury <alexandre.bury@gmail.com>
Date: Fri, 16 Dec 2016 18:20:18 +0100
Subject: [PATCH] Add `UnknownCSI` event type (#73)

* Add `UnknownCSI` event type.

* Compile test from `raw` module

But don't run it.

* Fix unused import warning in doc-test

* Rename UnknownCSI -> UnknownCsi
---
 src/color.rs |  4 +---
 src/event.rs | 37 ++++++++++++++++++++++++++-----------
 src/raw.rs   |  2 +-
 3 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/src/color.rs b/src/color.rs
index e154ae29..c1eee52d 100644
--- a/src/color.rs
+++ b/src/color.rs
@@ -3,9 +3,7 @@
 //! # Example
 //!
 //! ```rust
-//! use termion::{color, style};
-//!
-//! use std::io;
+//! use termion::color;
 //!
 //! fn main() {
 //!     println!("{}Red", color::Fg(color::Red));
diff --git a/src/event.rs b/src/event.rs
index 9d338c69..44a139ea 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -5,7 +5,7 @@ use std::ascii::AsciiExt;
 use std::str;
 
 /// An event reported by the terminal.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Event {
     /// A key press.
     Key(Key),
@@ -13,6 +13,9 @@ pub enum Event {
     Mouse(MouseEvent),
     /// An event that cannot currently be evaluated.
     Unsupported,
+    /// A CSI sequence unrecognized by termion. Does not inlude the leading `^[`.
+    UnknownCsi(Vec<u8>),
+
 }
 
 /// A mouse related event.
@@ -93,7 +96,6 @@ pub enum Key {
     /// Esc key.
     Esc,
 
-    #[allow(missing_docs)]
     #[doc(hidden)]
     __IsNotComplete
 }
@@ -108,11 +110,13 @@ where I: Iterator<Item = Result<u8, Error>>
             Ok(match iter.next() {
                 Some(Ok(b'O')) => {
                     match iter.next() {
+                        // F1-F4
                         Some(Ok(val @ b'P' ... b'S')) => Event::Key(Key::F(1 + val - b'P')),
                         _ => return error,
                     }
                 }
                 Some(Ok(b'[')) => {
+                    // This is a CSI sequence.
                     match iter.next() {
                         Some(Ok(b'D')) => Event::Key(Key::Left),
                         Some(Ok(b'C')) => Event::Key(Key::Right),
@@ -198,17 +202,24 @@ where I: Iterator<Item = Result<u8, Error>>
                                 buf.push(c);
                                 c = iter.next().unwrap().unwrap();
                             }
+                            // Include the terminal char in the buffer.
+                            // We'll want it if we return an unknown sequence.
+                            buf.push(c);
 
                             match c {
                                 // rxvt mouse encoding:
                                 // ESC [ Cb ; Cx ; Cy ; M
                                 b'M' => {
                                     let str_buf = String::from_utf8(buf).unwrap();
-                                    let nums = &mut str_buf.split(';');
 
-                                    let cb = nums.next().unwrap().parse::<u16>().unwrap();
-                                    let cx = nums.next().unwrap().parse::<u16>().unwrap();
-                                    let cy = nums.next().unwrap().parse::<u16>().unwrap();
+                                    // 
+                                    let nums: Vec<u16> = str_buf[..str_buf.len()-1].split(';')
+                                        .map(|n| n.parse().unwrap())
+                                        .collect();
+
+                                    let cb = nums[0];
+                                    let cx = nums[1];
+                                    let cy = nums[2];
 
                                     let event = match cb {
                                         32 => MouseEvent::Press(MouseButton::Left, cx, cy),
@@ -218,7 +229,7 @@ where I: Iterator<Item = Result<u8, Error>>
                                         64 => MouseEvent::Hold(cx, cy),
                                         96 |
                                         97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
-                                        _ => return error,
+                                        _ => return Ok(Event::UnknownCsi(str_buf.into_bytes())),
                                     };
 
                                     Event::Mouse(event)
@@ -229,16 +240,20 @@ where I: Iterator<Item = Result<u8, Error>>
 
                                     // This CSI sequence can be a list of semicolon-separated
                                     // numbers.
-                                    let nums: Vec<u8> = str_buf.split(';')
+                                    let nums: Vec<u8> = str_buf[..str_buf.len()-1].split(';')
                                         .map(|n| n.parse().unwrap())
                                         .collect();
 
                                     if nums.is_empty() {
-                                        return error;
+                                        return Ok(Event::UnknownCsi(str_buf.into_bytes()));
                                     }
 
                                     // TODO: handle multiple values for key modififiers (ex: values
                                     // [3, 2] means Shift+Delete)
+                                    if nums.len() > 1 {
+                                        return Ok(Event::UnknownCsi(str_buf.into_bytes()));
+                                    }
+
                                     match nums[0] {
                                         1 | 7 => Event::Key(Key::Home),
                                         2 => Event::Key(Key::Insert),
@@ -249,10 +264,10 @@ where I: Iterator<Item = Result<u8, Error>>
                                         v @ 11...15 => Event::Key(Key::F(v - 10)),
                                         v @ 17...21 => Event::Key(Key::F(v - 11)),
                                         v @ 23...24 => Event::Key(Key::F(v - 12)),
-                                        _ => return error,
+                                        _ => return Ok(Event::UnknownCsi(str_buf.into_bytes())),
                                     }
                                 },
-                                _ => return error,
+                                _ => return Ok(Event::UnknownCsi(buf)),
                             }
                         },
                         _ => return error,
diff --git a/src/raw.rs b/src/raw.rs
index 20a07f94..09cd5e4a 100644
--- a/src/raw.rs
+++ b/src/raw.rs
@@ -11,7 +11,7 @@
 //!
 //! # Example
 //!
-//! ```rust,ignore
+//! ```rust,no_run
 //! use termion::raw::IntoRawMode;
 //! use std::io::{Write, stdout};
 //!
-- 
GitLab