a good start for this project

This commit is contained in:
Abraham Toriz 2021-06-18 11:27:19 -05:00
commit 1655803076
No known key found for this signature in database
GPG Key ID: D5B4A746DB5DD42A
14 changed files with 986 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

450
Cargo.lock generated Normal file
View File

@ -0,0 +1,450 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "ahash"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
dependencies = [
"getrandom",
"once_cell",
"version_check",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"time",
"winapi",
]
[[package]]
name = "clap"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]]
name = "dirs"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "dtoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fallible-streaming-iterator"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]]
name = "getrandom"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash",
]
[[package]]
name = "hashlink"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
dependencies = [
"hashbrown",
]
[[package]]
name = "hermit-abi"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
dependencies = [
"libc",
]
[[package]]
name = "libc"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
[[package]]
name = "libsqlite3-sys"
version = "0.22.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290b64917f8b0cb885d9de0f9959fe1f775d7fa12f1da2db9001c1c8ab60f89d"
dependencies = [
"pkg-config",
"vcpkg",
]
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "memchr"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "pkg-config"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]]
name = "proc-macro2"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [
"getrandom",
"redox_syscall",
]
[[package]]
name = "rusqlite"
version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57adcf67c8faaf96f3248c2a7b419a0dbc52ebe36ba83dd57fe83827c1ea4eb3"
dependencies = [
"bitflags",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",
"libsqlite3-sys",
"memchr",
"smallvec",
]
[[package]]
name = "serde"
version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_yaml"
version = "0.8.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23"
dependencies = [
"dtoa",
"linked-hash-map",
"serde",
"yaml-rust",
]
[[package]]
name = "smallvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "syn"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "thiserror"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tiempo"
version = "0.1.0"
dependencies = [
"chrono",
"clap",
"dirs",
"rusqlite",
"serde",
"serde_yaml",
"thiserror",
"toml",
]
[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi",
"winapi",
]
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "vcpkg"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "025ce40a007e1907e58d5bc1a594def78e5573bb0b1160bc389634e8f12e4faa"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]

17
Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[package]
name = "tiempo"
version = "0.1.0"
authors = ["Abraham Toriz <categulario@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = "2"
chrono = "0.4"
rusqlite = "0.25.3"
thiserror = "*"
dirs = "*"
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.8"
toml = "0.5"

15
src/commands.rs Normal file
View File

@ -0,0 +1,15 @@
use std::convert::TryFrom;
use std::io::Write;
use clap::ArgMatches;
use crate::{error, database::Database};
pub mod r#in;
pub mod display;
pub trait Command<'a> {
type Args: TryFrom<&'a ArgMatches<'a>>;
fn handle<D: Database, W: Write>(args: Self::Args, db: &mut D, out: &mut W) -> error::Result<()>;
}

34
src/commands/display.rs Normal file
View File

@ -0,0 +1,34 @@
use std::convert::TryFrom;
use std::io::Write;
use clap::ArgMatches;
use crate::{error, database::Database};
use super::Command;
pub struct Args {
}
impl<'a> TryFrom<&'a ArgMatches<'a>> for Args {
type Error = error::Error;
fn try_from(matches: &'a ArgMatches) -> error::Result<Args> {
unimplemented!()
}
}
pub struct DisplayCommand {
}
impl<'a> Command<'a> for DisplayCommand {
type Args = Args;
fn handle<D, W>(args: Self::Args, db: &mut D, out: &mut W) -> error::Result<()>
where
D: Database,
W: Write,
{
unimplemented!()
}
}

95
src/commands/in.rs Normal file
View File

