diff options
| author | Ellie Huxtable <e@elm.sh> | 2021-04-20 17:07:11 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-04-20 16:07:11 +0000 |
| commit | 34888827f8a06de835cbe5833a06914f28cce514 (patch) | |
| tree | 8b56f20e50065cd2c222d5e8e067ec55cf1947a1 /src/command | |
| parent | Optimise docker (#34) (diff) | |
| download | atuin-34888827f8a06de835cbe5833a06914f28cce514.zip | |
Switch to Warp + SQLx, use async, switch to Rust stable (#36)
* Switch to warp + sql, use async and stable rust
* Update CI to use stable
Diffstat (limited to 'src/command')
| -rw-r--r-- | src/command/history.rs | 8 | ||||
| -rw-r--r-- | src/command/login.rs | 7 | ||||
| -rw-r--r-- | src/command/mod.rs | 8 | ||||
| -rw-r--r-- | src/command/search.rs | 110 | ||||
| -rw-r--r-- | src/command/server.rs | 6 | ||||
| -rw-r--r-- | src/command/sync.rs | 4 |
6 files changed, 103 insertions, 40 deletions
diff --git a/src/command/history.rs b/src/command/history.rs index 3b4a717c..627efae4 100644 --- a/src/command/history.rs +++ b/src/command/history.rs @@ -53,7 +53,7 @@ fn print_list(h: &[History]) { } impl Cmd { - pub fn run(&self, settings: &Settings, db: &mut impl Database) -> Result<()> { + pub async fn run(&self, settings: &Settings, db: &mut (impl Database + Send)) -> Result<()> { match self { Self::Start { command: words } => { let command = words.join(" "); @@ -69,6 +69,10 @@ impl Cmd { } Self::End { id, exit } => { + if id.trim() == "" { + return Ok(()); + } + let mut h = db.load(id)?; h.exit = *exit; h.duration = chrono::Utc::now().timestamp_nanos() - h.timestamp.timestamp_nanos(); @@ -82,7 +86,7 @@ impl Cmd { } Ok(Fork::Child) => { debug!("running periodic background sync"); - sync::sync(settings, false, db)?; + sync::sync(settings, false, db).await?; } Err(_) => println!("Fork failed"), } diff --git a/src/command/login.rs b/src/command/login.rs index 4f58b77f..636ac0d3 100644 --- a/src/command/login.rs +++ b/src/command/login.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::fs::File; use std::io::prelude::*; -use eyre::Result; +use eyre::{eyre, Result}; use structopt::StructOpt; use crate::settings::Settings; @@ -28,8 +28,13 @@ impl Cmd { let url = format!("{}/login", settings.local.sync_address); let client = reqwest::blocking::Client::new(); + let resp = client.post(url).json(&map).send()?; + if resp.status() != reqwest::StatusCode::OK { + return Err(eyre!("invalid login details")); + } + let session = resp.json::<HashMap<String, String>>()?; let session = session["session"].clone(); diff --git a/src/command/mod.rs b/src/command/mod.rs index eeb11a87..cd857e9f 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -63,16 +63,16 @@ pub fn uuid_v4() -> String { } impl AtuinCmd { - pub fn run(self, db: &mut impl Database, settings: &Settings) -> Result<()> { + pub async fn run<T: Database + Send>(self, db: &mut T, settings: &Settings) -> Result<()> { match self { - Self::History(history) => history.run(settings, db), + Self::History(history) => history.run(settings, db).await, Self::Import(import) => import.run(db), - Self::Server(server) => server.run(settings), + Self::Server(server) => server.run(settings).await, Self::Stats(stats) => stats.run(db, settings), Self::Init => init::init(), Self::Search { query } => search::run(&query, db), - Self::Sync { force } => sync::run(settings, force, db), + Self::Sync { force } => sync::run(settings, force, db).await, Self::Login(l) => l.run(settings), Self::Register(r) => register::run( settings, diff --git a/src/command/search.rs b/src/command/search.rs index b9f3987c..d7b477da 100644 --- a/src/command/search.rs +++ b/src/command/search.rs @@ -1,6 +1,8 @@ use eyre::Result; use itertools::Itertools; use std::io::stdout; +use std::time::Duration; + use termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::AlternateScreen}; use tui::{ backend::TermionBackend, @@ -26,6 +28,78 @@ struct State { results_state: ListState, } +#[allow(clippy::clippy::cast_sign_loss)] +impl State { + fn durations(&self) -> Vec<String> { + self.results + .iter() + .map(|h| { + let duration = + Duration::from_millis(std::cmp::max(h.duration, 0) as u64 / 1_000_000); + let duration = humantime::format_duration(duration).to_string(); + let duration: Vec<&str> = duration.split(' ').collect(); + + duration[0].to_string() + }) + .collect() + } + + fn render_results<T: tui::backend::Backend>( + &mut self, + f: &mut tui::Frame<T>, + r: tui::layout::Rect, + ) { + let durations = self.durations(); + let max_length = durations + .iter() + .fold(0, |largest, i| std::cmp::max(largest, i.len())); + + let results: Vec<ListItem> = self + .results + .iter() + .enumerate() + .map(|(i, m)| { + let command = m.command.to_string().replace("\n", " ").replace("\t", " "); + + let mut command = Span::raw(command); + + let mut duration = durations[i].clone(); + + while duration.len() < max_length { + duration.push(' '); + } + + let duration = Span::styled( + duration, + Style::default().fg(if m.exit == 0 || m.duration == -1 { + Color::Green + } else { + Color::Red + }), + ); + + if let Some(selected) = self.results_state.selected() { + if selected == i { + command.style = + Style::default().fg(Color::Red).add_modifier(Modifier::BOLD); + } + } + + let spans = Spans::from(vec![duration, Span::raw(" "), command]); + + ListItem::new(spans) + }) + .collect(); + + let results = List::new(results) + .block(Block::default().borders(Borders::ALL).title("History")) + .start_corner(Corner::BottomLeft) + .highlight_symbol(">> "); + + f.render_stateful_widget(results, r, &mut self.results_state); + } +} + fn query_results(app: &mut State, db: &mut impl Database) { let results = match app.input.as_str() { "" => db.list(), @@ -48,7 +122,11 @@ fn key_handler(input: Key, db: &mut impl Database, app: &mut State) -> Option<St Key::Esc | Key::Char('\n') => { let i = app.results_state.selected().unwrap_or(0); - return Some(app.results.get(i).unwrap().command.clone()); + return Some( + app.results + .get(i) + .map_or("".to_string(), |h| h.command.clone()), + ); } Key::Char(c) => { app.input.push(c); @@ -163,32 +241,8 @@ fn select_history(query: &[String], db: &mut impl Database) -> Result<String> { let help = Text::from(Spans::from(help)); let help = Paragraph::new(help); - let input = Paragraph::new(app.input.as_ref()) - .block(Block::default().borders(Borders::ALL).title("Search")); - - let results: Vec<ListItem> = app - .results - .iter() - .enumerate() - .map(|(i, m)| { - let mut content = - Span::raw(m.command.to_string().replace("\n", " ").replace("\t", " ")); - - if let Some(selected) = app.results_state.selected() { - if selected == i { - content.style = - Style::default().fg(Color::Red).add_modifier(Modifier::BOLD); - } - } - - ListItem::new(content) - }) - .collect(); - - let results = List::new(results) - .block(Block::default().borders(Borders::ALL).title("History")) - .start_corner(Corner::BottomLeft) - .highlight_symbol(">> "); + let input = Paragraph::new(app.input.clone()) + .block(Block::default().borders(Borders::ALL).title("Query")); let stats = Paragraph::new(Text::from(Span::raw(format!( "history count: {}", @@ -199,8 +253,8 @@ fn select_history(query: &[String], db: &mut impl Database) -> Result<String> { f.render_widget(title, top_left_chunks[0]); f.render_widget(help, top_left_chunks[1]); + app.render_results(f, chunks[1]); f.render_widget(stats, top_right_chunks[0]); - f.render_stateful_widget(results, chunks[1], &mut app.results_state); f.render_widget(input, chunks[2]); f.set_cursor( diff --git a/src/command/server.rs b/src/command/server.rs index bf757948..a7835092 100644 --- a/src/command/server.rs +++ b/src/command/server.rs @@ -1,7 +1,7 @@ use eyre::Result; use structopt::StructOpt; -use crate::remote::server; +use crate::server; use crate::settings::Settings; #[derive(StructOpt)] @@ -20,7 +20,7 @@ pub enum Cmd { } impl Cmd { - pub fn run(&self, settings: &Settings) -> Result<()> { + pub async fn run(&self, settings: &Settings) -> Result<()> { match self { Self::Start { host, port } => { let host = host.as_ref().map_or( @@ -29,7 +29,7 @@ impl Cmd { ); let port = port.map_or(settings.server.port, |p| p); - server::launch(settings, host, port) + server::launch(settings, host, port).await } } } diff --git a/src/command/sync.rs b/src/command/sync.rs index facbe578..88217b3c 100644 --- a/src/command/sync.rs +++ b/src/command/sync.rs @@ -4,8 +4,8 @@ use crate::local::database::Database; use crate::local::sync; use crate::settings::Settings; -pub fn run(settings: &Settings, force: bool, db: &mut impl Database) -> Result<()> { - sync::sync(settings, force, db)?; +pub async fn run(settings: &Settings, force: bool, db: &mut (impl Database + Send)) -> Result<()> { + sync::sync(settings, force, db).await?; println!( "Sync complete! {} items in database, force: {}", db.history_count()?, |
