Run rustfmt on the code.

This commit is contained in:
ticki 2017-03-24 21:53:05 +01:00
parent 7351aa3f16
commit 15c65dc5f9
No known key found for this signature in database
GPG Key ID: 28F8864B5C973CB6
19 changed files with 314 additions and 264 deletions

View File

@ -27,12 +27,12 @@ fn main() {
Key::Char('q') => break, Key::Char('q') => break,
Key::Char('1') => { Key::Char('1') => {
write!(screen, "{}", ToMainScreen).unwrap(); write!(screen, "{}", ToMainScreen).unwrap();
}, }
Key::Char('2') => { Key::Char('2') => {
write!(screen, "{}", ToAlternateScreen).unwrap(); write!(screen, "{}", ToAlternateScreen).unwrap();
write_alt_screen_msg(&mut screen); write_alt_screen_msg(&mut screen);
}, }
_ => {}, _ => {}
} }
screen.flush().unwrap(); screen.flush().unwrap();
} }

View File

@ -11,7 +11,11 @@ fn main() {
let mut stdout = stdout.lock().into_raw_mode().unwrap(); let mut stdout = stdout.lock().into_raw_mode().unwrap();
let mut stdin = async_stdin().bytes(); let mut stdin = async_stdin().bytes();
write!(stdout, "{}{}", termion::clear::All, termion::cursor::Goto(1, 1)).unwrap(); write!(stdout,
"{}{}",
termion::clear::All,
termion::cursor::Goto(1, 1))
.unwrap();
loop { loop {
write!(stdout, "{}", termion::clear::CurrentLine).unwrap(); write!(stdout, "{}", termion::clear::CurrentLine).unwrap();

View File

@ -9,7 +9,11 @@ fn main() {
let stdin = stdin(); let stdin = stdin();
let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap()); let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap());
write!(stdout, "{}{}q to exit. Click, click, click!", termion::clear::All, termion::cursor::Goto(1, 1)).unwrap(); write!(stdout,
"{}{}q to exit. Click, click, click!",
termion::clear::All,
termion::cursor::Goto(1, 1))
.unwrap();
stdout.flush().unwrap(); stdout.flush().unwrap();
for c in stdin.events() { for c in stdin.events() {
@ -20,7 +24,7 @@ fn main() {
match me { match me {
MouseEvent::Press(_, x, y) => { MouseEvent::Press(_, x, y) => {
write!(stdout, "{}x", termion::cursor::Goto(x, y)).unwrap(); write!(stdout, "{}x", termion::cursor::Goto(x, y)).unwrap();
}, }
_ => (), _ => (),
} }
} }

View File

@ -28,10 +28,20 @@ const COMMUNISM: &'static str = r#"
fn main() { fn main() {
let mut state = 0; let mut state = 0;
println!("\n{}{}{}{}{}{}", cursor::Hide, clear::All, cursor::Goto(1, 1), color::Fg(color::Black), color::Bg(color::Red), COMMUNISM); println!("\n{}{}{}{}{}{}",
cursor::Hide,
clear::All,
cursor::Goto(1, 1),
color::Fg(color::Black),
color::Bg(color::Red),
COMMUNISM);
loop { loop {
println!("{}{} ☭ GAY ☭ SPACE ☭ COMMUNISM ☭ ", cursor::Goto(1, 1), color::Bg(color::AnsiValue(state))); println!("{}{} ☭ GAY ☭ SPACE ☭ COMMUNISM ☭ ",
println!("{}{} WILL PREVAIL, COMRADES! ", cursor::Goto(1, 20), color::Bg(color::AnsiValue(state))); cursor::Goto(1, 1),
color::Bg(color::AnsiValue(state)));
println!("{}{} WILL PREVAIL, COMRADES! ",
cursor::Goto(1, 20),
color::Bg(color::AnsiValue(state)));
state += 1; state += 1;
state %= 8; state %= 8;

View File

@ -9,14 +9,20 @@ fn main() {
let stdin = stdin(); let stdin = stdin();
let mut stdout = stdout().into_raw_mode().unwrap(); let mut stdout = stdout().into_raw_mode().unwrap();
write!(stdout, "{}{}q to exit. Type stuff, use alt, and so on.{}", write!(stdout,
"{}{}q to exit. Type stuff, use alt, and so on.{}",
termion::clear::All, termion::clear::All,
termion::cursor::Goto(1, 1), termion::cursor::Goto(1, 1),
termion::cursor::Hide).unwrap(); termion::cursor::Hide)
.unwrap();
stdout.flush().unwrap(); stdout.flush().unwrap();
for c in stdin.keys() { for c in stdin.keys() {
write!(stdout, "{}{}", termion::cursor::Goto(1, 1), termion::clear::CurrentLine).unwrap(); write!(stdout,
"{}{}",
termion::cursor::Goto(1, 1),
termion::clear::CurrentLine)
.unwrap();
match c.unwrap() { match c.unwrap() {
Key::Char('q') => break, Key::Char('q') => break,
@ -29,7 +35,7 @@ fn main() {
Key::Up => println!(""), Key::Up => println!(""),
Key::Down => println!(""), Key::Down => println!(""),
Key::Backspace => println!("×"), Key::Backspace => println!("×"),
_ => {}, _ => {}
} }
stdout.flush().unwrap(); stdout.flush().unwrap();
} }

View File

@ -14,7 +14,7 @@ fn main() {
"{}{}q to exit. Type stuff, use alt, click around...", "{}{}q to exit. Type stuff, use alt, click around...",
termion::clear::All, termion::clear::All,
termion::cursor::Goto(1, 1)) termion::cursor::Goto(1, 1))
.unwrap(); .unwrap();
for c in stdin.events() { for c in stdin.events() {
let evt = c.unwrap(); let evt = c.unwrap();
@ -33,7 +33,8 @@ fn main() {
termion::clear::UntilNewline, termion::clear::UntilNewline,
x, x,
y, y,
cursor::Goto(a, b)).unwrap(); cursor::Goto(a, b))
.unwrap();
} }
} }
} }

View File

@ -6,13 +6,20 @@ use termion::raw::IntoRawMode;
use std::io::{Write, stdout, stdin}; use std::io::{Write, stdout, stdin};
fn rainbow<W: Write>(stdout: &mut W, blue: u8) { fn rainbow<W: Write>(stdout: &mut W, blue: u8) {
write!(stdout, "{}{}", termion::cursor::Goto(1, 1), termion::clear::All).unwrap(); write!(stdout,
"{}{}",
termion::cursor::Goto(1, 1),
termion::clear::All)
.unwrap();
for red in 0..32 { for red in 0..32 {
let red = red * 8; let red = red * 8;
for green in 0..64 { for green in 0..64 {
let green = green * 4; let green = green * 4;
write!(stdout, "{} ", termion::color::Bg(termion::color::Rgb(red, green, blue))).unwrap(); write!(stdout,
"{} ",
termion::color::Bg(termion::color::Rgb(red, green, blue)))
.unwrap();
} }
write!(stdout, "\n\r").unwrap(); write!(stdout, "\n\r").unwrap();
} }
@ -24,10 +31,12 @@ fn main() {
let stdin = stdin(); let stdin = stdin();
let mut stdout = stdout().into_raw_mode().unwrap(); let mut stdout = stdout().into_raw_mode().unwrap();
writeln!(stdout, "{}{}{}Use the up/down arrow keys to change the blue in the rainbow.", writeln!(stdout,
termion::clear::All, "{}{}{}Use the up/down arrow keys to change the blue in the rainbow.",
termion::cursor::Goto(1, 1), termion::clear::All,
termion::cursor::Hide).unwrap(); termion::cursor::Goto(1, 1),
termion::cursor::Hide)
.unwrap();
let mut blue = 172u8; let mut blue = 172u8;
@ -36,13 +45,13 @@ fn main() {
Key::Up => { Key::Up => {
blue = blue.saturating_add(4); blue = blue.saturating_add(4);
rainbow(&mut stdout, blue); rainbow(&mut stdout, blue);
}, }
Key::Down => { Key::Down => {
blue = blue.saturating_sub(4); blue = blue.saturating_sub(4);
rainbow(&mut stdout, blue); rainbow(&mut stdout, blue);
}, }
Key::Char('q') => break, Key::Char('q') => break,
_ => {}, _ => {}
} }
stdout.flush().unwrap(); stdout.flush().unwrap();
} }

View File

@ -12,13 +12,13 @@ fn main() {
{line_num_fg}{line_num_bg}84 {reset} }};\n\ {line_num_fg}{line_num_bg}84 {reset} }};\n\
{line_num_fg}{line_num_bg}85 {reset} }}\n\ {line_num_fg}{line_num_bg}85 {reset} }}\n\
{line_num_fg}{line_num_bg}{info_line}{reset} {red}^{reset} {error_fg}borrow from first closure ends here", {line_num_fg}{line_num_bg}{info_line}{reset} {red}^{reset} {error_fg}borrow from first closure ends here",
lighgreen=color::Fg(color::LightGreen), lighgreen = color::Fg(color::LightGreen),
red=color::Fg(color::Red), red = color::Fg(color::Red),
bold=style::Bold, bold = style::Bold,
reset=style::Reset, reset = style::Reset,
magenta=color::Fg(color::Magenta), magenta = color::Fg(color::Magenta),
line_num_bg=color::Bg(color::AnsiValue::grayscale(3)), line_num_bg = color::Bg(color::AnsiValue::grayscale(3)),
line_num_fg=color::Fg(color::AnsiValue::grayscale(18)), line_num_fg = color::Fg(color::AnsiValue::grayscale(18)),
info_line="| ", info_line = "| ",
error_fg=color::Fg(color::AnsiValue::grayscale(17))) error_fg = color::Fg(color::AnsiValue::grayscale(17)))
} }

