mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Use async input for termion backend
This enables async refresh, fixing the `logs` and `progress` examples.
This commit is contained in:
parent
89ec140f41
commit
ea3dde33ec
@ -2,22 +2,28 @@ extern crate termion;
|
|||||||
|
|
||||||
use ::backend;
|
use ::backend;
|
||||||
use ::event::{Event, Key};
|
use ::event::{Event, Key};
|
||||||
use self::termion::color;
|
use self::termion::color as tcolor;
|
||||||
use self::termion::event::Key as TKey;
|
use self::termion::event::Key as TKey;
|
||||||
use self::termion::input::TermRead;
|
use self::termion::input::TermRead;
|
||||||
use self::termion::style;
|
|
||||||
use self::termion::raw::IntoRawMode;
|
use self::termion::raw::IntoRawMode;
|
||||||
|
use self::termion::style as tstyle;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::io::Write;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::thread;
|
||||||
|
use std::time;
|
||||||
|
|
||||||
use ::theme;
|
use ::theme;
|
||||||
|
|
||||||
pub struct Concrete {
|
pub struct Concrete {
|
||||||
terminal: termion::raw::RawTerminal<::std::io::Stdout>,
|
terminal: termion::raw::RawTerminal<::std::io::Stdout>,
|
||||||
current_style: Cell<theme::ColorStyle>,
|
current_style: Cell<theme::ColorStyle>,
|
||||||
colors: BTreeMap<i16, (Box<color::Color>, Box<color::Color>)>,
|
colors: BTreeMap<i16, (Box<tcolor::Color>, Box<tcolor::Color>)>,
|
||||||
|
|
||||||
|
input: mpsc::Receiver<Event>,
|
||||||
|
timeout: Option<time::Duration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Effectable {
|
trait Effectable {
|
||||||
@ -25,10 +31,9 @@ trait Effectable {
|
|||||||
fn off(&self);
|
fn off(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ColorRef<'a>(&'a color::Color);
|
struct ColorRef<'a>(&'a tcolor::Color);
|
||||||
|
|
||||||
impl <'a> color::Color for ColorRef<'a> {
|
|
||||||
|
|
||||||
|
impl<'a> tcolor::Color for ColorRef<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.0.write_fg(f)
|
self.0.write_fg(f)
|
||||||
@ -38,27 +43,26 @@ impl <'a> color::Color for ColorRef<'a> {
|
|||||||
fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.0.write_bg(f)
|
self.0.write_bg(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Effectable for theme::Effect {
|
impl Effectable for theme::Effect {
|
||||||
fn on(&self) {
|
fn on(&self) {
|
||||||
match *self {
|
match *self {
|
||||||
theme::Effect::Simple => (),
|
theme::Effect::Simple => (),
|
||||||
theme::Effect::Reverse => print!("{}", style::Invert),
|
theme::Effect::Reverse => print!("{}", tstyle::Invert),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn off(&self) {
|
fn off(&self) {
|
||||||
match *self {
|
match *self {
|
||||||
theme::Effect::Simple => (),
|
theme::Effect::Simple => (),
|
||||||
theme::Effect::Reverse => print!("{}", style::NoInvert),
|
theme::Effect::Reverse => print!("{}", tstyle::NoInvert),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_colors(fg: &color::Color, bg: &color::Color) {
|
fn apply_colors(fg: &tcolor::Color, bg: &tcolor::Color) {
|
||||||
print!("{}{}", color::Fg(ColorRef(fg)), color::Bg(ColorRef(bg)));
|
print!("{}{}", tcolor::Fg(ColorRef(fg)), tcolor::Bg(ColorRef(bg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Concrete {
|
impl Concrete {
|
||||||
@ -71,18 +75,33 @@ impl Concrete {
|
|||||||
impl backend::Backend for Concrete {
|
impl backend::Backend for Concrete {
|
||||||
fn init() -> Self {
|
fn init() -> Self {
|
||||||
print!("{}", termion::cursor::Hide);
|
print!("{}", termion::cursor::Hide);
|
||||||
|
let terminal = ::std::io::stdout().into_raw_mode().unwrap();
|
||||||
|
let (sender, receiver) = mpsc::channel();
|
||||||
|
|
||||||
|
// TODO: use signal_chan crate
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
for key in ::std::io::stdin().keys() {
|
||||||
|
if let Ok(key) = key {
|
||||||
|
if sender.send(map_key(key)).is_err() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let backend = Concrete {
|
let backend = Concrete {
|
||||||
terminal: ::std::io::stdout().into_raw_mode().unwrap(),
|
terminal: terminal,
|
||||||
current_style: Cell::new(theme::ColorStyle::Background),
|
current_style: Cell::new(theme::ColorStyle::Background),
|
||||||
colors: BTreeMap::new(),
|
colors: BTreeMap::new(),
|
||||||
|
input: receiver,
|
||||||
|
timeout: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
backend
|
backend
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&mut self) {
|
fn finish(&mut self) {
|
||||||
// Maybe we should clear everything?
|
|
||||||
print!("{}{}", termion::cursor::Show, termion::cursor::Goto(1, 1));
|
print!("{}{}", termion::cursor::Show, termion::cursor::Goto(1, 1));
|
||||||
self.clear();
|
self.clear();
|
||||||
}
|
}
|
||||||
@ -148,83 +167,90 @@ impl backend::Backend for Concrete {
|
|||||||
// TODO: handle async refresh, when no input is entered.
|
// TODO: handle async refresh, when no input is entered.
|
||||||
// Could be done with a timeout on the event polling,
|
// Could be done with a timeout on the event polling,
|
||||||
// if it was supportedd.
|
// if it was supportedd.
|
||||||
|
self.timeout = Some(time::Duration::from_millis(1000 / fps as u64));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_event(&self) -> Event {
|
fn poll_event(&self) -> Event {
|
||||||
// TODO: parse input
|
// TODO: select! on the input and SIGWINCH signal channel.
|
||||||
if let Some(key) = ::std::io::stdin().keys().next() {
|
// TODO: also handle timeout... recv_timeout?
|
||||||
match key.unwrap() {
|
if let Some(timeout) = self.timeout {
|
||||||
TKey::Esc => Event::Key(Key::Esc),
|
self.input.recv_timeout(timeout).unwrap_or(Event::Refresh)
|
||||||
TKey::Backspace => Event::Key(Key::Backspace),
|
|
||||||
TKey::Left => Event::Key(Key::Left),
|
|
||||||
TKey::Right => Event::Key(Key::Right),
|
|
||||||
TKey::Up => Event::Key(Key::Up),
|
|
||||||
TKey::Down => Event::Key(Key::Down),
|
|
||||||
TKey::Home => Event::Key(Key::Home),
|
|
||||||
TKey::End => Event::Key(Key::End),
|
|
||||||
TKey::PageUp => Event::Key(Key::PageUp),
|
|
||||||
TKey::PageDown => Event::Key(Key::PageDown),
|
|
||||||
TKey::Delete => Event::Key(Key::Del),
|
|
||||||
TKey::Insert => Event::Key(Key::Ins),
|
|
||||||
TKey::F(i) if i < 12 => Event::Key(Key::from_f(i)),
|
|
||||||
TKey::F(j) => Event::Unknown(-(j as i32)),
|
|
||||||
TKey::Char('\n') => Event::Key(Key::Enter),
|
|
||||||
TKey::Char('\t') => Event::Key(Key::Tab),
|
|
||||||
TKey::Char(c) => Event::Char(c),
|
|
||||||
TKey::Ctrl('c') => panic!("Ctrl-C pressed"),
|
|
||||||
TKey::Ctrl(c) => Event::CtrlChar(c),
|
|
||||||
TKey::Alt(c) => Event::AltChar(c),
|
|
||||||
_ => Event::Unknown(-1),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Event::Refresh
|
self.input.recv().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn colour_to_termion_colour(clr: &theme::Color) -> Box<color::Color> {
|
fn map_key(key: TKey) -> Event {
|
||||||
|
match key {
|
||||||
|
TKey::Esc => Event::Key(Key::Esc),
|
||||||
|
TKey::Backspace => Event::Key(Key::Backspace),
|
||||||
|
TKey::Left => Event::Key(Key::Left),
|
||||||
|
TKey::Right => Event::Key(Key::Right),
|
||||||
|
TKey::Up => Event::Key(Key::Up),
|
||||||
|
TKey::Down => Event::Key(Key::Down),
|
||||||
|
TKey::Home => Event::Key(Key::Home),
|
||||||
|
TKey::End => Event::Key(Key::End),
|
||||||
|
TKey::PageUp => Event::Key(Key::PageUp),
|
||||||
|
TKey::PageDown => Event::Key(Key::PageDown),
|
||||||
|
TKey::Delete => Event::Key(Key::Del),
|
||||||
|
TKey::Insert => Event::Key(Key::Ins),
|
||||||
|
TKey::F(i) if i < 12 => Event::Key(Key::from_f(i)),
|
||||||
|
TKey::F(j) => Event::Unknown(-(j as i32)),
|
||||||
|
TKey::Char('\n') => Event::Key(Key::Enter),
|
||||||
|
TKey::Char('\t') => Event::Key(Key::Tab),
|
||||||
|
TKey::Char(c) => Event::Char(c),
|
||||||
|
TKey::Ctrl('c') => Event::Exit,
|
||||||
|
TKey::Ctrl(c) => Event::CtrlChar(c),
|
||||||
|
TKey::Alt(c) => Event::AltChar(c),
|
||||||
|
_ => Event::Unknown(-1),
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn colour_to_termion_colour(clr: &theme::Color) -> Box<tcolor::Color> {
|
||||||
match *clr {
|
match *clr {
|
||||||
theme::Color::Dark(theme::BaseColor::Black) => Box::new(color::Black),
|
theme::Color::Dark(theme::BaseColor::Black) => Box::new(tcolor::Black),
|
||||||
theme::Color::Dark(theme::BaseColor::Red) => Box::new(color::Red),
|
theme::Color::Dark(theme::BaseColor::Red) => Box::new(tcolor::Red),
|
||||||
theme::Color::Dark(theme::BaseColor::Green) => Box::new(color::Green),
|
theme::Color::Dark(theme::BaseColor::Green) => Box::new(tcolor::Green),
|
||||||
theme::Color::Dark(theme::BaseColor::Yellow) => {
|
theme::Color::Dark(theme::BaseColor::Yellow) => {
|
||||||
Box::new(color::Yellow)
|
Box::new(tcolor::Yellow)
|
||||||
}
|
}
|
||||||
theme::Color::Dark(theme::BaseColor::Blue) => Box::new(color::Blue),
|
theme::Color::Dark(theme::BaseColor::Blue) => Box::new(tcolor::Blue),
|
||||||
theme::Color::Dark(theme::BaseColor::Magenta) => {
|
theme::Color::Dark(theme::BaseColor::Magenta) => {
|
||||||
Box::new(color::Magenta)
|
Box::new(tcolor::Magenta)
|
||||||
}
|
}
|
||||||
theme::Color::Dark(theme::BaseColor::Cyan) => Box::new(color::Cyan),
|
theme::Color::Dark(theme::BaseColor::Cyan) => Box::new(tcolor::Cyan),
|
||||||
theme::Color::Dark(theme::BaseColor::White) => Box::new(color::White),
|
theme::Color::Dark(theme::BaseColor::White) => Box::new(tcolor::White),
|
||||||
|
|
||||||
theme::Color::Light(theme::BaseColor::Black) => {
|
theme::Color::Light(theme::BaseColor::Black) => {
|
||||||
Box::new(color::LightBlack)
|
Box::new(tcolor::LightBlack)
|
||||||
}
|
}
|
||||||
theme::Color::Light(theme::BaseColor::Red) => {
|
theme::Color::Light(theme::BaseColor::Red) => {
|
||||||
Box::new(color::LightRed)
|
Box::new(tcolor::LightRed)
|
||||||
}
|
}
|
||||||
theme::Color::Light(theme::BaseColor::Green) => {
|
theme::Color::Light(theme::BaseColor::Green) => {
|
||||||
Box::new(color::LightGreen)
|
Box::new(tcolor::LightGreen)
|
||||||
}
|
}
|
||||||
theme::Color::Light(theme::BaseColor::Yellow) => {
|
theme::Color::Light(theme::BaseColor::Yellow) => {
|
||||||
Box::new(color::LightYellow)
|
Box::new(tcolor::LightYellow)
|
||||||
}
|
}
|
||||||
theme::Color::Light(theme::BaseColor::Blue) => {
|
theme::Color::Light(theme::BaseColor::Blue) => {
|
||||||
Box::new(color::LightBlue)
|
Box::new(tcolor::LightBlue)
|
||||||
}
|
}
|
||||||
theme::Color::Light(theme::BaseColor::Magenta) => {
|
theme::Color::Light(theme::BaseColor::Magenta) => {
|
||||||
Box::new(color::LightMagenta)
|
Box::new(tcolor::LightMagenta)
|
||||||
}
|
}
|
||||||
theme::Color::Light(theme::BaseColor::Cyan) => {
|
theme::Color::Light(theme::BaseColor::Cyan) => {
|
||||||
Box::new(color::LightCyan)
|
Box::new(tcolor::LightCyan)
|
||||||
}
|
}
|
||||||
theme::Color::Light(theme::BaseColor::White) => {
|
theme::Color::Light(theme::BaseColor::White) => {
|
||||||
Box::new(color::LightWhite)
|
Box::new(tcolor::LightWhite)
|
||||||
}
|
}
|
||||||
|
|
||||||
theme::Color::Rgb(r, g, b) => Box::new(color::Rgb(r, g, b)),
|
theme::Color::Rgb(r, g, b) => Box::new(tcolor::Rgb(r, g, b)),
|
||||||
theme::Color::RgbLowRes(r, g, b) => {
|
theme::Color::RgbLowRes(r, g, b) => {
|
||||||
Box::new(color::AnsiValue::rgb(r, g, b))
|
Box::new(tcolor::AnsiValue::rgb(r, g, b))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user