1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
use std::convert::TryFrom;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::rc::Rc;

use rusqlite::{Connection, NO_PARAMS};

mod autojump;
mod brave;
mod histfile;
mod mcfly;

pub struct ProviderInfo {
    pub name: String,
    pub size: usize,
}

type ProviderError = String;

pub trait Provider {
    fn info(&self) -> &ProviderInfo;
    fn search(&self, term: &str) -> Result<Vec<String>, ProviderError>;
}

pub fn available() -> (Vec<Rc<Provider>>, Vec<String>) {
    let mut out: Vec<Rc<Provider>> = Vec::new();
    let mut errors: Vec<String> = Vec::new();
    if let Ok(p) = autojump::build() {
        out.push(Rc::new(p))
    }
    match brave::build() {
        Ok(p) => out.push(Rc::new(p)),
        Err(e) => errors.push(e),
    }
    if let Ok(p) = histfile::build() {
        out.push(Rc::new(p));
    }
    if let Ok(p) = mcfly::build() {
        out.push(Rc::new(p));
    }
    (out, errors)
}

#[allow(dead_code)]
pub fn lines_in_file(path: &Path) -> Result<usize, ProviderError> {
    let file = File::open(&path).map_err(|_e| "file error".to_owned())?;
    let br = BufReader::new(file);
    Ok(br.lines().count())
}

pub struct Db {
    connection: Connection,
    table_name: String,
}

impl Db {
    pub fn open(path: &Path, table_name: &str) -> Result<Db, String> {
        let connection = Connection::open(path)
            .map_err(|e| format!("db open sqlite error {:?}, db {:?}", e, path))?;

        Ok(Db {
            connection,
            table_name: table_name.to_owned(),
        })
    }

    fn count(&self) -> Result<usize, String> {
        let result: isize = self
            .connection
            .query_row(
                &format!("select count(rowid) from {}", self.table_name),
                NO_PARAMS,
                |row| row.get(0),
            )
            .map_err(|e| format!("db count got sqlite query {:?}", e))?;
        usize::try_from(result).map_err(|_| "bad isize".to_owned())
    }
}

pub fn read_lines(path: &Path) -> Result<Vec<String>, ProviderError> {
    let mut data = Vec::new();
    let file = File::open(path).map_err(|_e| "file error".to_owned())?;
    let br = BufReader::new(file);
    for line in br.lines() {
        if let Ok(line) = line {
            data.push(line);
        }
    }
    Ok(data)
}

pub fn search(term: &str, data: &[String]) -> Result<Vec<String>, String> {
    let mut out = Vec::new();
    for d in data.iter() {
        if d.contains(term) {
            out.push(d.clone());
        }
    }
    Ok(out)
}