use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::Write;
use std::path::Path;
use linefeed::Reader;
use linefeed::terminal::DefaultTerminal;
use sqlite;
use tools;
use shell;
pub fn init(rl: &mut Reader<DefaultTerminal>) {
let mut hist_size: usize = 999;
if let Ok(x) = env::var("HISTORY_SIZE") {
if let Ok(y) = x.parse::<usize>() {
hist_size = y;
}
}
rl.set_history_size(hist_size);
let history_table = get_history_table();
let hfile = get_history_file();
let path = Path::new(hfile.as_str());
if !path.exists() {
let _parent;
match path.parent() {
Some(x) => _parent = x,
None => {
println!("cicada: history init - no parent found");
return;
}
}
let parent;
match _parent.to_str() {
Some(x) => parent = x,
None => {
println!("cicada: parent to_str is None");
return;
}
}
match fs::create_dir_all(parent) {
Ok(_) => {}
Err(e) => {
println!("dirs create failed: {:?}", e);
return;
}
}
match fs::File::create(hfile.as_str()) {
Ok(_) => {}
Err(e) => {
println!("file create failed: {:?}", e);
}
}
}
let mut histories: HashMap<String, bool> = HashMap::new();
match sqlite::open(hfile.clone()) {
Ok(conn) => {
let sql_create = format!(
"
CREATE TABLE IF NOT EXISTS {}
(inp TEXT,
rtn INTEGER,
tsb REAL,
tse REAL,
sessionid TEXT,
out TEXT,
info TEXT
);
",
history_table
);
match conn.execute(sql_create) {
Ok(_) => {}
Err(e) => println_stderr!("cicada: sqlite exec error - {:?}", e),
}
if let Ok(x) = env::var("HISTORY_DELETE_DUPS") {
if x == "1" {
delete_duplicated_histories();
}
}
let sql_select =
format!(
"SELECT inp FROM {} ORDER BY tsb;",
history_table,
);
match conn.iterate(sql_select, |pairs| {
for &(_, value) in pairs.iter() {
let inp;
match value {
Some(x) => inp = x,
None => {
println!("cicada: sqlite pairs None");
continue;
}
}
let _k = inp.to_string();
if histories.contains_key(&_k) {
continue;
}
histories.insert(_k, true);
rl.add_history(inp.trim().to_string());
}
true
}) {
Ok(_) => {}
Err(e) => println_stderr!("cicada: sqlite select error - {:?}", e),
}
}
Err(e) => {
println_stderr!("cicada: sqlite conn error - {:?}", e);
}
}
}
pub fn get_history_file() -> String {
if let Ok(hfile) = env::var("HISTORY_FILE") {
return hfile;
} else if let Ok(d) = env::var("XDG_DATA_HOME") {
return format!("{}/{}", d, "cicada/history.sqlite");
} else {
let home = tools::get_user_home();
return format!("{}/{}", home, ".local/share/cicada/history.sqlite");
}
}
pub fn get_history_table() -> String {
if let Ok(hfile) = env::var("HISTORY_TABLE") {
return hfile;
} else {
return String::from("cicada_history");
}
}
fn delete_duplicated_histories() {
let hfile = get_history_file();
let history_table = get_history_table();
match sqlite::open(hfile.clone()) {
Ok(conn) => {
let sql = format!(
"DELETE FROM {} WHERE rowid NOT IN (
SELECT MAX(rowid) FROM {} GROUP BY inp)",
history_table,
history_table
);
match conn.execute(sql) {
Ok(_) => {}
Err(e) => println_stderr!("cicada: sqlite exec error - {:?}", e),
}
}
Err(e) => println_stderr!("cicada: sqlite open file error - {:?}", e),
}
}
pub fn add(
sh: &mut shell::Shell,
rl: &mut Reader<DefaultTerminal>,
line: &str,
status: i32,
tsb: f64,
tse: f64,
) {
if line == sh.previous_cmd {
return;
}
rl.add_history(line.to_string());
sh.previous_cmd = line.to_string();
let hfile = get_history_file();
let history_table = get_history_table();
let conn;
match sqlite::open(hfile) {
Ok(x) => conn = x,
Err(e) => {
println!("cicada: sqlite open db error: {:?}", e);
return;
}
}
let sql = format!(
"INSERT INTO \
{} (inp, rtn, tsb, tse, sessionid) \
VALUES('{}', {}, {}, {}, '{}');",
history_table,
str::replace(line.trim(), "'", "''"),
status,
tsb,
tse,
"cicada"
);
match conn.execute(sql) {
Ok(_) => {}
Err(e) => println!("failed to save history: {:?}", e),
}
}