@ -0,0 +1,95 @@
use std::convert::TryFrom;
use std::io::Write;
use clap::ArgMatches;
use crate::{database::Database, error, types::Time, editor, commands::Command};
pub struct Args {
at: Option<Time>,
note: Option<String>,
}
impl<'a> TryFrom<&'a ArgMatches<'a>> for Args {
type Error = error::Error;
fn try_from(matches: &'a ArgMatches) -> Result<Self, Self::Error> {
Ok(Args {
at: matches.value_of("at").map(|s| s.parse()).transpose()?,
note: matches.value_of("note").map(|s| s.into()),
})
}
}
pub struct InCommand {}
impl<'a> Command<'a> for InCommand {
type Args = Args;
fn handle<D, W>(args: Args, db: &mut D, out: &mut W) -> error::Result<()>
where
D: Database,
W: Write,
{
let at = args.at.unwrap_or(Time::now());
let note = if let Some(note) = args.note {
note
} else {
editor::get_string()?
};
db.entry_insert(at, note)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::database::SqliteDatabase;
#[test]
fn test_handles_new_entry() {
let mut d = SqliteDatabase::from_memory().unwrap();
let args = Args {
at: None,
note: Some("hola".into()),
};
let out = Vec::new();
assert!(false, "there are no entries");
InCommand::handle(args, &mut d, &mut out).unwrap();
assert!(false, "there is one entry");
}
#[test]
fn test_handles_already_running_entry() {
let mut d = SqliteDatabase::from_memory().unwrap();
let args = Args {
at: None,
note: Some("hola".into()),
};
let mut out = Vec::new();
assert!(false, "there are no entries");
InCommand::handle(args, &mut d, &mut out).unwrap();
assert!(false, "there are still no entries");
}
#[test]
fn test_with_no_time_given_uses_now() {
assert!(false);
}
#[test]
fn test_sets_given_time() {
assert!(false);
}
}

130
src/config.rs Normal file
View File

@ -0,0 +1,130 @@
use std::env;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Read;
use dirs::home_dir;
use serde::{Serialize, Deserialize};
use crate::{error::{self, Error::*}, formatters::Formatter};
#[derive(Debug, Serialize, Deserialize)]
pub enum WeekDay {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
/// Absolute path to the sqlite database
pub database_file: PathBuf, // "/home/abraham/.timetrap.db"
/// The duration of time to use for rounding with the -r flag
pub round_in_seconds: u32, // 900
/// delimiter used when appending notes via t edit --append
pub append_notes_delimiter: String, //" "
/// an array of directories to search for user defined fomatter classes
pub formatter_search_paths: Vec<PathBuf>, //- "/home/abraham/.timetrap/formatters"
/// The format to use when display is invoked without a --format option
pub default_formatter: Formatter, //text
/// Which auto sheet module to use.
pub auto_sheet: String, //dotfiles
/// an array of directories to search for user defined auto_sheet classes
pub auto_sheet_search_paths: Vec<PathBuf>, // - "/home/abraham/.timetrap/auto_sheets"
/// The default command to invoke when you call t
pub default_command: Option<String>,
/// Automatically check out of running entries when you check in or out
pub auto_checkout: bool, // false
/// Prompt for a note if one isn't provided when checking in
pub require_note: bool, // true
/// The command to start editing notes. Defaults to false which means no
/// external editor is used. Please see the section below on Notes Editing
/// for tips on using non-terminal based editors. Example: note_editor:
/// "vim"
pub note_editor: String, // nvim
/// The day of the week to use as the start of the week for t week.
pub week_start: WeekDay, // Monday
}
impl Config {
/// Tries as hard as possible to read the current configuration. Retrieving
/// the path to it from the environment or common locations.
pub fn read() -> error::Result<Config> {
// first try from env variable TIMETRAP_CONFIG_FILE
if let Ok(value) = env::var("TIMETRAP_CONFIG_FILE") {
if value.ends_with(".toml") {
return Ok(Self::read_from_toml(value)?);
} else {
return Ok(Self::read_from_yaml(value)?);
}
}
// Next try from some known directories
if let Some(home) = home_dir() {
let mut old_location = home.clone();
old_location.push(".timetrap.yml");
if old_location.is_file() {
return Self::read_from_yaml(old_location);
}
let mut new_location = home.clone();
new_location.push(".config");
new_location.push("timetrap");
new_location.push("config.toml");
if new_location.is_file() {
Self::read_from_toml(new_location)
} else {
Self::create_and_return_config()
}
} else {
Err(error::Error::NoHomeDir)
}
}
fn read_from_yaml<P: AsRef<Path>>(path: P) -> error::Result<Config> {
let path: PathBuf = path.as_ref().into();
let mut contents = String::new();
let mut file = File::open(&path).map_err(|_| FileNotFound(path.clone()))?;
file.read_to_string(&mut contents).map_err(|_| CouldntRead(path.clone()))?;
serde_yaml::from_str(&contents).map_err(|error| YamlError {
path, error
})
}
fn read_from_toml<P: AsRef<Path>>(path: P) -> error::Result<Config> {
let path: PathBuf = path.as_ref().into();
let mut contents = String::new();
let mut file = File::open(&path).map_err(|_| FileNotFound(path.clone()))?;
file.read_to_string(&mut contents).map_err(|_| CouldntRead(path.clone()))?;
toml::from_str(&contents).map_err(|error| TomlError {
path, error
})
}
fn create_and_return_config() -> error::Result<Config> {
unimplemented!()
}
}

30
src/database.rs Normal file
View File

@ -0,0 +1,30 @@
use rusqlite::Connection;
use crate::{types::Time, error};
pub trait Database {
fn entry_insert(&mut self, at: Time, note: String) -> error::Result<()>;
}
pub struct SqliteDatabase {
}
impl SqliteDatabase {
pub fn from_memory() -> error::Result<impl Database> {
Ok(SqliteDatabase {
})
}
pub fn from_path(path: &str) -> error::Result<impl Database> {
let conn = Connection::open(path)?;
Ok(SqliteDatabase {
})
}
}
impl Database for SqliteDatabase {
fn entry_insert(&mut self, at: Time, note: String) -> error::Result<()> {
unimplemented!()
}
}

5
src/editor.rs Normal file
View File

@ -0,0 +1,5 @@
use crate::error;
pub fn get_string() -> error::Result<String> {
unimplemented!()
}

30
src/error.rs Normal file
View File

@ -0,0 +1,30 @@
use std::result;
use std::path::PathBuf;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("The command '{0}' is not implemented")]
UnimplementedCommand(String),
#[error("Sqlite error: {0}")]
Sqlite(#[from] rusqlite::Error),
#[error("Could not find home directory :(")]
NoHomeDir,
#[error("The file {0} was not found")]
FileNotFound(PathBuf),
#[error("Error reading the file: {0}")]
CouldntRead(PathBuf),
#[error("Couldn't parse toml file at: {path}\nwith error: {error}")]
TomlError{ path: PathBuf, error: toml::de::Error},
#[error("Couldn't parse yaml file at: {path}\nwith error: {error}")]
YamlError{ path: PathBuf, error: serde_yaml::Error},
}
pub type Result<T> = result::Result<T, Error>;

