use clap::{ Command, Arg, SubCommand, command, value_parser, }; pub fn make_cli() -> Command<'static> { // Let's first declare some args that repeat here and there let start_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"); let end_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"); let ids_arg = Arg::with_name("ids") .short('v').long("ids") .help("Print database ids (for use with edit)"); let grep_arg = Arg::with_name("grep") .long("grep").short('g') .takes_value(true).value_name("REGEXP") .help("Only include entries whose note matches this regular expression"); let format_arg = Arg::with_name("format") .short('f').long("format") .takes_value(true).value_name("FORMAT") .help( "The output format. Valid built-in formats are chart, text, ical, \ csv, json and ids. Documentation on defining custom formats can be \ found at https://tiempo.categulario.xyz or the man page included \ with the installation." ); let sheet_arg = Arg::with_name("sheet") .takes_value(true).value_name("SHEET") .help( "The sheet to display. Pass 'all' to see entries from all sheets \ or 'full' to see hidden entries" ); let at_arg = Arg::with_name("at") .long("at") .takes_value(true).value_name("TIME") .help("Use this time instead of now"); let id_arg = Arg::with_name("id") .long("id") .takes_value(true).value_name("ID") .value_parser(value_parser!(u64)); let interactive_arg = Arg::with_name("interactive") .short('i') .long("interactive") .takes_value(false) .conflicts_with("id") .help("Choose an entry of the (unique) last N interactively"); // Now declar this app's cli let cli = command!() .subcommand_required(true) .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(start_arg.clone()) .arg(end_arg.clone()) .arg(grep_arg.clone()) .arg(sheet_arg.clone().help("Archive entries from this sheet instead of the current one")) .arg(Arg::with_name("fake") .short('f').long("fake") .help("Don't actually archive the entries, just display them") ) .arg(Arg::with_name("time") .short('t').long("time") .takes_value(true).value_name("HOURS") .help("Time in hours to archive. Archived time will be equal or less than this.") ) ) .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 in-place. If no arguments are given it just prints the path to the config file in use.") .arg(Arg::with_name("round_in_seconds") .long("round-in-seconds") .takes_value(true) .value_name("SECONDS") .value_parser(value_parser!(u64)) .help("The duration of time to use for rounding with the -r flag. Default: 900 (15 m)")) .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. Default: ' ' (space)")) .arg(Arg::with_name("formatter_search_paths") .long("formatter-search-paths") .takes_value(true) .multiple(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. Default 'text'")) .arg(Arg::with_name("require_note") .long("require-note") .help("Prompt for a note if one isn't provided when checking in (default)")) .arg(Arg::with_name("no_require_note") .long("no-require-note") .help("Entries can be created without notes")) .arg(Arg::with_name("auto_checkout") .long("auto-checkout") .help("Checkout of current running entry when starting a new one")) .arg(Arg::with_name("no_auto_checkout") .long("no-auto-checkout") .help("Starting a new entry fails if one is running (default)")) .arg(Arg::with_name("note_editor") .long("note-editor") .takes_value(true) .value_name("EDITOR") .help("Command to launch notes editor. Default: $EDITOR")) .arg(Arg::with_name("week_start") .long("week-start") .takes_value(true) .value_name("DAY") .possible_values(["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]) .help("The day of the week to use as the start of the week for t week. Default: monday")) .arg(Arg::with_name("interactive_entries") .long("interactive-entries") .takes_value(true) .value_name("N") .value_parser(value_parser!(u64)) .help("How many unique previous notes to show when selecting interactively")) ) .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.") .arg(ids_arg.clone()) .arg(start_arg.clone()) .arg(end_arg.clone()) .arg(format_arg.clone()) .arg(grep_arg.clone()) .arg(sheet_arg.clone()) ) .subcommand(SubCommand::with_name("today") .visible_alias("t") .about("Display entries that started today") .arg(ids_arg.clone()) .arg(end_arg.clone()) .arg(format_arg.clone()) .arg(grep_arg.clone()) .arg(sheet_arg.clone()) ) .subcommand(SubCommand::with_name("yesterday") .visible_alias("y") .about("Display entries that started yesterday") .arg(ids_arg.clone()) .arg(format_arg.clone()) .arg(grep_arg.clone()) .arg(sheet_arg.clone()) ) .subcommand(SubCommand::with_name("week") .visible_alias("w") .about("Display entries starting last monday or later") .arg(ids_arg.clone()) .arg(end_arg.clone()) .arg(format_arg.clone()) .arg(grep_arg.clone()) .arg(sheet_arg.clone()) ) .subcommand(SubCommand::with_name("month") .visible_alias("m") .about("Display entries starting this month") .arg(ids_arg.clone()) .arg(format_arg.clone()) .arg(grep_arg.clone()) .arg(sheet_arg.clone()) .arg(Arg::with_name("month") .long("month").short('m') .takes_value(true).value_name("TIME") .aliases(&["s", "start"]) .possible_values([ "this", "current", "last", "jan", "january", "feb", "february", "mar", "march", "apr", "april", "may", "jun", "june", "jul", "july", "aug", "august", "sep", "september", "oct", "october", "nov", "november", "dic", "december", ]) .hide_possible_values(true) .help( "Include entries of the specified month instead of the \ current month" ) ) ) .subcommand(SubCommand::with_name("in") .visible_alias("i") .about("Start an activity in the current timesheet") .arg(at_arg.clone()) .arg(Arg::with_name("note") .takes_value(true) .value_name("NOTE") .help("Text describing the activity to start")) ) .subcommand(SubCommand::with_name("resume") .visible_alias("r") .about("Restart the timer for an entry. Defaults to the last active entry") .arg(at_arg.clone()) .arg(id_arg.clone().help("Use entry with ID instead of the last entry")) .arg(interactive_arg.clone()) ) .subcommand(SubCommand::with_name("out") .visible_alias("o") .about("end the active entry in the current timesheet") .arg(at_arg.clone()) ) .subcommand(SubCommand::with_name("sheet") .visible_alias("s") .about("Change active timesheet or list existing timesheets") .arg(sheet_arg.clone().help("The sheet to switch to. Use - to quickly switch to the previous sheet")) ) .subcommand(SubCommand::with_name("list") .visible_alias("l") .about("List existing sheets") .arg(Arg::with_name("all") .short('a').long("all") .help("List archive sheets also")) .arg(Arg::with_name("flat") .short('f').long("flat") .help("show only the sheet names")) ) .subcommand(SubCommand::with_name("kill") .visible_alias("k") .about("Delete an entry or an entire sheet") .arg(id_arg.clone().help("Delete entry with this ID instead of sheet")) .arg(Arg::with_name("sheet") .takes_value(true).value_name("SHEET") .conflicts_with_all(&["id", "last"]) .required_unless_one(["id", "last"]) .help( "Delete an entire sheet by its name" )) .arg(Arg::with_name("last") .short('l').long("last") .takes_value(false) .help("Delete the last entry of the current sheet")) ) .subcommand(SubCommand::with_name("now") .visible_alias("n") .about("Show all running entries") ) .subcommand(SubCommand::with_name("edit") .visible_alias("e") .about("Edit an entry") .arg(id_arg.clone().help("Edit entry with this ID instead of the last one in the current sheet")) .arg(start_arg.clone().help("Set this as the start time")) .arg(end_arg.clone().help("Set this as the end time")) .arg( Arg::with_name("append") .long("append").short('z') .help("Append to the current note instead of replacing it. The delimiter between appended notes is configurable (see configure)") ) .arg( Arg::with_name("move") .short('m').long("move") .takes_value(true) .value_name("SHEET") .help("Move entry to another sheet") ) .arg( Arg::with_name("note") .takes_value(true) .value_name("NOTE") .help("The note text. It will replace the previous one unless --append is given") ) ); cli }