aboutsummaryrefslogtreecommitdiffstats
path: root/src/command
diff options
context:
space:
mode:
authorEllie Huxtable <e@elm.sh>2021-02-13 19:37:00 +0000
committerEllie Huxtable <e@elm.sh>2021-02-13 19:37:31 +0000
commit099afe66ecfb569a8a04b66425ded29665e6a37c (patch)
tree7bb1baadb9304fa0d4f353d0849f962e2af209e3 /src/command
parentRecord command exit code and duration (diff)
downloadatuin-099afe66ecfb569a8a04b66425ded29665e6a37c.zip
Implement history import
Diffstat (limited to 'src/command')
-rw-r--r--src/command/history.rs63
-rw-r--r--src/command/import.rs107
-rw-r--r--src/command/mod.rs2
3 files changed, 172 insertions, 0 deletions
diff --git a/src/command/history.rs b/src/command/history.rs
new file mode 100644
index 00000000..72f821c5
--- /dev/null
+++ b/src/command/history.rs
@@ -0,0 +1,63 @@
+use std::env;
+
+use eyre::Result;
+use structopt::StructOpt;
+
+use crate::local::database::{Database, SqliteDatabase};
+use crate::local::history::History;
+
+#[derive(StructOpt)]
+pub enum HistoryCmd {
+ #[structopt(
+ about="begins a new command in the history",
+ aliases=&["s", "st", "sta", "star"],
+ )]
+ Start { command: Vec<String> },
+
+ #[structopt(
+ about="finishes a new command in the history (adds time, exit code)",
+ aliases=&["e", "en"],
+ )]
+ End {
+ id: String,
+ #[structopt(long, short)]
+ exit: i64,
+ },
+
+ #[structopt(
+ about="list all items in history",
+ aliases=&["l", "li", "lis"],
+ )]
+ List,
+}
+
+impl HistoryCmd {
+ pub fn run(&self, db: SqliteDatabase) -> Result<()> {
+ match self {
+ HistoryCmd::Start { command: words } => {
+ let command = words.join(" ");
+ let cwd = env::current_dir()?.display().to_string();
+
+ let h = History::new(chrono::Utc::now().timestamp_nanos(), command, cwd, -1, -1);
+
+ // print the ID
+ // we use this as the key for calling end
+ println!("{}", h.id);
+ db.save(h)?;
+ Ok(())
+ }
+
+ HistoryCmd::End { id, exit } => {
+ let mut h = db.load(id)?;
+ h.exit = *exit;
+ h.duration = chrono::Utc::now().timestamp_nanos() - h.timestamp;
+
+ db.update(h)?;
+
+ Ok(())
+ }
+
+ HistoryCmd::List => db.list(),
+ }
+ }
+}
diff --git a/src/command/import.rs b/src/command/import.rs
new file mode 100644
index 00000000..5ece13a8
--- /dev/null
+++ b/src/command/import.rs
@@ -0,0 +1,107 @@
+use std::env;
+use std::path::PathBuf;
+
+use eyre::{eyre, Result};
+use home::home_dir;
+use structopt::StructOpt;
+
+use crate::local::database::{Database, SqliteDatabase};
+use crate::local::history::History;
+use crate::local::import::ImportZsh;
+use indicatif::ProgressBar;
+
+#[derive(StructOpt)]
+pub enum ImportCmd {
+ #[structopt(
+ about="import history for the current shell",
+ aliases=&["a", "au", "aut"],
+ )]
+ Auto,
+
+ #[structopt(
+ about="import history from the zsh history file",
+ aliases=&["z", "zs"],
+ )]
+ Zsh,
+}
+
+impl ImportCmd {
+ fn import_zsh(&self, db: &mut SqliteDatabase) -> Result<()> {
+ // oh-my-zsh sets HISTFILE=~/.zhistory
+ // zsh has no default value for this var, but uses ~/.zhistory.
+ // we could maybe be smarter about this in the future :)
+
+ let histpath = env::var("HISTFILE");
+
+ let histpath = match histpath {
+ Ok(p) => PathBuf::from(p),
+ Err(_) => {
+ let mut home = home_dir().unwrap();
+ home.push(".zhistory");
+
+ home
+ }
+ };
+
+ if !histpath.exists() {
+ return Err(eyre!(
+ "Could not find history file at {}, try setting $HISTFILE",
+ histpath.to_str().unwrap()
+ ));
+ }
+
+ let zsh = ImportZsh::new(histpath.to_str().unwrap())?;
+
+ let progress = ProgressBar::new(zsh.loc);
+
+ let buf_size = 100;
+ let mut buf = Vec::<History>::with_capacity(buf_size);
+
+ for i in zsh {
+ match i {
+ Ok(h) => {
+ buf.push(h);
+ }
+ Err(e) => {
+ error!("{}", e);
+ continue;
+ }
+ }
+
+ if buf.len() == buf_size {
+ db.save_bulk(&buf)?;
+ progress.inc(buf.len() as u64);
+
+ buf = Vec::<History>::with_capacity(buf_size);
+ }
+ }
+
+ if buf.len() > 0 {
+ db.save_bulk(&buf)?;
+ progress.inc(buf.len() as u64);
+ }
+
+ progress.finish_with_message("Imported history!");
+
+ Ok(())
+ }
+
+ pub fn run(&self, db: &mut SqliteDatabase) -> Result<()> {
+ match self {
+ ImportCmd::Auto => {
+ let shell = env::var("SHELL").unwrap_or(String::from("NO_SHELL"));
+
+ match shell.as_str() {
+ "/bin/zsh" => self.import_zsh(db),
+
+ _ => {
+ println!("cannot import {} history", shell);
+ Ok(())
+ }
+ }
+ }
+
+ ImportCmd::Zsh => Ok(()),
+ }
+ }
+}
diff --git a/src/command/mod.rs b/src/command/mod.rs
new file mode 100644
index 00000000..c61d2280
--- /dev/null
+++ b/src/command/mod.rs
@@ -0,0 +1,2 @@
+pub mod history;
+pub mod import;