View File

@ -11,8 +11,14 @@ fn main() {
let stdin = stdin(); let stdin = stdin();
let stdin = stdin.lock(); let stdin = stdin.lock();
write!(stdout, "{}{}{}yo, 'q' will exit.{}{}", termion::clear::All, termion::cursor::Goto(5, 5), write!(stdout,
termion::style::Bold, termion::style::Reset, termion::cursor::Goto(20, 10)).unwrap(); "{}{}{}yo, 'q' will exit.{}{}",
termion::clear::All,
termion::cursor::Goto(5, 5),
termion::style::Bold,
termion::style::Reset,
termion::cursor::Goto(20, 10))
.unwrap();
stdout.flush().unwrap(); stdout.flush().unwrap();
let mut bytes = stdin.bytes(); let mut bytes = stdin.bytes();
@ -20,15 +26,16 @@ fn main() {
let b = bytes.next().unwrap().unwrap(); let b = bytes.next().unwrap().unwrap();
match b { match b {
// Quit // Quit
b'q' => return, b'q' => return,
// Clear the screen // Clear the screen
b'c' => write!(stdout, "{}", termion::clear::All), b'c' => write!(stdout, "{}", termion::clear::All),
// Set red color // Set red color
b'r' => write!(stdout, "{}", color::Fg(color::Rgb(5, 0, 0))), b'r' => write!(stdout, "{}", color::Fg(color::Rgb(5, 0, 0))),
// Write it to stdout. // Write it to stdout.
a => write!(stdout, "{}", a), a => write!(stdout, "{}", a),
}.unwrap(); }
.unwrap();
stdout.flush().unwrap(); stdout.flush().unwrap();
} }

