aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/date.rs2
-rw-r--r--src/history.rs77
-rw-r--r--src/main.rs29
-rw-r--r--src/parse/mod.rs2
4 files changed, 85 insertions, 25 deletions
diff --git a/src/date.rs b/src/date.rs
index dc6121c..8083da8 100644
--- a/src/date.rs
+++ b/src/date.rs
@@ -42,7 +42,7 @@ impl DateTime {
Ok(out)
}
- fn unix(&self) -> u64 {
+ pub fn unix(&self) -> u64 {
self.sys
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
diff --git a/src/history.rs b/src/history.rs
index e69de29..2e06133 100644
--- a/src/history.rs
+++ b/src/history.rs
@@ -0,0 +1,77 @@
+use sqlite::Connection;
+
+use crate::BString;
+use crate::date::DateTime;
+use std::env::current_dir;
+use std::path::PathBuf;
+
+fn db_file() -> PathBuf {
+ crate::basedir::data_dir().join("history.db")
+}
+
+#[derive(Clone)]
+pub struct HistoryEntry {
+ /// time of execution
+ pub time: DateTime,
+
+ /// absolute path where the command was executed
+ pub loc: BString,
+
+ /// the command
+ pub cmd: BString,
+}
+
+impl HistoryEntry {
+ pub fn new(cmd: BString) -> Self {
+ Self {
+ time: DateTime::now(),
+ loc: current_dir()
+ .unwrap()
+ .as_os_str()
+ .as_encoded_bytes()
+ .to_vec(),
+ cmd,
+ }
+ }
+}
+
+fn try_db() -> sqlite::Result<Connection> {
+ sqlite::open(db_file())
+}
+
+fn db() -> Connection {
+ try_db().unwrap()
+}
+
+pub fn setup() {
+ let db = db();
+
+ db.execute(
+ "
+ CREATE TABLE IF NOT EXISTS history (
+ ts INTEGER NOT NULL,
+ loc BLOB NOT NULL,
+ cmd BLOB NOT NULL
+ )
+ ",
+ )
+ .unwrap();
+
+ db.execute("CREATE INDEX IF NOT EXISTS idx_history_ts ON history(ts)")
+ .unwrap();
+}
+
+fn try_persist(entry: &HistoryEntry) -> sqlite::Result<()> {
+ let db = try_db()?;
+ let mut s = db.prepare("INSERT INTO history (ts, loc, cmd) VALUES (?, ?, ?)")?;
+ s.bind((1, entry.time.unix() as i64))?;
+ s.bind((2, entry.loc.as_slice()))?;
+ s.bind((3, entry.cmd.as_slice()))?;
+ s.next()?;
+ Ok(())
+}
+
+pub fn persist(entry: &HistoryEntry) {
+ // keep quiet in case db fails
+ let _ = try_persist(entry);
+}
diff --git a/src/main.rs b/src/main.rs
index 3687cd0..c2cf375 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -27,6 +27,7 @@ use linebuf::LineBuf;
use raw::*;
use crate::cursor::{Direction, move_cursor};
+use crate::history::HistoryEntry;
use crate::parse::{Ast, PreExpansion};
macro_rules! print {
@@ -59,28 +60,6 @@ type BString = Vec<u8>;
#[allow(non_camel_case_types)]
type bstr = [u8];
-#[derive(Clone)]
-struct HistoryEntry {
- /// time of execution
- pub time: date::DateTime,
-
- /// absolute path where the command was executed
- pub loc: BString,
-
- /// the command
- pub cmd: BString,
-}
-
-impl HistoryEntry {
- pub fn new(cmd: BString) -> Self {
- Self {
- time: date::DateTime::now(),
- loc: current_dir().unwrap().as_os_str().as_encoded_bytes().to_vec(),
- cmd,
- }
- }
-}
-
pub struct Session {
raw: ScopedRawMode,
line: LineBuf,
@@ -259,6 +238,8 @@ fn read1() -> u8 {
}
fn event_loop() {
+ history::setup();
+
let stdin = io::stdin();
let stdout = io::stdout();
@@ -335,7 +316,9 @@ fn event_loop() {
let line = se.line.dump();
if !line.is_empty() {
print!("\r\n");
- se.history.push(HistoryEntry::new(line.clone()));
+ let entry = HistoryEntry::new(line.clone());
+ history::persist(&entry);
+ se.history.push(entry);
se.history_visit = 0;
drop(se);
run::run(session.clone(), line);
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index ab693ab..8fa2e23 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -353,7 +353,7 @@ impl ExpString {
fn is_symbol(x: u8) -> bool {
match x {
- b'|' | b'{' | b'}' | b'$' | b'(' | b')' | b'\'' | b'"' => true,
+ b';' | b'|' | b'{' | b'}' | b'$' | b'(' | b')' | b'\'' | b'"' => true,
_ => false,
}
}