diff --git a/ChangeLog b/ChangeLog index a9eeae2..81a6e0d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,7 +5,9 @@ v4.4.0 placeholder chars instead of blowing up * Fix `--lineart` option failing with unicode errors * `quick` command now prompts for which calendar to use when ambiguous - * Fix --nodeclined option failing on events with aliased email + * Fix `--nodeclined` option failing on events with aliased email + * `add` command now supports `--end` as an alternative to `--duration` + (michaelPotter) v4.3.0 * Adds 'conference' to details display (michaelhoffman) diff --git a/gcalcli/argparsers.py b/gcalcli/argparsers.py index b2392e0..47f5c9c 100644 --- a/gcalcli/argparsers.py +++ b/gcalcli/argparsers.py @@ -377,19 +377,25 @@ def get_argument_parser(): help='Event participant (may be provided multiple times)') add.add_argument('--where', default=None, type=str, help='Event location') add.add_argument('--when', default=None, type=str, help='Event time') + # Allow either --duration or --end, but not both. + end_group = add.add_mutually_exclusive_group() + end_group.add_argument( + '--duration', default=None, type=int, + help='Event duration in minutes (or days if --allday is given). ' + 'Alternative to --end.') + end_group.add_argument( + '--end', default=None, type=str, + help='Event ending time. Alternative to --duration.') add.add_argument( - '--duration', default=None, type=int, - help='Event duration in minutes or days if --allday is given.') + '--description', default=None, type=str, help='Event description') add.add_argument( - '--description', default=None, type=str, help='Event description') + '--allday', action='store_true', dest='allday', default=False, + help='If --allday is given, the event will be an all-day event ' + '(possibly multi-day if --duration is greater than 1). The time part ' + 'of the --when will be ignored.') add.add_argument( - '--allday', action='store_true', dest='allday', default=False, - help='If --allday is given, the event will be an all-day event ' - '(possibly multi-day if --duration is greater than 1). The ' - 'time part of the --when will be ignored.') - add.add_argument( - '--noprompt', action='store_false', dest='prompt', default=True, - help='Don\'t prompt for missing data when adding events') + '--noprompt', action='store_false', dest='prompt', default=True, + help='Don\'t prompt for missing data when adding events') _import = sub.add_parser( 'import', parents=[remind_parser], @@ -403,10 +409,10 @@ def get_argument_parser(): nargs='?', default=None) _import.add_argument( - '--verbose', '-v', action='count', help='Be verbose on imports') + '--verbose', '-v', action='count', help='Be verbose on imports') _import.add_argument( - '--dump', '-d', action='store_true', - help='Print events and don\'t import') + '--dump', '-d', action='store_true', + help='Print events and don\'t import') default_cmd = 'notify-send -u critical -i appointment-soon -a gcalcli %s' remind = sub.add_parser( diff --git a/gcalcli/cli.py b/gcalcli/cli.py index f36dc4f..5e6297a 100755 --- a/gcalcli/cli.py +++ b/gcalcli/cli.py @@ -62,7 +62,7 @@ def run_add_prompt(parsed_args, printer): printer, 'Location: ', STR_ALLOW_EMPTY) if parsed_args.when is None: parsed_args.when = get_input(printer, 'When: ', PARSABLE_DATE) - if parsed_args.duration is None: + if parsed_args.duration is None and parsed_args.end is None: if parsed_args.allday: prompt = 'Duration (days): ' else: @@ -190,9 +190,10 @@ def main(): # calculate "when" time: try: estart, eend = utils.get_times_from_duration( - parsed_args.when, parsed_args.duration, - parsed_args.allday - ) + parsed_args.when, + duration=parsed_args.duration, + end=parsed_args.end, + allday=parsed_args.allday) except ValueError as exc: printer.err_msg(str(exc)) # Since we actually need a valid start and end time in order to diff --git a/gcalcli/gcal.py b/gcalcli/gcal.py index b7ebb50..f0a7794 100644 --- a/gcalcli/gcal.py +++ b/gcalcli/gcal.py @@ -944,8 +944,7 @@ def _edit_event(self, event): all_day = self.options.get('allday') try: new_start, new_end = utils.get_times_from_duration( - val, length, all_day - ) + val, duration=length, all_day=all_day) except ValueError as exc: self.printer.err_msg(str(exc)) sys.exit(1) @@ -960,9 +959,9 @@ def _edit_event(self, event): all_day = self.options.get('allday') try: new_start, new_end = utils.get_times_from_duration( - event['start']['dateTime'], val, - all_day - ) + event['start']['dateTime'], + duration=val, + all_day=all_day) event = self._SetEventStartEnd(new_start, new_end, event) except ValueError as exc: self.printer.err_msg(str(exc)) diff --git a/gcalcli/utils.py b/gcalcli/utils.py index 75d84c4..2a19561 100644 --- a/gcalcli/utils.py +++ b/gcalcli/utils.py @@ -3,6 +3,7 @@ import locale import re import time +from typing import Tuple from dateutil.parser import parse as dateutil_parse from dateutil.tz import tzlocal @@ -53,34 +54,32 @@ def set_locale(new_locale): '!\n Check supported locales of your system.\n') -def get_times_from_duration(when, duration=0, allday=False): - +def get_times_from_duration( + when, duration=0, end=None, allday=False +) -> Tuple[str, str]: try: start = get_time_from_str(when) except Exception: raise ValueError('Date and time is invalid: %s\n' % (when)) - if allday: + if end is not None: + stop = get_time_from_str(end) + elif allday: try: stop = start + timedelta(days=float(duration)) except Exception: raise ValueError( - 'Duration time (days) is invalid: %s\n' % (duration)) - - start = start.date().isoformat() - stop = stop.date().isoformat() - + 'Duration time (days) is invalid: %s\n' % (duration) + ) + start = start.date() + stop = stop.date() else: try: stop = start + get_timedelta_from_str(duration) except Exception: - raise ValueError( - 'Duration time is invalid: %s\n' % (duration)) - - start = start.isoformat() - stop = stop.isoformat() + raise ValueError('Duration time is invalid: %s\n' % (duration)) - return start, stop + return start.isoformat(), stop.isoformat() def get_time_from_str(when):