Refactor escape sequences handling
diff --git a/src/tty/unix.rs b/src/tty/unix.rs
index cd35e30..fd366d5 100644
--- a/src/tty/unix.rs
+++ b/src/tty/unix.rs
@@ -113,145 +113,17 @@
})
}
+ /// Handle ESC <seq1> sequences
fn escape_sequence(&mut self) -> Result<KeyPress> {
- // Read the next two bytes representing the escape sequence.
+ // Read the next byte representing the escape sequence.
let seq1 = try!(self.next_char());
if seq1 == '[' {
// ESC [ sequences. (CSI)
- let seq2 = try!(self.next_char());
- if seq2.is_digit(10) {
- // Extended escape, read additional byte.
- let seq3 = try!(self.next_char());
- if seq3 == '~' {
- Ok(match seq2 {
- '1' | '7' => KeyPress::Home, // tmux, xrvt
- '2' => KeyPress::Insert,
- '3' => KeyPress::Delete, // kdch1
- '4' | '8' => KeyPress::End, // tmux, xrvt
- '5' => KeyPress::PageUp, // kpp
- '6' => KeyPress::PageDown, // knp
- _ => {
- debug!(target: "rustyline",
- "unsupported esc sequence: ESC [ {} ~", seq2);
- KeyPress::UnknownEscSeq
- }
- })
- } else if seq3.is_digit(10) {
- let seq4 = try!(self.next_char());
- if seq4 == '~' {
- Ok(match (seq2, seq3) {
- ('1', '1') => KeyPress::F(1), // rxvt-unicode
- ('1', '2') => KeyPress::F(2), // rxvt-unicode
- ('1', '3') => KeyPress::F(3), // rxvt-unicode
- ('1', '4') => KeyPress::F(4), // rxvt-unicode
- ('1', '5') => KeyPress::F(5), // kf5
- ('1', '7') => KeyPress::F(6), // kf6
- ('1', '8') => KeyPress::F(7), // kf7
- ('1', '9') => KeyPress::F(8), // kf8
- ('2', '0') => KeyPress::F(9), // kf9
- ('2', '1') => KeyPress::F(10), // kf10
- ('2', '3') => KeyPress::F(11), // kf11
- ('2', '4') => KeyPress::F(12), // kf12
- _ => {
- debug!(target: "rustyline",
- "unsupported esc sequence: ESC [ {}{} ~", seq1, seq2);
- KeyPress::UnknownEscSeq
- }
- })
- } else if seq4 == ';' {
- let seq5 = try!(self.next_char());
- if seq5.is_digit(10) {
- let seq6 = try!(self.next_char()); // '~' expected
- debug!(target: "rustyline",
- "unsupported esc sequence: ESC [ {}{} ; {} {}", seq2, seq3, seq5, seq6);
- } else {
- debug!(target: "rustyline",
- "unsupported esc sequence: ESC [ {}{} ; {:?}", seq2, seq3, seq5);
- }
- Ok(KeyPress::UnknownEscSeq)
- } else {
- debug!(target: "rustyline",
- "unsupported esc sequence: ESC [ {}{} {:?}", seq2, seq3, seq4);
- Ok(KeyPress::UnknownEscSeq)
- }
- } else if seq3 == ';' {
- let seq4 = try!(self.next_char());
- if seq4.is_digit(10) {
- let seq5 = try!(self.next_char());
- if seq2 == '1' {
- Ok(match (seq4, seq5) {
- ('5', 'A') => KeyPress::ControlUp,
- ('5', 'B') => KeyPress::ControlDown,
- ('5', 'C') => KeyPress::ControlRight,
- ('5', 'D') => KeyPress::ControlLeft,
- ('2', 'A') => KeyPress::ShiftUp,
- ('2', 'B') => KeyPress::ShiftDown,
- ('2', 'C') => KeyPress::ShiftRight,
- ('2', 'D') => KeyPress::ShiftLeft,
- _ => {
- debug!(target: "rustyline",
- "unsupported esc sequence: ESC [ {} ; {} {}", seq2, seq4, seq5);
- KeyPress::UnknownEscSeq
- }
- })
- } else {
- debug!(target: "rustyline",
- "unsupported esc sequence: ESC [ {} ; {} {}", seq2, seq4, seq5);
- Ok(KeyPress::UnknownEscSeq)
- }
- } else {
- debug!(target: "rustyline",
- "unsupported esc sequence: ESC [ {} ; {:?}", seq2, seq4);
- Ok(KeyPress::UnknownEscSeq)
- }
- } else {
- Ok(match (seq2, seq3) {
- ('5', 'A') => KeyPress::ControlUp,
- ('5', 'B') => KeyPress::ControlDown,
- ('5', 'C') => KeyPress::ControlRight,
- ('5', 'D') => KeyPress::ControlLeft,
- _ => {
- debug!(target: "rustyline",
- "unsupported esc sequence: ESC [ {} {:?}", seq2, seq3);
- KeyPress::UnknownEscSeq
- }
- })
- }
- } else {
- // ANSI
- Ok(match seq2 {
- 'A' => KeyPress::Up, // kcuu1
- 'B' => KeyPress::Down, // kcud1
- 'C' => KeyPress::Right, // kcuf1
- 'D' => KeyPress::Left, // kcub1
- 'F' => KeyPress::End,
- 'H' => KeyPress::Home, // khome
- _ => {
- debug!(target: "rustyline", "unsupported esc sequence: ESC [ {:?}", seq2);
- KeyPress::UnknownEscSeq
- }
- })
- }
+ self.escape_csi()
} else if seq1 == 'O' {
// xterm
// ESC O sequences. (SS3)
- let seq2 = try!(self.next_char());
- Ok(match seq2 {
- 'A' => KeyPress::Up, // kcuu1
- 'B' => KeyPress::Down, // kcud1
- 'C' => KeyPress::Right, // kcuf1
- 'D' => KeyPress::Left, // kcub1
- 'F' => KeyPress::End, // kend
- 'H' => KeyPress::Home, // khome
- 'P' => KeyPress::F(1), // kf1
- 'Q' => KeyPress::F(2), // kf2
- 'R' => KeyPress::F(3), // kf3
- 'S' => KeyPress::F(4), // kf4
- _ => {
- debug!(target: "rustyline", "unsupported esc sequence: ESC O {:?}", seq2);
- KeyPress::UnknownEscSeq
- }
- })
+ self.escape_o()
} else if seq1 == '\x1b' {
// ESC ESC
Ok(KeyPress::Esc)
@@ -260,6 +132,162 @@
Ok(KeyPress::Meta(seq1))
}
}
+
+ /// Handle ESC [ <seq2> escape sequences
+ fn escape_csi(&mut self) -> Result<KeyPress> {
+ let seq2 = try!(self.next_char());
+ if seq2.is_digit(10) {
+ match seq2 {
+ '0' | '9' => {
+ debug!(target: "rustyline", "unsupported esc sequence: ESC [ {:?}", seq2);
+ Ok(KeyPress::UnknownEscSeq)
+ }
+ _ => {
+ // Extended escape, read additional byte.
+ self.extended_escape(seq2)
+ }
+ }
+ } else {
+ // ANSI
+ Ok(match seq2 {
+ 'A' => KeyPress::Up, // kcuu1
+ 'B' => KeyPress::Down, // kcud1
+ 'C' => KeyPress::Right, // kcuf1
+ 'D' => KeyPress::Left, // kcub1
+ 'F' => KeyPress::End,
+ 'H' => KeyPress::Home, // khome
+ _ => {
+ debug!(target: "rustyline", "unsupported esc sequence: ESC [ {:?}", seq2);
+ KeyPress::UnknownEscSeq
+ }
+ })
+ }
+ }
+
+ /// Handle ESC [ <seq2:digit> escape sequences
+ fn extended_escape(&mut self, seq2: char) -> Result<KeyPress> {
+ let seq3 = try!(self.next_char());
+ if seq3 == '~' {
+ Ok(match seq2 {
+ '1' | '7' => KeyPress::Home, // tmux, xrvt
+ '2' => KeyPress::Insert,
+ '3' => KeyPress::Delete, // kdch1
+ '4' | '8' => KeyPress::End, // tmux, xrvt
+ '5' => KeyPress::PageUp, // kpp
+ '6' => KeyPress::PageDown, // knp
+ _ => {
+ debug!(target: "rustyline",
+ "unsupported esc sequence: ESC [ {} ~", seq2);
+ KeyPress::UnknownEscSeq
+ }
+ })
+ } else if seq3.is_digit(10) {
+ let seq4 = try!(self.next_char());
+ if seq4 == '~' {
+ Ok(match (seq2, seq3) {
+ ('1', '1') => KeyPress::F(1), // rxvt-unicode
+ ('1', '2') => KeyPress::F(2), // rxvt-unicode
+ ('1', '3') => KeyPress::F(3), // rxvt-unicode
+ ('1', '4') => KeyPress::F(4), // rxvt-unicode
+ ('1', '5') => KeyPress::F(5), // kf5
+ ('1', '7') => KeyPress::F(6), // kf6
+ ('1', '8') => KeyPress::F(7), // kf7
+ ('1', '9') => KeyPress::F(8), // kf8
+ ('2', '0') => KeyPress::F(9), // kf9
+ ('2', '1') => KeyPress::F(10), // kf10
+ ('2', '3') => KeyPress::F(11), // kf11
+ ('2', '4') => KeyPress::F(12), // kf12
+ _ => {
+ debug!(target: "rustyline",
+ "unsupported esc sequence: ESC [ {}{} ~", seq2, seq3);
+ KeyPress::UnknownEscSeq
+ }
+ })
+ } else if seq4 == ';' {
+ let seq5 = try!(self.next_char());
+ if seq5.is_digit(10) {
+ let seq6 = try!(self.next_char()); // '~' expected
+ debug!(target: "rustyline",
+ "unsupported esc sequence: ESC [ {}{} ; {} {}", seq2, seq3, seq5, seq6);
+ } else {
+ debug!(target: "rustyline",
+ "unsupported esc sequence: ESC [ {}{} ; {:?}", seq2, seq3, seq5);
+ }
+ Ok(KeyPress::UnknownEscSeq)
+ } else {
+ debug!(target: "rustyline",
+ "unsupported esc sequence: ESC [ {}{} {:?}", seq2, seq3, seq4);
+ Ok(KeyPress::UnknownEscSeq)
+ }
+ } else if seq3 == ';' {
+ let seq4 = try!(self.next_char());
+ if seq4.is_digit(10) {
+ let seq5 = try!(self.next_char());
+ if seq2 == '1' {
+ Ok(match (seq4, seq5) {
+ ('5', 'A') => KeyPress::ControlUp,
+ ('5', 'B') => KeyPress::ControlDown,
+ ('5', 'C') => KeyPress::ControlRight,
+ ('5', 'D') => KeyPress::ControlLeft,
+ ('2', 'A') => KeyPress::ShiftUp,
+ ('2', 'B') => KeyPress::ShiftDown,
+ ('2', 'C') => KeyPress::ShiftRight,
+ ('2', 'D') => KeyPress::ShiftLeft,
+ _ => {
+ debug!(target: "rustyline",
+ "unsupported esc sequence: ESC [ {} ; {} {}", seq2, seq4, seq5);
+ KeyPress::UnknownEscSeq
+ }
+ })
+ } else {
+ debug!(target: "rustyline",
+ "unsupported esc sequence: ESC [ {} ; {} {}", seq2, seq4, seq5);
+ Ok(KeyPress::UnknownEscSeq)
+ }
+ } else {
+ debug!(target: "rustyline",
+ "unsupported esc sequence: ESC [ {} ; {:?}", seq2, seq4);
+ Ok(KeyPress::UnknownEscSeq)
+ }
+ } else {
+ Ok(match (seq2, seq3) {
+ ('5', 'A') => KeyPress::ControlUp,
+ ('5', 'B') => KeyPress::ControlDown,
+ ('5', 'C') => KeyPress::ControlRight,
+ ('5', 'D') => KeyPress::ControlLeft,
+ _ => {
+ debug!(target: "rustyline",
+ "unsupported esc sequence: ESC [ {} {:?}", seq2, seq3);
+ KeyPress::UnknownEscSeq
+ }
+ })
+ }
+ }
+
+ /// Handle ESC O <seq2> escape sequences
+ fn escape_o(&mut self) -> Result<KeyPress> {
+ let seq2 = try!(self.next_char());
+ Ok(match seq2 {
+ 'A' => KeyPress::Up, // kcuu1
+ 'B' => KeyPress::Down, // kcud1
+ 'C' => KeyPress::Right, // kcuf1
+ 'D' => KeyPress::Left, // kcub1
+ 'F' => KeyPress::End, // kend
+ 'H' => KeyPress::Home, // khome
+ 'P' => KeyPress::F(1), // kf1
+ 'Q' => KeyPress::F(2), // kf2
+ 'R' => KeyPress::F(3), // kf3
+ 'S' => KeyPress::F(4), // kf4
+ 'a' => KeyPress::ControlUp,
+ 'b' => KeyPress::ControlDown,
+ 'c' => KeyPress::ControlRight,
+ 'd' => KeyPress::ControlLeft,
+ _ => {
+ debug!(target: "rustyline", "unsupported esc sequence: ESC O {:?}", seq2);
+ KeyPress::UnknownEscSeq
+ }
+ })
+ }
}
// https://tools.ietf.org/html/rfc3629