View File

@ -17,17 +17,13 @@ use tty;
pub fn async_stdin() -> AsyncReader { pub fn async_stdin() -> AsyncReader {
let (send, recv) = mpsc::channel(); let (send, recv) = mpsc::channel();
thread::spawn(move || { thread::spawn(move || for i in tty::get_tty().unwrap().bytes() {
for i in tty::get_tty().unwrap().bytes() { if send.send(i).is_err() {
if send.send(i).is_err() { return;
return; }
} });
}
});
AsyncReader { AsyncReader { recv: recv }
recv: recv,
}
} }
/// An asynchronous reader. /// An asynchronous reader.
@ -59,7 +55,7 @@ impl Read for AsyncReader {
Ok(Ok(b)) => { Ok(Ok(b)) => {
buf[total] = b; buf[total] = b;
total += 1; total += 1;
}, }
Ok(Err(e)) => return Err(e), Ok(Err(e)) => return Err(e),
Err(_) => break, Err(_) => break,
} }

View File

@ -83,9 +83,15 @@ pub struct AnsiValue(pub u8);
impl AnsiValue { impl AnsiValue {
/// 216-color (r, g, b ≤ 5) RGB. /// 216-color (r, g, b ≤ 5) RGB.
pub fn rgb(r: u8, g: u8, b: u8) -> AnsiValue { pub fn rgb(r: u8, g: u8, b: u8) -> AnsiValue {
debug_assert!(r <= 5, "Red color fragment (r = {}) is out of bound. Make sure r ≤ 5.", r); debug_assert!(r <= 5,
debug_assert!(g <= 5, "Green color fragment (g = {}) is out of bound. Make sure g ≤ 5.", g); "Red color fragment (r = {}) is out of bound. Make sure r ≤ 5.",
debug_assert!(b <= 5, "Blue color fragment (b = {}) is out of bound. Make sure b ≤ 5.", b); r);
debug_assert!(g <= 5,
"Green color fragment (g = {}) is out of bound. Make sure g ≤ 5.",
g);
debug_assert!(b <= 5,
"Blue color fragment (b = {}) is out of bound. Make sure b ≤ 5.",
b);
AnsiValue(16 + 36 * r + 6 * g + b) AnsiValue(16 + 36 * r + 6 * g + b)
} }
@ -95,8 +101,10 @@ impl AnsiValue {
/// There are 24 shades of gray. /// There are 24 shades of gray.
pub fn grayscale(shade: u8) -> AnsiValue { pub fn grayscale(shade: u8) -> AnsiValue {
// Unfortunately, there are a little less than fifty shades. // Unfortunately, there are a little less than fifty shades.
debug_assert!(shade < 24, "Grayscale out of bound (shade = {}). There are only 24 shades of \ debug_assert!(shade < 24,
gray.", shade); "Grayscale out of bound (shade = {}). There are only 24 shades of \
gray.",
shade);
AnsiValue(0xE8 + shade) AnsiValue(0xE8 + shade)
} }
@ -197,24 +205,21 @@ impl<W: Write> DetectColors for W {
} else { } else {
// OSC 4 is not supported, trust TERM contents. // OSC 4 is not supported, trust TERM contents.
Ok(match env::var_os("TERM") { Ok(match env::var_os("TERM") {
Some(val) => { Some(val) => {
if val.to_str().unwrap_or("").contains("256color") { if val.to_str().unwrap_or("").contains("256color") {
256 256
} else { } else {
8 8
} }
} }
None => 8, None => 8,
}) })
} }
} }
} }
/// Detect a color using OSC 4. /// Detect a color using OSC 4.
fn detect_color(stdout: &mut Write, fn detect_color(stdout: &mut Write, stdin: &mut Read, color: u16) -> io::Result<bool> {
stdin: &mut Read,
color: u16)
-> io::Result<bool> {
// Is the color available? // Is the color available?
// Use `ESC ] 4 ; color ; ? BEL`. // Use `ESC ] 4 ; color ; ? BEL`.
write!(stdout, "\x1B]4;{};?\x07", color)?; write!(stdout, "\x1B]4;{};?\x07", color)?;

View File

@ -30,7 +30,9 @@ derive_csi_sequence!("Show the cursor.", Show, "?25h");
pub struct Goto(pub u16, pub u16); pub struct Goto(pub u16, pub u16);
impl Default for Goto { impl Default for Goto {
fn default() -> Goto { Goto(1, 1) } fn default() -> Goto {
Goto(1, 1)
}
} }
impl fmt::Display for Goto { impl fmt::Display for Goto {
@ -118,11 +120,17 @@ impl<W: Write> DetectCursorPos for W {
read_chars.pop(); // remove trailing R. read_chars.pop(); // remove trailing R.
let read_str = String::from_utf8(read_chars).unwrap(); let read_str = String::from_utf8(read_chars).unwrap();
let beg = read_str.rfind('[').unwrap(); let beg = read_str.rfind('[').unwrap();
let coords: String = read_str.chars().skip(beg+1).collect(); let coords: String = read_str.chars().skip(beg + 1).collect();
let mut nums = coords.split(';'); let mut nums = coords.split(';');
let cy = nums.next().unwrap().parse::<u16>().unwrap(); let cy = nums.next()
let cx = nums.next().unwrap().parse::<u16>().unwrap(); .unwrap()
.parse::<u16>()
.unwrap();
let cx = nums.next()
.unwrap()
.parse::<u16>()
.unwrap();
Ok((cx, cy)) Ok((cx, cy))
} }

View File

@ -106,23 +106,23 @@ pub fn parse_event<I>(item: u8, iter: &mut I) -> Result<Event, Error>
b'\x1B' => { b'\x1B' => {
// This is an escape character, leading a control sequence. // This is an escape character, leading a control sequence.
Ok(match iter.next() { Ok(match iter.next() {
Some(Ok(b'O')) => { Some(Ok(b'O')) => {
match iter.next() { match iter.next() {
// F1-F4 // F1-F4
Some(Ok(val @ b'P'...b'S')) => Event::Key(Key::F(1 + val - b'P')), Some(Ok(val @ b'P'...b'S')) => Event::Key(Key::F(1 + val - b'P')),
_ => return Err(error), _ => return Err(error),
}
} }
Some(Ok(b'[')) => { }
// This is a CSI sequence. Some(Ok(b'[')) => {
parse_csi(iter).ok_or(error)? // This is a CSI sequence.
} parse_csi(iter).ok_or(error)?
Some(Ok(c)) => { }
let ch = parse_utf8_char(c, iter); Some(Ok(c)) => {
Event::Key(Key::Alt(try!(ch))) let ch = parse_utf8_char(c, iter);
} Event::Key(Key::Alt(try!(ch)))
Some(Err(_)) | None => return Err(error), }
}) Some(Err(_)) | None => return Err(error),
})
} }
b'\n' | b'\r' => Ok(Event::Key(Key::Char('\n'))), b'\n' | b'\r' => Ok(Event::Key(Key::Char('\n'))),
b'\t' => Ok(Event::Key(Key::Char('\t'))), b'\t' => Ok(Event::Key(Key::Char('\t'))),
@ -132,9 +132,9 @@ pub fn parse_event<I>(item: u8, iter: &mut I) -> Result<Event, Error>
b'\0' => Ok(Event::Key(Key::Null)), b'\0' => Ok(Event::Key(Key::Null)),
c => { c => {
Ok({ Ok({
let ch = parse_utf8_char(c, iter); let ch = parse_utf8_char(c, iter);
Event::Key(Key::Char(try!(ch))) Event::Key(Key::Char(try!(ch)))
}) })
} }
} }
} }
@ -146,160 +146,163 @@ fn parse_csi<I>(iter: &mut I) -> Option<Event>
where I: Iterator<Item = Result<u8, Error>> where I: Iterator<Item = Result<u8, Error>>
{ {
Some(match iter.next() { Some(match iter.next() {
Some(Ok(b'D')) => Event::Key(Key::Left), Some(Ok(b'D')) => Event::Key(Key::Left),
Some(Ok(b'C')) => Event::Key(Key::Right), Some(Ok(b'C')) => Event::Key(Key::Right),
Some(Ok(b'A')) => Event::Key(Key::Up), Some(Ok(b'A')) => Event::Key(Key::Up),
Some(Ok(b'B')) => Event::Key(Key::Down), Some(Ok(b'B')) => Event::Key(Key::Down),
Some(Ok(b'H')) => Event::Key(Key::Home), Some(Ok(b'H')) => Event::Key(Key::Home),
Some(Ok(b'F')) => Event::Key(Key::End), Some(Ok(b'F')) => Event::Key(Key::End),
Some(Ok(b'M')) => { Some(Ok(b'M')) => {
// X10 emulation mouse encoding: ESC [ CB Cx Cy (6 characters only). // X10 emulation mouse encoding: ESC [ CB Cx Cy (6 characters only).
let mut next = || iter.next().unwrap().unwrap(); let mut next = || iter.next().unwrap().unwrap();
let cb = next() as i8 - 32; let cb = next() as i8 - 32;
// (1, 1) are the coords for upper left. // (1, 1) are the coords for upper left.
let cx = next().saturating_sub(32) as u16; let cx = next().saturating_sub(32) as u16;
let cy = next().saturating_sub(32) as u16; let cy = next().saturating_sub(32) as u16;
Event::Mouse(match cb & 0b11 { Event::Mouse(match cb & 0b11 {
0 => { 0 => {
if cb & 0x40 != 0 { if cb & 0x40 != 0 {
MouseEvent::Press(MouseButton::WheelUp, cx, cy) MouseEvent::Press(MouseButton::WheelUp, cx, cy)
} else { } else {
MouseEvent::Press(MouseButton::Left, cx, cy) MouseEvent::Press(MouseButton::Left, cx, cy)
} }
} }
1 => { 1 => {
if cb & 0x40 != 0 { if cb & 0x40 != 0 {
MouseEvent::Press(MouseButton::WheelDown, cx, cy) MouseEvent::Press(MouseButton::WheelDown, cx, cy)
} else { } else {
MouseEvent::Press(MouseButton::Middle, cx, cy) MouseEvent::Press(MouseButton::Middle, cx, cy)
} }
} }
2 => MouseEvent::Press(MouseButton::Right, cx, cy), 2 => MouseEvent::Press(MouseButton::Right, cx, cy),
3 => MouseEvent::Release(cx, cy), 3 => MouseEvent::Release(cx, cy),
_ => return None, _ => return None,
}) })
} }
Some(Ok(b'<')) => { Some(Ok(b'<')) => {
// xterm mouse encoding: // xterm mouse encoding:
// ESC [ < Cb ; Cx ; Cy (;) (M or m) // ESC [ < Cb ; Cx ; Cy (;) (M or m)
let mut buf = Vec::new(); let mut buf = Vec::new();
let mut c = iter.next().unwrap().unwrap(); let mut c = iter.next().unwrap().unwrap();
while match c { while match c {
b'm' | b'M' => false, b'm' | b'M' => false,
_ => true, _ => true,
} { } {
buf.push(c);
c = iter.next().unwrap().unwrap();
}
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 event = match cb {
0...2 | 64...65 => {
let button = match cb {
0 => MouseButton::Left,
1 => MouseButton::Middle,
2 => MouseButton::Right,
64 => MouseButton::WheelUp,
65 => MouseButton::WheelDown,
_ => unreachable!(),
};
match c {
b'M' => MouseEvent::Press(button, cx, cy),
b'm' => MouseEvent::Release(cx, cy),
_ => return None,
}
}
32 => MouseEvent::Hold(cx, cy),
3 => MouseEvent::Release(cx, cy),
_ => return None,
};
Event::Mouse(event)
}
Some(Ok(c @ b'0'...b'9')) => {
// Numbered escape code.
let mut buf = Vec::new();
buf.push(c); buf.push(c);
let mut c = iter.next().unwrap().unwrap(); c = iter.next().unwrap().unwrap();
// The final byte of a CSI sequence can be in the range 64-126, so
// let's keep reading anything else.
while c < 64 || c > 126 {
buf.push(c);
c = iter.next().unwrap().unwrap();
}
match c {
// rxvt mouse encoding:
// ESC [ Cb ; Cx ; Cy ; M
b'M' => {
let str_buf = String::from_utf8(buf).unwrap();
let nums: Vec<u16> = str_buf
.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),
33 => MouseEvent::Press(MouseButton::Middle, cx, cy),
34 => MouseEvent::Press(MouseButton::Right, cx, cy),
35 => MouseEvent::Release(cx, cy),
64 => MouseEvent::Hold(cx, cy),
96 | 97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
_ => return None,
};
Event::Mouse(event)
}
// Special key code.
b'~' => {
let str_buf = String::from_utf8(buf).unwrap();
// This CSI sequence can be a list of semicolon-separated
// numbers.
let nums: Vec<u8> = str_buf
.split(';')
.map(|n| n.parse().unwrap())
.collect();
if nums.is_empty() {
return None;
}
// TODO: handle multiple values for key modififiers (ex: values
// [3, 2] means Shift+Delete)
if nums.len() > 1 {
return None;
}
match nums[0] {
1 | 7 => Event::Key(Key::Home),
2 => Event::Key(Key::Insert),
3 => Event::Key(Key::Delete),
4 | 8 => Event::Key(Key::End),
5 => Event::Key(Key::PageUp),
6 => Event::Key(Key::PageDown),
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 None,
}
}
_ => return None,
}
} }
_ => return None, 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 event = match cb {
0...2 | 64...65 => {
let button = match cb {
0 => MouseButton::Left,
1 => MouseButton::Middle,
2 => MouseButton::Right,
64 => MouseButton::WheelUp,
65 => MouseButton::WheelDown,
_ => unreachable!(),
};
match c {
b'M' => MouseEvent::Press(button, cx, cy),
b'm' => MouseEvent::Release(cx, cy),
_ => return None,
}
}
32 => MouseEvent::Hold(cx, cy),
3 => MouseEvent::Release(cx, cy),
_ => return None,
};
Event::Mouse(event)
}
Some(Ok(c @ b'0'...b'9')) => {
// Numbered escape code.
let mut buf = Vec::new();
buf.push(c);
let mut c = iter.next().unwrap().unwrap();
// The final byte of a CSI sequence can be in the range 64-126, so
// let's keep reading anything else.
while c < 64 || c > 126 {
buf.push(c);
c = iter.next().unwrap().unwrap();
}
match c {
// rxvt mouse encoding:
// ESC [ Cb ; Cx ; Cy ; M
b'M' => {
let str_buf = String::from_utf8(buf).unwrap();
let nums: Vec<u16> = str_buf.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),
33 => MouseEvent::Press(MouseButton::Middle, cx, cy),
34 => MouseEvent::Press(MouseButton::Right, cx, cy),
35 => MouseEvent::Release(cx, cy),
64 => MouseEvent::Hold(cx, cy),
96 | 97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy),
_ => return None,
};
Event::Mouse(event)
}
// Special key code.
b'~' => {
let str_buf = String::from_utf8(buf).unwrap();
// This CSI sequence can be a list of semicolon-separated
// numbers.
let nums: Vec<u8> = str_buf.split(';').map(|n| n.parse().unwrap()).collect();
if nums.is_empty() {
return None;
}
// TODO: handle multiple values for key modififiers (ex: values
// [3, 2] means Shift+Delete)
if nums.len() > 1 {
return None;
}
match nums[0] {
1 | 7 => Event::Key(Key::Home),
2 => Event::Key(Key::Insert),
3 => Event::Key(Key::Delete),
4 | 8 => Event::Key(Key::End),
5 => Event::Key(Key::PageUp),
6 => Event::Key(Key::PageDown),
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 None,
}
}
_ => return None,
}
}
_ => return None,
})
} }

