From 099afe66ecfb569a8a04b66425ded29665e6a37c Mon Sep 17 00:00:00 2001 From: Ellie Huxtable Date: Sat, 13 Feb 2021 19:37:00 +0000 Subject: Implement history import --- src/local/import.rs | 101 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 15 deletions(-) (limited to 'src/local/import.rs') diff --git a/src/local/import.rs b/src/local/import.rs index 8db8f0e3..ce141c52 100644 --- a/src/local/import.rs +++ b/src/local/import.rs @@ -4,38 +4,109 @@ use std::fs::File; use std::io::{BufRead, BufReader}; -use eyre::Result; +use chrono::{TimeZone, Utc}; +use eyre::{eyre, Result}; -use crate::models::history::History; +use crate::local::history::History; -pub struct ImportBash { +#[derive(Debug)] +pub struct ImportZsh { file: BufReader, + + pub loc: u64, } -impl ImportBash { - pub fn new(path: &str) -> Result { +// this could probably be sped up +fn count_lines(path: &str) -> Result { + let file = File::open(path)?; + let buf = BufReader::new(file); + + Ok(buf.lines().count()) +} + +impl ImportZsh { + pub fn new(path: &str) -> Result { + let loc = count_lines(path)?; + let file = File::open(path)?; let buf = BufReader::new(file); - Ok(ImportBash { file: buf }) + Ok(ImportZsh { + file: buf, + loc: loc as u64, + }) } } -impl Iterator for ImportBash { - type Item = History; +fn trim_newline(s: &str) -> String { + let mut s = String::from(s); + + if s.ends_with('\n') { + s.pop(); + if s.ends_with('\r') { + s.pop(); + } + } + + s +} - fn next(&mut self) -> Option { +fn parse_extended(line: String) -> History { + let line = line.replacen(": ", "", 2); + let mut split = line.splitn(2, ":"); + + let time = split.next().unwrap_or("-1"); + let time = time + .parse::() + .unwrap_or(chrono::Utc::now().timestamp_nanos()); + + let duration = split.next().unwrap(); // might be 0;the command + let mut split = duration.split(";"); + + let duration = split.next().unwrap_or("-1"); // should just be the 0 + let duration = duration.parse::().unwrap_or(-1); + + let command = split.next().unwrap(); + + // use nanos, because why the hell not? we won't display them. + History::new( + Utc.timestamp(time, 0).timestamp_nanos(), + trim_newline(command), + String::from("unknown"), + -1, + duration * 1_000_000_000, + ) +} + +impl Iterator for ImportZsh { + type Item = Result; + + fn next(&mut self) -> Option { + // ZSH extended history records the timestamp + command duration + // These lines begin with : + // So, if the line begins with :, parse it. Otherwise it's just + // the command let mut line = String::new(); match self.file.read_line(&mut line) { Ok(0) => None, - Err(_) => None, + Err(e) => Some(Err(eyre!("failed to parse line: {}", e))), + + Ok(_) => { + let extended = line.starts_with(":"); - Ok(_) => Some(History { - cwd: "none".to_string(), - command: line, - timestamp: -1, - }), + if extended { + Some(Ok(parse_extended(line))) + } else { + Some(Ok(History::new( + chrono::Utc::now().timestamp_nanos(), // what else? :/ + trim_newline(line.as_str()), + String::from("unknown"), + -1, + -1, + ))) + } + } } } } -- cgit v1.3.1