Run rustfmt on the code.
This commit is contained in:
parent
7351aa3f16
commit
15c65dc5f9
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
},
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
18
src/async.rs
18
src/async.rs
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
41
src/color.rs
41
src/color.rs
|
@ -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)?;
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
343
src/event.rs
343
src/event.rs
|
@ -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,
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
src/input.rs
11
src/input.rs
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 }
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue