aboutsummaryrefslogtreecommitdiffstats
path: root/src/command
diff options
context:
space:
mode:
Diffstat (limited to 'src/command')
-rw-r--r--src/command/history.rs8
-rw-r--r--src/command/login.rs7
-rw-r--r--src/command/mod.rs8
-rw-r--r--src/command/search.rs110
-rw-r--r--src/command/server.rs6
-rw-r--r--src/command/sync.rs4
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()?,