diff options
-rw-r--r-- | Cargo.toml | 4 | ||||
-rw-r--r-- | src/display/mod.rs | 186 | ||||
-rw-r--r-- | src/tw/events.rs | 1 | ||||
-rw-r--r-- | src/tw/mod.rs | 2 |
4 files changed, 125 insertions, 68 deletions
@@ -12,8 +12,8 @@ a nice twitter [[bin]] name = "twidder" # path = "main.rs" -# test = false -# bench = false +test = false +bench = false [dependencies] "termios" = "0.2.2" diff --git a/src/display/mod.rs b/src/display/mod.rs index fdb8448..c011294 100644 --- a/src/display/mod.rs +++ b/src/display/mod.rs @@ -1,6 +1,10 @@ extern crate termion; +use std::io::Write; +use std::io::stdout; + use self::termion::color; +use self::termion::{clear, cursor}; use ::tw; @@ -8,6 +12,7 @@ use ::tw::TweetId; use std; +#[derive(Clone)] pub enum Infos { Tweet(TweetId), Thread(Vec<TweetId>), @@ -16,27 +21,73 @@ pub enum Infos { } pub fn paint(tweeter: &mut ::tw::TwitterCache) { - println!("Painting, totally."); - println!("Statuses:"); - { - let to_show = tweeter.display_info.log.iter().rev().take(4).collect::<Vec<&String>>().into_iter().rev(); - for line in to_show { - println!("{}", line); - } - } + match termion::terminal_size() { + Ok((width, height)) => { + // draw input prompt + println!("{}{}", cursor::Goto(1, height - 6), clear::CurrentLine); + println!("{}{}>", cursor::Goto(1, height - 5), clear::CurrentLine); + println!("{}{}", cursor::Goto(1, height - 4), clear::CurrentLine); + let mut i = 0; + let log_size = 4; + let last_elem = tweeter.display_info.log.len().saturating_sub(log_size); + { + let to_show = tweeter.display_info.log.drain(last_elem..); + for line in to_show { + println!("{}{}{}", cursor::Goto(1, height - i), clear::CurrentLine, line); + i = i + 1; + } + } + while i < log_size as u16 { + println!("{}{}", cursor::Goto(1, height - i), clear::CurrentLine); + i = i + 1; + } + // draw status lines + // draw tweets + let last_twevent = tweeter.display_info.infos.len().saturating_sub(height as usize - 4); + let last_few_twevent: Vec<Infos> = tweeter.display_info.infos[last_twevent..].iter().map(|x| x.clone()).rev().collect::<Vec<Infos>>(); - if let Some(elem) = tweeter.display_info.infos.pop() { - match elem { - Infos::Tweet(id) => render_twete(&id, tweeter), - Infos::Thread(ids) => { - println!("I'd show a thread if I knew how"); - }, - Infos::Event(e) => { - e.render(tweeter); - }, - Infos::DM(msg) => { - println!("DM: {}", msg); + let mut h = 7; + for info in last_few_twevent { + let mut to_draw = match info { + Infos::Tweet(id) => { + render_twete(&id, tweeter).iter().map(|x| x.to_owned()).rev().collect() + } + Infos::Thread(ids) => { + vec![format!("{}{}I'd show a thread if I knew how", cursor::Goto(1, height - h), clear::CurrentLine)] + }, + Infos::Event(e) => { + e.clone().render(tweeter).into_iter().rev().collect() + }, + Infos::DM(msg) => { + vec![format!("{}{}DM: {}", cursor::Goto(1, height - h), clear::CurrentLine, msg)] + } + }; + for line in to_draw { + println!("{}{}{}", cursor::Goto(1, height - h), clear::CurrentLine, line); + h = h + 1; + if h >= height { + print!("{}", cursor::Goto(2, height - 6)); + stdout().flush(); + return; + } + } + println!("{}{}", cursor::Goto(1, height - h), clear::CurrentLine); + h = h + 1; + if h >= height { + print!("{}", cursor::Goto(2, height - 6)); + stdout().flush(); + return; + } } + while h < height { + println!("{}{}", cursor::Goto(1, height - h), clear::CurrentLine); + h = h + 1; + } + print!("{}", cursor::Goto(2, height - 6)); + stdout().flush(); + }, + Err(e) => { + println!("Can't get term dimensions: {}", e); } } } @@ -63,14 +114,15 @@ fn color_for(handle: &String) -> termion::color::Fg<&color::Color> { } pub trait Render { - fn render(self, tweeter: &mut ::tw::TwitterCache); + fn render(self, tweeter: &mut ::tw::TwitterCache) -> Vec<String>; } impl Render for tw::events::Event { - fn render(self, tweeter: &mut ::tw::TwitterCache) { + fn render(self, tweeter: &mut ::tw::TwitterCache) -> Vec<String> { + let mut result = Vec::new(); match self { tw::events::Event::Quoted { user_id, twete_id } => { - println!("---------------------------------"); + result.push("---------------------------------".to_string()); { let user = tweeter.retrieve_user(&user_id).unwrap(); println!(" quoted_tweet : {} (@{})", user.name, user.handle); @@ -80,75 +132,75 @@ impl Render for tw::events::Event { tw::events::Event::Deleted { user_id, twete_id } => { if let Some(handle) = tweeter.retrieve_user(&user_id).map(|x| &x.handle).map(|x| x.clone()) { if let Some(_tweet) = tweeter.retrieve_tweet(&TweetId::Twitter(twete_id.to_owned())).map(|x| x.clone()) { - println!("-------------DELETED------------------"); - render_twete(&TweetId::Twitter(twete_id), tweeter); - println!("-------------DELETED------------------"); + result.push(format!("-------------DELETED------------------")); + result.extend(render_twete(&TweetId::Twitter(twete_id), tweeter)); + result.push(format!("-------------DELETED------------------")); } else { - println!("dunno what, but do know who: {} - {}", user_id, handle); + result.push(format!("dunno what, but do know who: {} - {}", user_id, handle)); } } else { - println!("delete..."); - println!("dunno who..."); + result.push("delete... dunno who".to_string()); } }, tw::events::Event::RT_RT { user_id, twete_id } => { - println!("---------------------------------"); + result.push("---------------------------------".to_string()); { let user = tweeter.retrieve_user(&user_id).unwrap(); - println!(" +rt_rt : {} (@{})", user.name, user.handle); + result.push(format!(" +rt_rt : {} (@{})", user.name, user.handle)); } - render_twete(&TweetId::Twitter(twete_id), tweeter); + result.extend(render_twete(&TweetId::Twitter(twete_id), tweeter)); }, tw::events::Event::Fav_RT { user_id, twete_id } => { - println!("---------------------------------"); + result.push("---------------------------------".to_string()); if let Some(user) = tweeter.retrieve_user(&user_id) { - println!(" +rt_fav : {} (@{})", user.name, user.handle); + result.push(format!(" +rt_fav : {} (@{})", user.name, user.handle)); } else { - println!(" +rt_fav but don't know who {} is", user_id); + result.push(format!(" +rt_fav but don't know who {} is", user_id)); } - render_twete(&TweetId::Twitter(twete_id), tweeter); + result.extend(render_twete(&TweetId::Twitter(twete_id), tweeter)); }, tw::events::Event::Fav { user_id, twete_id } => { - println!("---------------------------------"); + result.push("---------------------------------".to_string()); { let user = tweeter.retrieve_user(&user_id).unwrap(); - println!("{} +fav : {} (@{}){}", color::Fg(color::Yellow), user.name, user.handle, color::Fg(color::Reset)); + result.push(format!("{} +fav : {} (@{}){}", color::Fg(color::Yellow), user.name, user.handle, color::Fg(color::Reset))); } - render_twete(&TweetId::Twitter(twete_id), tweeter); + result.extend(render_twete(&TweetId::Twitter(twete_id), tweeter)); }, tw::events::Event::Unfav { user_id, twete_id } => { - println!("---------------------------------"); + result.push("---------------------------------".to_string()); { let user = tweeter.retrieve_user(&user_id).unwrap(); - println!("{} -fav : {} (@{}){}", color::Fg(color::Yellow), user.name, user.handle, color::Fg(color::Reset)); + result.push(format!("{} -fav : {} (@{}){}", color::Fg(color::Yellow), user.name, user.handle, color::Fg(color::Reset))); } - render_twete(&TweetId::Twitter(twete_id), tweeter); + result.extend(render_twete(&TweetId::Twitter(twete_id), tweeter)); }, tw::events::Event::Followed { user_id } => { - println!("---------------------------------"); + result.push("---------------------------------".to_string()); let user = tweeter.retrieve_user(&user_id).unwrap(); - println!(" +fl : {} (@{})", user.name, user.handle); + result.push(format!(" +fl : {} (@{})", user.name, user.handle)); }, tw::events::Event::Unfollowed { user_id } => { - println!("---------------------------------"); + result.push("---------------------------------".to_string()); let user = tweeter.retrieve_user(&user_id).unwrap(); - println!(" -fl : {} (@{})", user.name, user.handle); + result.push(format!(" -fl : {} (@{})", user.name, user.handle)); } /* Blocked(user_id) => { }, */ } - println!(""); + result } } -pub fn render_twete(twete_id: &TweetId, tweeter: &mut tw::TwitterCache) { +pub fn render_twete(twete_id: &TweetId, tweeter: &mut tw::TwitterCache) -> Vec<String> { + let mut result = Vec::new(); let id_color = color::Fg(color::Rgb(180, 80, 40)); let maybe_twete = tweeter.retrieve_tweet(twete_id).map(|x| x.clone()); if maybe_twete.is_none() { - println!("No such tweet: {:?}", twete_id); - return; + result.push(format!("No such tweet: {:?}", twete_id)); + return result; } let twete = maybe_twete.unwrap(); // if we got the tweet, the API gave us the user too @@ -159,7 +211,7 @@ pub fn render_twete(twete_id: &TweetId, tweeter: &mut tw::TwitterCache) { let rt = tweeter.retrieve_tweet(&TweetId::Twitter(rt_id.to_owned())).unwrap().clone(); // and its author let rt_author = tweeter.retrieve_user(&rt.author_id).unwrap().clone(); - println!("{} id:{} (rt_id:{}){}{}", + result.push(format!("{} id:{} (rt_id:{}){}{}", id_color, rt.internal_id, twete.internal_id, rt.reply_to_tweet.clone() .map(|id| tweeter.retrieve_tweet(&TweetId::Twitter(id.to_owned())) @@ -168,16 +220,16 @@ pub fn render_twete(twete_id: &TweetId, tweeter: &mut tw::TwitterCache) { ) .unwrap_or("".to_string()), color::Fg(color::Reset) - ); - println!(" {}{}{} ({}@{}{}) via {}{}{} ({}@{}{}) RT:", + )); + result.push(format!(" {}{}{} ({}@{}{}) via {}{}{} ({}@{}{}) RT:", color_for(&rt_author.handle), rt_author.name, color::Fg(color::Reset), color_for(&rt_author.handle), rt_author.handle, color::Fg(color::Reset), color_for(&user.handle), user.name, color::Fg(color::Reset), color_for(&user.handle), user.handle, color::Fg(color::Reset) - ); + )); } None => { - println!("{} id:{}{}{}", + result.push(format!("{} id:{}{}{}", id_color, twete.internal_id, twete.reply_to_tweet.clone() .map(|id| tweeter.retrieve_tweet(&TweetId::Twitter(id.to_owned())) @@ -186,21 +238,23 @@ pub fn render_twete(twete_id: &TweetId, tweeter: &mut tw::TwitterCache) { ) .unwrap_or("".to_string()), color::Fg(color::Reset) - ); - println!(" {}{}{} ({}@{}{})", + )); + result.push(format!(" {}{}{} ({}@{}{})", color_for(&user.handle), user.name, color::Fg(color::Reset), color_for(&user.handle), user.handle, color::Fg(color::Reset) - ); + )); } } - println!(" {}", twete.text.replace("\r", "\\r").split("\n").collect::<Vec<&str>>().join("\n ")); + result.extend( + format!(" {}", twete.text.replace("\r", "\\r").split("\n").collect::<Vec<&str>>().join("\n ")).split("\n").map(|x| x.to_owned()) + ); if let Some(ref qt_id) = twete.quoted_tweet_id { let maybe_qt = tweeter.retrieve_tweet(&TweetId::Twitter(qt_id.to_owned())).map(|x| x.to_owned()); if let Some(qt) = maybe_qt { let qt_author = tweeter.retrieve_user(&qt.author_id).unwrap().clone(); - println!("{} id:{}{}{}", + result.push(format!("{} id:{}{}{}", id_color, qt.internal_id, qt.reply_to_tweet.clone() .map(|id| tweeter.retrieve_tweet(&TweetId::Twitter(id.to_owned())) @@ -209,18 +263,20 @@ pub fn render_twete(twete_id: &TweetId, tweeter: &mut tw::TwitterCache) { ) .unwrap_or("".to_string()), color::Fg(color::Reset) - ); - println!( + )); + result.push(format!( " {}{}{} ({}@{}{})", color_for(&qt_author.handle), qt_author.name, color::Fg(color::Reset), color_for(&qt_author.handle), qt_author.handle, color::Fg(color::Reset) - ); - println!( + )); + result.push(format!( " {}", qt.text.replace("\r", "\\r").split("\n").collect::<Vec<&str>>().join("\n ") - ); + )); } else { - println!(" << don't have quoted tweet! >>"); + result.push(format!(" << don't have quoted tweet! >>")); } } + + result } diff --git a/src/tw/events.rs b/src/tw/events.rs index c26a840..afc7fbb 100644 --- a/src/tw/events.rs +++ b/src/tw/events.rs @@ -1,5 +1,6 @@ extern crate serde_json; +#[derive(Clone)] pub enum Event { Deleted { user_id: String, twete_id: String }, RT_RT { user_id: String, twete_id: String }, diff --git a/src/tw/mod.rs b/src/tw/mod.rs index f2582cf..0341ec9 100644 --- a/src/tw/mod.rs +++ b/src/tw/mod.rs @@ -135,7 +135,7 @@ impl Default for IdConversions { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] pub enum TweetId { Today(u64), // just a number Dated(String, u64), // 20171002:number |