7
src/formatters.rs Normal file
View File

@ -0,0 +1,7 @@
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Formatter {
Text,
}

7
src/lib.rs Normal file
View File

@ -0,0 +1,7 @@
pub mod types;
pub mod commands;
pub mod database;
pub mod config;
pub mod editor;
pub mod formatters;
pub mod error;

146
src/main.rs Normal file
View File

@ -0,0 +1,146 @@
use std::convert::TryInto;
use std::process::exit;
use std::io;
use clap::{App, Arg, SubCommand, AppSettings, crate_version, ArgMatches};
use tiempo::error;
use tiempo::database::SqliteDatabase;
use tiempo::config::Config;
use tiempo::commands::{ Command, r#in::InCommand, display::DisplayCommand, };
fn error_trap(matches: ArgMatches) -> error::Result<()> {
let config = Config::read()?;
dbg!(config);
let mut conn = SqliteDatabase::from_path("db.sqlite3")?;
let mut out = io::stdout();
match matches.subcommand() {
("in", Some(matches)) => InCommand::handle(matches.try_into()?, &mut conn, &mut out),
("display", Some(matches)) => DisplayCommand::handle(matches.try_into()?, &mut conn, &mut out),
(cmd, _) => Err(error::Error::UnimplementedCommand(cmd.into())),
}
}
fn main() {
let matches = App::new("Tiempo")
.name("t")
.setting(AppSettings::SubcommandRequired)
.version(crate_version!())
.author("Abraham Toriz <categulario@gmail.com>")
.about("Tiempo helps you keep track of time spent in different activities")
.subcommand(SubCommand::with_name("archive")
.visible_alias("a")
.about("Move entries to a hidden sheet (by default named '_[SHEET]') so they're out of the way.")
.arg(Arg::with_name("start")
.long("start")
.short("s")
.takes_value(true)
.value_name("TIME")
.help("Include entries that start on this date or later"))
.arg(Arg::with_name("end")
.long("end")
.short("e")
.takes_value(true)
.value_name("TIME")
.help("Include entries that start on this date or earlier"))
.arg(Arg::with_name("grep")
.long("grep")
.short("g")
.takes_value(true)
.value_name("REGEXP")
.help("Include entries where the note matches this regexp."))
)
.subcommand(SubCommand::with_name("backend")
.visible_alias("b")
.about("Open an sqlite shell to the database.")
)
.subcommand(SubCommand::with_name("configure")
.visible_alias("c")
.about("Configure tiempo. Print path to config file.")
.arg(Arg::with_name("round_in_seconds")
.long("round-in-seconds")
.takes_value(true)
.value_name("SECONDS")
.help("The duration of time to use for rounding with the -r flag"))
.arg(Arg::with_name("database_file")
.long("database-file")
.takes_value(true)
.value_name("PATH")
.help("The file path of the sqlite database"))
.arg(Arg::with_name("append_notes_delimiter")
.long("append-notes-delimiter")
.takes_value(true)
.value_name("DELIMITER")
.help("delimiter used when appending notes via t edit --append"))
.arg(Arg::with_name("formatter_search_paths")
.long("formatter-search-paths")
.takes_value(true)
.value_name("PATHS")
.help("comma separated directories to search for user defined fomatter classes"))
.arg(Arg::with_name("default_formatter")
.long("default-formatter")
.takes_value(true)
.value_name("FORMATTER")
.help("The format to use when display is invoked without a `--format` option"))
.arg(Arg::with_name("require_note")
.long("require-note")
.help("Prompt for a note if one isn't provided when checking in"))
.arg(Arg::with_name("no_require_note")
.long("no-require-note")
.help("Prompt for a note if one isn't provided when checking in"))
.arg(Arg::with_name("note_editor")
.long("note-editor")
.takes_value(true)
.value_name("EDITOR")
.help("Command to launch notes editor or false if no editor use."))
.arg(Arg::with_name("week_start")
.long("week-start")
.takes_value(true)
.value_name("DAY")
.help("The day of the week to use as the start of the week for t week."))
)
.subcommand(SubCommand::with_name("display")
.visible_alias("d")
.about("Display the current timesheet or a specific. Pass `all' as SHEET
to display all unarchived sheets or `full' to display archived and
unarchived sheets.")
)
.subcommand(SubCommand::with_name("in")
.visible_alias("i")
.about("Start an activity in the current timesheet")
.arg(Arg::with_name("at")
.long("at")
.takes_value(true)
.value_name("TIME")
.help("Use this time instead of now"))
.arg(Arg::with_name("note")
.takes_value(true)
.value_name("NOTE")
.help("Text describing the activity to start"))
)
.subcommand(SubCommand::with_name("out")
.visible_alias("o")
.about("end the active entry in the current timesheet")
)
.subcommand(SubCommand::with_name("sheet")
.visible_alias("s")
.about("Change active timesheet or list existing timesheets")
)
.get_matches();
if let Err(e) = error_trap(matches) {
eprintln!("{}", e);
exit(1);
}
}

19
src/types.rs Normal file
View File

@ -0,0 +1,19 @@
use std::str::FromStr;
use crate::error;
pub struct Time;
impl Time {
pub fn now() -> Time {
Time
}
}
impl FromStr for Time {
type Err = error::Error;
fn from_str(s: &str) -> error::Result<Time> {
unimplemented!()
}
}