View File

@ -81,8 +81,8 @@ fn parse_event<I>(item: u8, iter: &mut I) -> Result<Event, io::Error>
let mut buf = vec![item]; let mut buf = vec![item];
let result = { let result = {
let mut iter = iter.inspect(|byte| if let &Ok(byte) = byte { let mut iter = iter.inspect(|byte| if let &Ok(byte) = byte {
buf.push(byte); buf.push(byte);
}); });
event::parse_event(item, &mut iter) event::parse_event(item, &mut iter)
}; };
result.or(Ok(Event::Unsupported(buf))) result.or(Ok(Event::Unsupported(buf)))
@ -216,9 +216,10 @@ mod test {
#[test] #[test]
fn test_events() { fn test_events() {
let mut i = b"\x1B[\x00bc\x7F\x1B[D\ let mut i =
b"\x1B[\x00bc\x7F\x1B[D\
\x1B[M\x00\x22\x24\x1B[<0;2;4;M\x1B[32;2;4M\x1B[<0;2;4;m\x1B[35;2;4Mb" \x1B[M\x00\x22\x24\x1B[<0;2;4;M\x1B[32;2;4M\x1B[<0;2;4;m\x1B[35;2;4Mb"
.events(); .events();
assert_eq!(i.next().unwrap().unwrap(), assert_eq!(i.next().unwrap().unwrap(),
Event::Unsupported(vec![0x1B, b'[', 0x00])); Event::Unsupported(vec![0x1B, b'[', 0x00]));
@ -249,7 +250,7 @@ mod test {
let mut st = b"\x1B[11~\x1B[12~\x1B[13~\x1B[14~\x1B[15~\ let mut st = b"\x1B[11~\x1B[12~\x1B[13~\x1B[14~\x1B[15~\
\x1B[17~\x1B[18~\x1B[19~\x1B[20~\x1B[21~\x1B[23~\x1B[24~" \x1B[17~\x1B[18~\x1B[19~\x1B[20~\x1B[21~\x1B[23~\x1B[24~"
.keys(); .keys();
for i in 1..13 { for i in 1..13 {
assert_eq!(st.next().unwrap().unwrap(), Key::F(i)); assert_eq!(st.next().unwrap().unwrap(), Key::F(i));
} }

View File

@ -129,9 +129,7 @@ impl<W: Write> IntoRawMode for W {
#[cfg(target_os = "redox")] #[cfg(target_os = "redox")]
fn into_raw_mode(mut self) -> io::Result<RawTerminal<W>> { fn into_raw_mode(mut self) -> io::Result<RawTerminal<W>> {
write!(self, csi!("?82h")).map(|_| { write!(self, csi!("?82h")).map(|_| RawTerminal { output: self })
RawTerminal { output: self }
})
} }
} }

View File

@ -56,9 +56,7 @@ impl<W: Write> AlternateScreen<W> {
/// to the alternate screen. /// to the alternate screen.
pub fn from(mut output: W) -> Self { pub fn from(mut output: W) -> Self {
write!(output, "{}", ToAlternateScreen).expect("switch to alternate screen"); write!(output, "{}", ToAlternateScreen).expect("switch to alternate screen");
AlternateScreen { AlternateScreen { output: output }
output: output,
}
} }
} }

View File

@ -16,5 +16,7 @@ derive_csi_sequence!("Undo italic text.", NoItalic, "23m");
derive_csi_sequence!("Undo underlined text.", NoUnderline, "24m"); derive_csi_sequence!("Undo underlined text.", NoUnderline, "24m");
derive_csi_sequence!("Undo blinking text (not widely supported).", NoBlink, "25m"); derive_csi_sequence!("Undo blinking text (not widely supported).", NoBlink, "25m");
derive_csi_sequence!("Undo inverted colors (negative mode).", NoInvert, "27m"); derive_csi_sequence!("Undo inverted colors (negative mode).", NoInvert, "27m");
derive_csi_sequence!("Undo crossed out text (not widely supported).", NoCrossedOut, "29m"); derive_csi_sequence!("Undo crossed out text (not widely supported).",
NoCrossedOut,
"29m");
derive_csi_sequence!("Framed text (not widely supported).", Framed, "51m"); derive_csi_sequence!("Framed text (not widely supported).", Framed, "51m");

View File

@ -9,7 +9,7 @@ pub const TIOCGWINSZ: usize = 0x00005413;
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
pub const TIOCGWINSZ: usize = 0x40087468; pub const TIOCGWINSZ: usize = 0x40087468;
extern { extern "C" {
pub fn tcgetattr(fd: c_int, termptr: *mut Termios) -> c_int; pub fn tcgetattr(fd: c_int, termptr: *mut Termios) -> c_int;
pub fn tcsetattr(fd: c_int, opt: c_int, termptr: *mut Termios) -> c_int; pub fn tcsetattr(fd: c_int, opt: c_int, termptr: *mut Termios) -> c_int;
pub fn cfmakeraw(termptr: *mut Termios); pub fn cfmakeraw(termptr: *mut Termios);
@ -24,9 +24,7 @@ pub fn get_terminal_attr() -> (Termios, c_int) {
} }
pub fn set_terminal_attr(ios: *mut Termios) -> c_int { pub fn set_terminal_attr(ios: *mut Termios) -> c_int {
unsafe { unsafe { tcsetattr(0, 0, ios) }
tcsetattr(0, 0, ios)
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -6,7 +6,7 @@ use std::os::unix::io::AsRawFd;
pub fn is_tty<T: AsRawFd>(stream: &T) -> bool { pub fn is_tty<T: AsRawFd>(stream: &T) -> bool {
use libc; use libc;
unsafe { libc::isatty(stream.as_raw_fd()) == 1} unsafe { libc::isatty(stream.as_raw_fd()) == 1 }
} }
/// This will panic. /// This will panic.