summaryrefslogtreecommitdiffstats
path: root/src/actions
diff options
context:
space:
mode:
Diffstat (limited to 'src/actions')
-rw-r--r--src/actions/agenda.rs305
-rw-r--r--src/actions/calendars.rs25
-rw-r--r--src/actions/copy.rs45
-rw-r--r--src/actions/cursor.rs156
-rw-r--r--src/actions/delete.rs68
-rw-r--r--src/actions/edit.rs50
-rw-r--r--src/actions/gen_completions.rs35
-rw-r--r--src/actions/get.rs49
-rw-r--r--src/actions/index/action.rs182
-rw-r--r--src/actions/index/bucketable.rs162
-rw-r--r--src/actions/index/indextime.rs38
-rw-r--r--src/actions/index/mod.rs18
-rw-r--r--src/actions/list.rs32
-rw-r--r--src/actions/mod.rs16
-rw-r--r--src/actions/modify.rs140
-rw-r--r--src/actions/new.rs358
-rw-r--r--src/actions/select.rs86
-rw-r--r--src/actions/seq.rs79
-rw-r--r--src/actions/show.rs34
-rw-r--r--src/actions/undo.rs131
-rw-r--r--src/actions/unroll.rs37
21 files changed, 0 insertions, 2046 deletions
diff --git a/src/actions/agenda.rs b/src/actions/agenda.rs
deleted file mode 100644
index 9659017..0000000
--- a/src/actions/agenda.rs
+++ /dev/null
@@ -1,305 +0,0 @@
-use chrono::{DateTime, Datelike, TimeZone, Local, Date};
-use yansi::{Style};
-use itertools::Itertools;
-use structopt::StructOpt;
-
-use crate::cursorfile;
-use crate::input;
-use crate::config::{Config,CalendarConfig};
-use crate::khevent::KhEvent;
-use crate::khline::KhLine;
-use crate::KhResult;
-
-#[derive(Debug, StructOpt)]
-pub struct AgendaArgs {
- /// Show agenda view
- #[structopt(name = "args")]
- pub args: Vec<String>,
-}
-
-pub fn show_events(config: &Config, args: &[&str]) -> KhResult<()> {
- let mut events = input::selection(args)?;
-
- let cursor = cursorfile::read_cursorfile().ok();
- show_events_cursor(config, &mut events, cursor.as_ref());
-
- Ok(())
-}
-
-pub fn show_events_cursor(
- config: &Config,
- events: &mut Iterator<Item = KhEvent>,
- cursor: Option<&KhLine>,
-) {
-
- let mut not_over_yet: Vec<(usize, KhEvent, Option<&CalendarConfig>)> = Vec::new();
- let mut cals_iter = events
- .enumerate()
- .map(|(i, event)| {
- let config = event.get_calendar_name().and_then(|name| config.get_config_for_calendar(&name));
- (i, event, config)
- })
- .peekable();
-
- let start_day = match cals_iter.peek() {
- Some((_, event, _)) => {
- event
- .get_start()
- .map(|dtstart| dtstart.into())
- .unwrap_or_else(|| Local.timestamp(0, 0))
- .date()
- }
- None => return,
- };
-
- let mut cur_day = start_day.pred();
- let mut last_printed_day = start_day.pred();
- while cals_iter.peek().is_some() || !not_over_yet.is_empty() {
- cur_day = cur_day.succ();
-
- maybe_print_date_line_header(&config, cur_day, start_day, &mut last_printed_day);
-
- not_over_yet.retain( |(index, event, cal_config)| {
- let is_cursor = cursor.map(|c| c.matches_khevent(&event)).unwrap_or(false);
- maybe_print_date_line(&config, cur_day, start_day, &mut last_printed_day);
- print_event_line(*cal_config, *index, &event, cur_day, is_cursor);
- event.continues_after(cur_day)
- });
-
- let relevant_events = cals_iter.peeking_take_while(|(_,event,_)| event.starts_on(cur_day));
- for (i, event, cal_config) in relevant_events {
- let is_cursor = cursor.map(|c| c.matches_khevent(&event)).unwrap_or(false);
- maybe_print_date_line(&config, cur_day, start_day, &mut last_printed_day);
- print_event_line(cal_config, i, &event, cur_day, is_cursor);
- if event.continues_after(cur_day) {
- not_over_yet.push((i, event, cal_config));
- }
- }
- }
-}
-
-fn maybe_print_week_separator(config: &Config, date: Date<Local>, start_date: Date<Local>, last_printed_date: Date<Local>) {
- if !config.agenda.print_week_separator {
- return;
- }
- if date != start_date && last_printed_date.iso_week() < date.iso_week() {
- khprintln!();
- }
-}
-
-fn maybe_print_date_line_header(config: &Config, date: Date<Local>, start_date: Date<Local>, last_printed_date: &mut Date<Local>) {
- if !config.agenda.print_empty_days {
- return;
- }
- maybe_print_date_line(config, date, start_date, last_printed_date);
-}
-
-fn maybe_print_date_line(config: &Config, date: Date<Local>, start_date: Date<Local>, last_printed_date: &mut Date<Local>) {
- if date <= *last_printed_date {
- return;
- }
- maybe_print_week_separator(config, date, start_date, *last_printed_date);
- print_date_line(date);
- *last_printed_date = date;
-}
-
-fn print_date_line(date: Date<Local>) {
- let style_heading = Style::default().bold();
- khprintln!("{}, {}", style_heading.paint(date.format("%Y-%m-%d")), date.format("%A"));
-}
-
-fn print_event_line(
- config: Option<&CalendarConfig>,
- index: usize,
- event: &KhEvent,
- date: Date<Local>,
- is_cursor: bool
-) {
- match event_line(config, &event, date, is_cursor) {
- Ok(line) => khprintln!("{:4} {}", index, line),
- Err(error) => warn!("{} in {}", error, event.get_uid())
- }
-}
-
-pub fn event_line(
- config: Option<&CalendarConfig>,
- event: &KhEvent,
- cur_day: Date<Local>,
- is_cursor: bool
-) -> Result<String, String> {
- if !event.relevant_on(cur_day) {
- return Err(format!("event is not relevant for {:?}", cur_day));
- }
-
- let mut summary = event.get_summary().ok_or("Invalid SUMMARY")?;
- if let Some(config) = config {
- let calendar_style = config.get_style_for_calendar();
- summary = calendar_style.paint(summary).to_string();
- }
-
- let cursor_icon = if is_cursor { ">" } else { "" };
-
- if event.is_allday() {
- Ok(format!("{:3} {}", cursor_icon, summary))
- } else {
- let mut time_sep = " ";
- let dtstart: DateTime<Local> = event.get_start().ok_or("Invalid DTSTART")?.into();
- let start_string = if dtstart.date() != cur_day {
- "".to_string()
- } else {
- time_sep = "-";
- format!("{}", dtstart.format("%H:%M"))
- };
-
- let dtend: DateTime<Local> = event.get_end().ok_or("Invalid DTEND")?.into();
- let end_string = if dtend.date() != cur_day {
- "".to_string()
- } else {
- time_sep = "-";
- format!("{}", dtend.format("%H:%M"))
- };
-
- Ok(format!("{:3}{:5}{}{:5} {}", cursor_icon, start_string, time_sep, end_string, summary))
- }
-}
-
-impl KhEvent {
- fn starts_on(&self, date: Date<Local>) -> bool {
- let dtstart: Date<Local> = self.get_start().unwrap().into();
- dtstart == date
- }
-
- fn relevant_on(&self, date: Date<Local>) -> bool {
- let dtstart: Option<Date<Local>> = self.get_start().map(|date| date.into());
- let last_relevant_date: Option<Date<Local>> = self.get_last_relevant_date().map(|date| date.into());
-
- dtstart.map(|dtstart| dtstart <= date).unwrap_or(false) &&
- last_relevant_date.map(|enddate| enddate >= date).unwrap_or(false)
- }
-
- fn continues_after(&self, date: Date<Local>) -> bool {
- let last_relevant_date: Option<Date<Local>> = self.get_last_relevant_date().map(|date| date.into());
- last_relevant_date
- .map(|enddate| enddate > date)
- .unwrap_or(false)
- }
-}
-
-#[cfg(test)]
-mod integration {
- use super::*;
- use crate::testdata;
- use crate::testutils::*;
- use crate::utils::stdioutils;
- use crate::config::Config;
- use crate::icalwrap::IcalVCalendar;
-
- use chrono::{Local, TimeZone};
-
- #[test]
- fn test_starts_on() {
- let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_MULTIDAY, None).unwrap();
- let event = cal.get_principal_khevent();
-
- let first_day = Local.ymd(2007, 6, 28);
- assert!(event.starts_on(first_day));
-
- let last_day = Local.ymd(2007, 7, 7);
- assert!(!event.starts_on(last_day));
- }
-
- #[test]
- fn test_continues_after_allday() {
- let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_MULTIDAY_ALLDAY, None).unwrap();
- let event = cal.get_principal_khevent();
- let first_day = Local.ymd(2007, 6, 28);
- assert!(event.continues_after(first_day));
- let last_day = Local.ymd(2007, 7, 8);
- assert!(!event.continues_after(last_day));
- }
-
- #[test]
- fn test_continues_after_simple() {
- let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_ONE_MEETING, None).unwrap();
- let event = cal.get_principal_khevent();
- let date = Local.ymd(1997, 3, 24);
- assert!(!event.continues_after(date));
- }
-
- #[test]
- fn test_event_line_negative() {
- let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_ONE_MEETING, None).unwrap();
- let event = cal.get_principal_khevent();
- let date = Local.ymd(1998, 1, 1);
- let event_line = event_line(None, &event, date, false);
- assert!(event_line.is_err())
- }
-
- #[test]
- fn test_event_line_simple() {
- testdata::setup();
- let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_ONE_MEETING, None).unwrap();
- let event = cal.get_principal_khevent();
- let date = Local.ymd(1997, 3, 24);
- let event_line = event_line(None, &event, date, false).unwrap();
- assert_eq!(" 13:30-22:00 Calendaring Interoperability Planning Meeting".to_string(), event_line)
- }
-
- #[test]
- fn test_event_line_cursor() {
- testdata::setup();
- let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_ONE_MEETING, None).unwrap();
- let event = cal.get_principal_khevent();
- let date = Local.ymd(1997, 3, 24);
- let event_line = event_line(None, &event, date, true).unwrap();
- assert_eq!("> 13:30-22:00 Calendaring Interoperability Planning Meeting".to_string(), event_line)
- }
-
- #[test]
- fn test_event_line_multiday() {
- testdata::setup();
- let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_MULTIDAY, None).unwrap();
- let event = cal.get_principal_khevent();
- let begin = Local.ymd(2007, 6, 28);
- let middle = Local.ymd(2007, 6, 30);
- let end = Local.ymd(2007, 7, 9);
- let event_line_begin = event_line(None, &event, begin, false).unwrap();
- let event_line_middle = event_line(None, &event, middle, false).unwrap();
- let event_line_end = event_line(None, &event, end, false).unwrap();
- assert_eq!(" 15:29- Festival International de Jazz de Montreal".to_string(), event_line_begin);
- assert_eq!(" Festival International de Jazz de Montreal".to_string(), event_line_middle);
- assert_eq!(" -09:29 Festival International de Jazz de Montreal".to_string(), event_line_end);
- }
-
- #[test]
- fn test_event_line_multiday_allday() {
- let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_MULTIDAY_ALLDAY, None).unwrap();
- let event = cal.get_principal_khevent();
- let date = Local.ymd(2007, 6, 28);
- let event_line = event_line(None, &event, date, false).unwrap();
- assert_eq!(" Festival International de Jazz de Montreal".to_string(), event_line)
- }
-
- #[test]
- fn test_stdout_simple() {
- testdata::setup();
- let _testdir = prepare_testdir("testdir_with_seq");
-
- show_events(&Config::read_config(), &[]).unwrap();
-
- let stdout = stdioutils::test_stdout_clear();
- let expected = indoc!("
- 2018-12-13, Thursday
- 0 23:30- shows up on two days
- 2018-12-14, Friday
- 0 shows up on two days
- 2018-12-15, Saturday
- 0 shows up on two days
- 2018-12-16, Sunday
- 0 shows up on two days
- 2018-12-17, Monday
- 0 -19:30 shows up on two days
- ");
- assert_eq!(expected, stdout);
- }
-}
diff --git a/src/actions/calendars.rs b/src/actions/calendars.rs
deleted file mode 100644
index 72a8a7d..0000000
--- a/src/actions/calendars.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-use calendars;
-
-pub fn action_list_calendars(_args: &[String]) -> Result<(), String> {
- for calendar in calendars::calendar_list() {
- khprintln!("{}", calendar);
- }
-
- Ok(())
-}
-
-#[cfg(test)]
-mod integration {
- use super::*;
-
- use testutils;
-
- #[test]
- fn test() {
- let _testdir = testutils::prepare_testdir("testdir_two_cals");
-
- action_list_calendars(&[]).unwrap();
-
- assert_eq!("second\nsecond/second_sub\nfirst\n", testutils::test_stdout_clear());
- }
-}
diff --git a/src/actions/copy.rs b/src/actions/copy.rs
deleted file mode 100644
index 811bcc5..0000000
--- a/src/actions/copy.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-use crate::input;
-use crate::utils::fileutil;
-use crate::utils::misc;
-
-use crate::KhResult;
-
-pub fn do_copy() -> KhResult<()> {
- let khline = input::default_input_khline()?;
-
- let uid = &misc::make_new_uid();
- let cal = khline.to_cal()?;
- let new_cal = cal.with_uid(uid)?.with_dtstamp_now();
-
- fileutil::write_cal(&new_cal)?;
-
- info!("Successfully wrote file: {}", new_cal.get_path().unwrap().display());
-
- Ok(())
-}
-
-
-#[cfg(test)]
-mod integration {
- use super::*;
-
- use assert_fs::prelude::*;
- use crate::khline::KhLine;
- use crate::testutils::prepare_testdir;
- use crate::utils::stdioutils;
- use predicates::prelude::*;
-
- #[test]
- fn copy_test() {
- let testdir = prepare_testdir("testdir");
- stdioutils::test_stdin_write("twodaysacrossbuckets.ics");
-
- do_copy().unwrap();
-
- let child = testdir.child(".khaleesi/cal/11111111-2222-3333-4444-444444444444@khaleesi.ics");
- child.assert(predicate::path::exists());
-
- let khline = "11111111-2222-3333-4444-444444444444@khaleesi.ics".parse::<KhLine>().unwrap();
- assert_eq!("11111111-2222-3333-4444-444444444444@khaleesi", khline.to_event().unwrap().get_uid());
- }
-}
diff --git a/src/actions/cursor.rs b/src/actions/cursor.rs
deleted file mode 100644
index b15ffed..0000000
--- a/src/actions/cursor.rs
+++ /dev/null
@@ -1,156 +0,0 @@
-use crate::cursorfile;
-use crate::utils::stdioutils;
-use crate::KhResult;
-use crate::seqfile;
-
-use structopt::StructOpt;
-
-#[derive(Debug, StructOpt)]
-pub struct CursorArgs {
- /// Move the cursor on the selection.
- #[structopt(name = "direction", raw(possible_values = "&CursorDirection::variants()"))]
- pub direction: Option<CursorDirection>,
-}
-
-arg_enum! {
-#[derive(Debug)]
- pub enum CursorDirection {
- Next,
- Prev,
- }
-}
-
-enum Direction {
- Up,
- Down,
-}
-
-pub fn do_cursor(args: &CursorArgs) -> KhResult<()> {
- if !stdioutils::is_stdin_tty() {
- write_stdin_to_cursorfile()?;
- } else {
- //println!("stdin is tty")
- if let Some(direction) = &args.direction {
- match direction {
- CursorDirection::Prev => return cursor_sequence_move(&Direction::Up),
- CursorDirection::Next => return cursor_sequence_move(&Direction::Down),
- }
- };
- }
-
- if !stdioutils::is_stdout_tty() || stdioutils::is_stdin_tty() {
- write_cursorfile_to_stdout();
- }
-
- Ok(())
-}
-
-fn write_stdin_to_cursorfile() -> KhResult<()> {
- let lines = stdioutils::read_lines_from_stdin()?;
-
- if lines.len() > 1 {
- Err("Too many lines on stdin")?;
- };
-
- cursorfile::write_cursorfile(&lines[0])?;
-
- Ok(())
-}
-
-fn write_cursorfile_to_stdout() {
- if let Ok(cursor) = cursorfile::read_cursorfile() {
- khprintln!("{}", cursor);
- }
-}
-
-fn cursor_sequence_move(direction: &Direction) -> KhResult<()> {
- let cursor_event = cursorfile::read_cursorfile()?;
- let mut seq = seqfile::read_seqfile_khlines()?;
- let next_elem = match direction {
- Direction::Up => {
- let mut seq_rev = seq.rev();
- seq_rev.find(|line| line == &cursor_event);
- seq_rev.next()
- },
- Direction::Down => {
- seq.find(|line| line == &cursor_event);
- seq.next()
- }
- };
-
- match next_elem {
- Some(next_elem) => cursorfile::write_cursorfile(&next_elem.to_string()),
- None => {
- warn!("Already at end of sequence");
- Ok(())
- }
- }
-}
-
-#[cfg(test)]
-mod integration {
- use super::*;
-
- use crate::testutils;
- use assert_fs::prelude::*;
- use predicates::prelude::*;
-
- #[test]
- fn test_with_stdin() {
- let testdir = testutils::prepare_testdir_empty();
- let expected_str = "hi there";
- stdioutils::test_stdin_write(expected_str);
-
- let args = CursorArgs{direction: None};
- do_cursor(&args).unwrap();
-
- testdir.child(".khaleesi/cursor").assert(expected_str);
- }
-
- #[test]
- fn test_cursor_sequence_move_next() {
- let testdir = testutils::prepare_testdir("testdir_with_seq_and_cursor");
- let args = CursorArgs{direction: Some(CursorDirection::Next)};
- do_cursor(&args).unwrap();
-
- let out = "1182988800 rfc_multi_day_allday.ics";
- let predicate = predicate::str::similar(out);
- testdir.child(".khaleesi/cursor").assert(predicate);
- }
-
- #[test]
- fn test_cursor_sequence_move_prev_at_end() {
- let testdir = testutils::prepare_testdir("testdir_with_seq_and_cursor");
- let args = CursorArgs{direction: Some(CursorDirection::Prev)};
- do_cursor(&args).unwrap();
-
- let out = "1544740200 twodaysacrossbuckets.ics\n";
- let predicate = predicate::str::similar(out);
- testdir.child(".khaleesi/cursor").assert(predicate);
- }
-
- #[test]
- fn test_with_stdin_linebreak() {
- let _testdir = testutils::prepare_testdir_empty();
- let expected_str = "hi\nthere";
- stdioutils::test_stdin_write(expected_str);
-
- let args = CursorArgs {direction: None};
- let result = do_cursor(&args);
-
- assert!(result.is_err());
- //testdir.child(".khaleesi/cursor").assert(expected_str);
- }
-
- #[test]
- fn test_no_stdin() {
- let testdir = testutils::prepare_testdir("testdir_with_cursor");
-
- let args = CursorArgs {direction: None};
- do_cursor(&args).unwrap();
- let out = stdioutils::test_stdout_clear();
-
- let predicate = predicate::str::similar(out);
- testdir.child(".khaleesi/cursor").assert(predicate);
- }
-}
diff --git a/src/actions/delete.rs b/src/actions/delete.rs
deleted file mode 100644
index ac2065a..0000000
--- a/src/actions/delete.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use crate::input;
-use crate::backup::backup;
-use crate::KhResult;
-use crate::khline::KhLine;
-use crate::utils::stdioutils;
-
-use std::path::PathBuf;
-use std::fs::remove_file;
-
-pub fn do_delete() -> KhResult<()> {
- info!("do_delete");
-
- let cursor_khline = input::default_input_khline()?;
-
- delete_file(cursor_khline)
-}
-
-fn delete_file(khline: KhLine) -> KhResult<()> {
-
- if ask_really_delete(&khline.path) {
- let backup_path = backup(&khline).unwrap();
- info!("Backup written to {}", backup_path.display());
-
- remove_file(khline.path.clone())?;
- info!("deleted {:#?}", khline.get_normalized_path());
- }
-
- Ok(())
-}
-
-fn ask_really_delete(path: &PathBuf) -> bool {
- if cfg!(test) { return true };
-
- println!("Really delete {:#?}? y/n:", path);
-
- match stdioutils::read_single_char_from_stdin().unwrap() {
- 'y' => true,
- _ => false
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- use crate::testutils::*;
- use assert_fs::prelude::*;
- use predicates::prelude::*;
-
- #[test]
- fn test_do_delete_cursor() {
- let testdir = prepare_testdir("testdir_with_cursor");
-
- do_delete().unwrap();
-
- let predicate = predicate::path::missing();
- testdir.child(".khaleesi/cal/twodaysacrossbuckets").assert(predicate);
-
- }
-
- #[test]
- #[should_panic]
- fn test_do_delete_no_cursor() {
- let _testdir = prepare_testdir("testdir");
-
- do_delete().unwrap();
- }
-}
diff --git a/src/actions/edit.rs b/src/actions/edit.rs
deleted file mode 100644
index 9d1abf8..0000000
--- a/src/actions/edit.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use tempfile::NamedTempFile;
-
-use crate::backup::backup;
-use crate::edit;
-use crate::input;
-use crate::khline::KhLine;
-use crate::utils::fileutil;
-use crate::KhResult;
-
-pub fn do_edit() -> KhResult<()> {
- let khline = input::default_input_khline()?;
- edit(&khline)
-}
-
-fn edit(khline: &KhLine) -> KhResult<()> {
- let tempfile = NamedTempFile::new()?;
- let calendar = khline.to_cal()?;
-
- fileutil::write_file(tempfile.path(), &calendar.to_string())?;
- edit::edit_loop(&tempfile.path())?;
-
- let backup_path = backup(&khline).unwrap();
- info!("Backup written to {}", backup_path.display());
-
- let edited_cal = KhLine::new(tempfile.path(), None).to_cal()?.with_dtstamp_now().with_last_modified_now();
- fileutil::write_file(&khline.path, &edited_cal.to_string())?;
- info!("Successfully edited file {}", khline.path.display());
-
- Ok(())
-}
-
-#[cfg(test)]
-mod integration {
- use super::*;
-
- use crate::testutils::prepare_testdir;
-
- #[test]
- fn edit_test() {
- let _testdir = prepare_testdir("testdir");
-
- let khline = "twodaysacrossbuckets.ics".parse::<KhLine>().unwrap();
-
- assert!(edit(&khline).is_ok());
- let event = khline.to_event().unwrap();
-
- assert_eq!("20130101T010203Z", event.get_dtstamp().unwrap());
- assert_eq!("20130101T010203Z", event.get_last_modified().unwrap());
- }
-}
diff --git a/src/actions/gen_completions.rs b/src/actions/gen_completions.rs
deleted file mode 100644
index e8e11ca..0000000
--- a/src/actions/gen_completions.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-use std::io;
-use structopt::clap::Shell;
-use structopt::StructOpt;
-
-use crate::cli::CommandLine;
-use crate::KhResult;
-
-#[derive(Debug, StructOpt)]
-pub struct GenCompletionsArgs {
- /// the shell
- #[structopt(name = "shell", raw(possible_values = "&ShellArg::variants()"))]
- pub shell: ShellArg,
-}
-
-arg_enum! {
-#[derive(Debug)]
- pub enum ShellArg{
- Bash,
- Zsh,
- Fish,
- Elvish
- }
-}
-
-pub fn gen_completions(args: &GenCompletionsArgs) -> KhResult<()> {
- let mut app = CommandLine::clap();
- let binary_name = "khaleesi";
- match args.shell {
- ShellArg::Bash => app.gen_completions_to(binary_name, Shell::Bash, &mut io::stdout()),
- ShellArg::Zsh => app.gen_completions_to(binary_name, Shell::Zsh, &mut io::stdout()),
- ShellArg::Fish => app.gen_completions_to(binary_name, Shell::Fish, &mut io::stdout()),
- ShellArg::Elvish => app.gen_completions_to(binary_name, Shell::Elvish, &mut io::stdout()),
- }
- Ok(())
-}
diff --git a/src/actions/get.rs b/src/actions/get.rs
deleted file mode 100644
index 513c0b3..0000000
--- a/src/actions/get.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-use crate::calendars;
-use crate::KhResult;
-use structopt::StructOpt;
-
-#[derive(Debug, StructOpt)]
-pub struct GetArgs {
- /// Show information about this
- #[structopt(name = "query", raw(possible_values = "&GetQueryArgs::variants()"))]
- pub query: GetQueryArgs,
-}
-
-arg_enum! {
-#[derive(Debug)]
- pub enum GetQueryArgs{
- Calendars,
- }
-}
-
-pub fn action_get(args: &GetArgs) -> KhResult<()> {
- match args.query {
- GetQueryArgs::Calendars => action_get_calendars(),
- }
-}
-
-pub fn action_get_calendars() -> KhResult<()> {
- for calendar in calendars::calendar_list() {
- khprintln!("{}", calendar);
- }
-
- Ok(())
-}
-
-#[cfg(test)]
-mod integration {
- use super::*;
-
- use crate::testutils;
- use crate::utils::stdioutils;
-
- #[test]
- fn test_get_calendars() {
- let _testdir = testutils::prepare_testdir("testdir_two_cals");
-
- let args = GetArgs { query: GetQueryArgs::Calendars };
- action_get(&args).unwrap();
-
- assert_eq!("first\nsecond\nsecond/second_sub\n", stdioutils::test_stdout_clear());
- }
-}
diff --git a/src/actions/index/action.rs b/src/actions/index/action.rs
deleted file mode 100644
index b32a248..0000000
--- a/src/actions/index/action.rs
+++ /dev/null
@@ -1,182 +0,0 @@
-use chrono::prelude::*;
-use crate::icalwrap::*;
-use std::collections::HashMap;
-use std::fs;
-use std::path::{Path,PathBuf};
-use std::time::SystemTime;
-use walkdir::DirEntry;
-
-use crate::defaults::*;
-use super::{IndexArgs, indextime};
-use crate::utils::fileutil;
-use crate::utils::lock;
-use crate::utils::misc;
-use crate::KhResult;
-
-pub fn action_index(args: &IndexArgs) -> KhResult<()> {
- let reindex = args.reindex;
- let indexpath = match &args.path {
- Some(path) => path.clone(),
- None => get_caldir(),
- };
-
- index_dir(&indexpath, reindex)
-}
-
-fn add_buckets_for_calendar(buckets: &mut HashMap<String, Vec<String>>, cal: &IcalVCalendar) {
- use super::bucketable::Bucketable;
- use super::bucketable::Merge;
-
- match cal.get_buckets() {
- Ok(cal_buckets) => buckets.merge(cal_buckets),
- Err(error) => {
- warn!("{}", error)
- }
- }
-}
-
-fn index_dir(dir: &Path, reindex: bool) -> KhResult<()> {
- use std::time::Instant;
-
- let _lock = lock::lock_file_exclusive(&get_indexlockfile())?;
-
- info!("Recursively indexing '.ics' files in directory: {}", dir.to_string_lossy());
- if !dir.exists() {
- Err(format!("Directory doesn't exist: {}", dir.to_string_lossy()))?;
- }
-
- let now = Instant::now();
- let start_time = Utc::now();
-
- let last_index_time = if reindex {
- debug!("Forced reindex, indexing all files");
- None
- } else {
- let last_index_time = indextime::get_index_time();
- match last_index_time {
- Some(time) => debug!("Previously indexed {}, indexing newer files only", time.with_timezone(&Local)),
- None => debug!("No previous index time, indexing all files"),
- }
- last_index_time
- };
-
- let modified_since = last_index_time.map(|time| time.timestamp()).unwrap_or(0);
- let ics_files = get_ics_files(dir, modified_since);
-
- let buckets = read_buckets(ics_files);
-
- let indexdir = get_indexdir();
- let clear_index_dir = last_index_time.is_none();
- prepare_index_dir(&indexdir, clear_index_dir)?;
-
- write_index(&indexdir, &buckets);
- info!("Index written in {}ms", misc::format_duration(&now.elapsed()));
-
- indextime::write_index_time(&start_time);
-
- Ok(())
-}
-
-pub fn get_ics_files(dir: &Path, modified_since: i64) -> impl Iterator<Item = PathBuf> {
- use walkdir::WalkDir;
-
- WalkDir::new(dir)
- .follow_links(true)
- .into_iter()
- .filter_entry(move |entry| accept_entry(entry, modified_since))
- .filter_map(|e| e.ok())
- .filter(|e| e.file_type().is_file())
- .filter(|e| e.path().extension().map_or(false, |extension| extension == "ics"))
- .map(|entry| entry.into_path())
-}
-
-fn accept_entry(dir_entry: &DirEntry, modified_since: i64) -> bool {
- if dir_entry.path().is_dir() {
- return true;
- }
- dir_entry.metadata()
- .map_err(|err| err.into()) // transform to io::Error
- .and_then(|metadata| metadata.modified())
- .map(|modified| modified.duration_since(SystemTime::UNIX_EPOCH).unwrap())
- .map(|modified| modified.as_secs() as i64)
- .map(|modified| modified > modified_since)
- .unwrap_or(false)
-}
-
-fn read_buckets(ics_files: impl Iterator<Item = PathBuf>) -> HashMap<String, Vec<String>> {
- let mut buckets: HashMap<String, Vec<String>> = HashMap::new();
-
- let mut total_files = 0;
- for file in ics_files {
- debug!("Indexing file: {:?}", file);
- match fileutil::read_file_to_string(&file) {
- Ok(content) => {
- total_files += 1;
- match IcalVCalendar::from_str(&content, Some(&file)) {
- Ok(cal) => add_buckets_for_calendar(&mut buckets, &cal),
- Err(error) => error!("{:?}: {}", file, error)
- }
- }
- Err(error) => error!("{}", error),
- }
- }
-
- info!("Loaded {} files into {} buckets", total_files, buckets.len());
- buckets
-}
-
-fn write_index(index_dir: &Path, buckets: &HashMap<String, Vec<String>>) {
- for (key, val) in buckets.iter() {
- let bucketfile = bucket_file(index_dir, key);
- trace!("Writing bucket: {}", key);
- let content = &[&val.join("\n"), "\n"].concat();
- if let Err(error) = fileutil::append_file(&bucketfile, content) {
- error!("{}", error);
- return;
- }
- }
-}
-
-fn bucket_file(index_dir: &Path, key: &str) -> PathBuf {
- let mut result = PathBuf::from(index_dir);
- result.push(key);
- result
-}
-
-fn prepare_index_dir(indexdir: &Path, clear_index_dir: bool) -> Result<(), std::io::Error> {
- if indexdir.exists() && clear_index_dir {
- info!("Clearing index directory: {}", indexdir.to_string_lossy());
- fs::remove_dir_all(&indexdir)?
- }
-
- if !indexdir.exists() {
- info!("Creating index directory: {}", indexdir.to_string_lossy());
- fs::create_dir(&indexdir)?;
- }
-
- Ok(())
-}
-
-#[cfg(test)]
-mod integration {
- use super::*;
-
- use crate::testutils::prepare_testdir;
- use assert_fs::prelude::*;
- use crate::cli::CommandLine;
- use crate::cli::Command::Index;
- use structopt::StructOpt;
-
- #[test]
- fn test_index() {
- let testdir = prepare_testdir("testdir");
-
- let args = CommandLine::from_iter(&["khaleesi", "index"]);
- if let Index(x) = args.cmd {
- action_index(&x).unwrap();
- }
-
- testdir.child(".khaleesi/index/2018-W50").assert("1544740200 twodaysacrossbuckets.ics\n");
- testdir.child(".khaleesi/index/2018-W51").assert("1544740200 twodaysacrossbuckets.ics\n");
- }
-}
diff --git a/src/actions/index/bucketable.rs b/src/actions/index/bucketable.rs
deleted file mode 100644
index 8644c1e..0000000
--- a/src/actions/index/bucketable.rs
+++ /dev/null
@@ -1,162 +0,0 @@
-use chrono::{Local, Date, Datelike, Duration};
-use std::collections::HashMap;
-use std::{hash, cmp};
-
-use crate::icalwrap::IcalVCalendar