diff options
author | Tobias Brox <tobias@redpill-linpro.com> | 2022-01-05 15:21:39 +0100 |
---|---|---|
committer | Tobias Brox <tobias@redpill-linpro.com> | 2022-01-05 15:21:39 +0100 |
commit | 0d34fa108f5669eabbe7df41c1431d203969183c (patch) | |
tree | 0424ba971471e28598a56204a46ff2f4018f0cea | |
parent | 966bc5e941ae5ed913dd2969820c86ff7e000aa1 (diff) | |
download | calendar-cli-0d34fa108f5669eabbe7df41c1431d203969183c.zip |
working on the new cli. Split out the thoughts from the NEXT_LEVEL.md file to an independent NEW_CLI.md
-rw-r--r-- | NEW_CLI.md | 118 | ||||
-rw-r--r-- | NEXT_LEVEL.md | 126 | ||||
-rwxr-xr-x | cal.py | 47 | ||||
-rwxr-xr-x | calendar-cli.py | 4 | ||||
-rw-r--r-- | tests/_setup_alias | 1 | ||||
-rwxr-xr-x | tests/tests.sh | 15 |
6 files changed, 185 insertions, 126 deletions
diff --git a/NEW_CLI.md b/NEW_CLI.md new file mode 100644 index 0000000..794d76d --- /dev/null +++ b/NEW_CLI.md @@ -0,0 +1,118 @@ +## General thoughts + +* calendar-cli should be a simple command line wrapper over existing python libraries. It should not contain a lot of logic besides parsing command line options and arguments. Logic that may be useful for python programmers should be pushed to other libraries, like the caldav-library, or be split into a new library. +* Old calendar-cli stays for quite some time, for backward compatibility +* We'll split out a new command for the new interface, probably it will be `kal`. I considered a lot of different name options: + * cal ... but `cal(1)` - is a well-established command, so it's out of the question (unless we overload the command by making a wrapper calling `cal` if no subcommand is given ... that could be an idea). + * `calcli`, `cal-cli` and different variants of it. The dash already hurt me with calendar-cli, don't want to repeat that. And "cli" is a bit redundant, when typing a command on the command line it's reasonable to assume it's a cli. + * `cal-add`, or even `cal-add-todo` ... but modern cli frameworks are more often than not built over different variants of `command subcommand subsubcommand`. + * `kal` ... looks a bit like a silly misspelling or an attempt to localize it into some non-english language (which then will look even more silly when combined with english subcommands and english options). At the other hand, I do see that it's not entirely uncommon to use `klass` when putting a class into a variable in python, `kal` is short to type, easy to remember, and there aren't too many other projects utilizing the `kal`-name as far as I can see. +* We'll use click, which is supposed to support subcommands in an elegant way. +* I'm fairly happy with the todo interface for listing/editing/completing. First options to filter/sort/limit the todo item(s), then a subcommand for what to do on those items. +* Should consider that we at some point may want to support tools that doesn't support caldav. Should als oconsider that we may want to support tools that doesn't support icalendar. For instance, issue tracking through gitlab or github. +* Perhaps a new calendar-tui for increased interactivity? +* Some or all of the commands should be possible to iterate over several calendars. This is almost impossible with `calendar-cli` due to the way the configuration is made (perhaps we should require that connection parameters are given in a config file?) + +## Details + +Add an event, task or journal entry: + +``` +kal --config-section=private_calendar add --set-location="Aker Brygge marina" event "new years party" 2032-12-31T20:00+5h +kal add todo "Buy food for the new years party" --set-due=2032-12-30T20:00 --set-duration=1h + +kal add journal "Captain's log" 2020-12-04 'Started from Świnoujście a bit after 03AM. Due to miscommunication, bad planning and language problems my crew member Bartek managed to throw the whole mooring rope to the sea (clearly the captains fault - I didnt explain the task "release one end of the rope, let it go into the sea and then pull it in" well enough, and he did ask multiple times "are you really sure about that?" before throwing both ends of the rope to the sea). Tail wind, between 8-16 knots relative windspeed, changed a bit between broad reach and butterfly. While going butterfly, due to a rather big wave we had an accidental jib, bad enough that the preventer rope broke off the cleat it was attached to (but luckily no damanges to the rig). There seems to be a minor salt water leakage by the rudder. Passed Falsterbo around 21, moored up in the guest harbour in Skanör around 22. Very quiet as it was way outside the season. Didnt find any obvious choice on the payment automat for harbor fee - eventually I payed SEK 100 for "tvättstuga". I got no access to the laundry room, so I decided that 100 SEK was an OK price for staying overnight with electricity off-season in Skanör.' +``` + +While the specification for journal, todo and event are fairly similar, the non-optional parameters will be different due to slightly different typical use-case scenarios: + +* All three should have a summary as the mandatory first parameter (deviation from calendar-cli which takes the timestamp as first parameter when creating an event) +* For making todos, that should be the only mandatory parameter (as with "calendar-cli todo add"). Not all tasks have a clear due-date. In accordance with my task management ideas above, all tasks should eventually have a due date set, but the idea is also to be able to quickly throw things on the list, and then consider an appropriate priority and due date later. +* dtstart is (If I read the rfc correctly) optional for all three classes, but it doesn't make much sense to have an event without a start time - and a journal entry should have a date. For events, the same timestamp format is used as in the existing calendar-cli - duration can be piggybacked in the timestamp. Change of parameter order, with "calendar-cli calendar add" the dtstart should come before the summary. This to make "summary first" consistent for all three calendar object resource classes. +* For journal entries (as they are intended), it doesn't make much sense to add an entry without a description, so it's the mandatory second parameter. + +The todo-item added above has both due timestamp and duration set, which is against the RFC. It will be converted to dtstart and due before it's pushed to the calendar. + +To get things out from the calendar, one can use the kal agenda command. + +``` +kal agenda --config-section=private --config-section=work --agenda-days=30 --event-template="{dtstart} {summary} UID={uid}" --todo-template="{due} {summary} UID={uid}" +``` + +kal agenda should first print out all events starting or ending within the next 30 days, then all tasks with dtstart or due within the next 30 days. (in my revised "task management" above, dtstart is defined as due minus estimated work time). The tasks should be "smart sorted", according to the algorithm given in the "Task management" section above ("based on the ratio between duration and available time until due date"). It should accept several --config-section, take out all it can find from those config sections and sort the things afterwards. Exceptions due to unreachable caldav servers or calendars not supporting tasks etc should be caught and presented nicely. + +The kal agenda is to be considered a convenience-command, it is slightly redundant. The output of the command should be considered to be for direct human consumption, no further processing of the output should be done. The kal select command is the ultimate tool for a lot of things: + +``` +kal select --timespan=2021-12-01+2w list +kal select --todo --nocategories --list +kal select --todo --nocategories -1 edit --add-category=keyboard +kal select --todo --due-before=2021-12-01 --categories=keyboard --smart-sort list +kal select --todo --due-before=2021-12-01 --categories=keyboard --smart-sort -1 complete +kal select --uid=e71a6180-45a2-11ec-9605-fa163e7cfdd5 delete +kal select --due-before=2021-12-24T15:00 --categories=housework calculate-panic-time --work-factor=0.125 +kal select --journal --dtstart-after=2021-10-01 --dtstart-before=2021-11-01 sum_hours +``` + +kal select should select objects based on some criterias and then perform some action (`list`, `edit`, `postpone`, `complete`, `delete`, `calculate-panic-time`, 'sum_hours' and some more - see further below) on the objects. + +The technical differences between tasks, events and journal entries are small - kal select should basically work on all three of them unless `--todo`, `--event` or `--journal` is epxlicitly given. If the action given does not match one or more of the objects selected (say, "completing" a journal does not make sense), the script should raise an exception before doing any modifications of the calendar. `--offset` and `--limit` may be used to specify a handful of objects. "-1" is shortform for "--limit 1", or typically "do this action with the top item at the list" + +`--smart-sort` will give the above mentioned sort algorithm for tasks, and regular sorting by dtstart for events and journals. + +The `calculate-panic-time` command will take out all planned events and todo items, count the duration of those and print out a timestamp for when you need to panic. If it shows a timestamp in the past one should either PANIC!!! or procrastinate some tasks and cancel some events. The command takes the `--work-factor` parameter which specifies how much of the time you will be able to concentrate on the selected tasks. For instance, an "ordinary" parent having kids to take care of, a daytime job, plus the need for sleeping every night may perhaps in average be able to spend 3 hours a day - or 12.5% of the full day - on house work. + +This should cover most regular needs for putting events on a calendar and managing tasks and todo-lists. It does not cover "pinning" tasks to a calendar nor tracking time spent on tasks. There may also be a need for a bit more interactivity. Sending invites and replying to invites is also not covered. + +Logical "and" should be assumed between filter selectors. I feel uncomfortable with implementing support for paranthesis and logical operators, but there could probably be a --union parameter working as a "logical or", and some syntax should be made for the individual filters (but `--limit`, `--offset` and `--sort` should be processed after the union). Perhaps `--categories=housework+gardenwork` should fetch everything with either "housework" or "gardenwork" as category, while `--categories=housework,kitchen` should fetch all housework to be done in the kitchen. Or maybe `--categories=housework&gardenwork` and `--categories=housework|gardenwork` is less ambiguous. It probably needs to be thought more through. + +sum_hours will sum the duration of all objects. Journal entries cannot have duration, so for journal entries it will sum the duration of all parents to all the journals selected. This is supposed to be equal to the total time spent working. + +## Pinning tasks to calendar + +The `pin` subcommand will "pin" one or more todo-items to some specific time on the calendar. Duration will be copied. The tasks will be serialized. If there are conflicting events in the same calendar, the tasks will be put after the conflicting events. No checks will be done to ensure that the tasks ends up within ordinary working hours, outside the night hours or before the due date. Or perhaps some sanity checks should be done ... it will be a lot of cleanup-work to be done if one accidentally forgets "-1" and adds some hundreds of items to the calendar ... + +```kal select --todo --categories=housework --smart-sort --limit=3 pin '2021-12-02 16:00' + +## Time tracking + +(see also [NEXT_LEVEL.md](NEXT_LEVEL.md)) + +The `complete` subcommand takes optional parameters `--spent=4h`, `--log="I just hammered on the keyboard all until eventually all the unit tests finally passed. yay!"`, `--start=2021-10-06T12:00` and `--end=2021-10-06T16:00`. + +Rules: + +* A new journal entry is created, and marked as the child of the completed task or event. +* Both events and tasks can be "completed". If an event is "completed", it is implicit that time was spent, and time will be tracked even without any extra parameters. +* If a task was completed and it has a child event ("pinned task"), it is to be considered as if the child event was completed. +* For an "ordinary" task (one that isn't pinned), time will only be tracked if at least one of the four options above is given. Meaning that if no such option was given, the rest of the logic is ignored. +* If all three time-related parameters are given, the duration should match dtend-dtstart, and this should be validated. +* If two of the three time-related parameters are given, the third will be calculated. +* If only `--spent` is given and it's an event, '--start' is considered to be the dtstart of the event, and `--end` can be calculated. +* If only `--spent` is given and it's an ordinary task, `--end` is considered to be the time the task was marked completed (which is "now") and `--start` can be calculated. +* If only start is given, the duration of the event/task is used to find `--spent`, and from there `--end` can be calculated. +* If no time parameters are given, and it's an event, use dtstart and due/dtend +* If no time parameters are given, and it's a task, set completed (and `--end`) to "now", consider the duration estimate as correct, and find `--start` from there. +* The new journal dtstart date should be set to the date of the `--start` timestamp +* For a pinned task having a child event without extra participants, we consider the event data as unimportant to keep. If the time parameters doesn't match the event dtstart/duration/dtend, then the event should simply be edited and saved back, and used as the parent for the new journal entry. +* For an ordinary event, if `--start` and `--end` doesn't match the dtstart and dtend, duplicate the event, prepend the summary with "Completed:" and let the new event be a parent of the new journal entry. +* For an ordinary task, if the duration matches, the journal entry will be a direct child of the task +* We don't want to edit the duration of a task - that's the original estimate and we may want to keep that information. If it's an ordinary task and the duration of the task does not match, then the task information should be duplicated in a new child event, this child event should be the parent of the journal entry, and the summary should be prepended with "Completed: " + +...clear as mud? :-) + +## Scheduling + +TODO + +## Interactivity + +Quite much can be gained by using any kind of desktop calendar application, mobile calendar app or caldav webui towards the calendar - though as per the cruft in the examples/task-management-examples it could probably be an idea to create some kind of a simple text UI allowing to interactively going through a list of tasks and do things on them, like: + +* Setting one or more categories on all tasks missing a category +* Setting due-date and priority on all tasks missing that +* Go through all overdue and neardue tasks and mark the completed ones as completed +* Go through all events that has just passed and mark up if one really attended or not, and time spent while doing so. +* Easily go through a list of tasks suggested to be postponed and interactively select/unselect tasks from there. + +In examples/task-management-examples I simply used the `list`-command combined with `--todo-template` to create new calendar-cli commands, those were sent to an editor for manual editing. The script looks horrible, but it kind of works. diff --git a/NEXT_LEVEL.md b/NEXT_LEVEL.md index 9ce4752..ccf957a 100644 --- a/NEXT_LEVEL.md +++ b/NEXT_LEVEL.md @@ -16,13 +16,13 @@ * Tasks (VTODOs) can be "striked out", but they don't stick very well to the calendar, and it cannot be used for tracking the time spent working on a task -* VJOURNAL entries on a calendar is meant exactly for meeting notes ... probably as well as recording things like who was really participating in an event, and how much time did they spend on it? +* VJOURNAL entries on a calendar is meant exactly for meeting notes ... probably as well as recording things like who was really participating in an event, and how much time did they spend on it? (when checking up: not really, a journal entry cannot have a duration or an end timestamp) -* Tasks have a DTSTART and either a DUE or a DURATION; the latter two are interchangable, the standard defines that the DURATION is the difference between DTSTART and DUE. The standard is a bit unclear on exactly what those timestamps are to be used for. I assume the DUE is the "hard" due date where a task should be completed. It makes sense to let DURATION be the time estimate for the task, then DTSTART will be the latest possible start time if the task is to be completed before the DUE date. This breaks with my usage up until now; I've used DTSTART as when I'm planning to consider to start working on the task. +* Tasks have a DTSTART and either a DUE or a DURATION; the latter two are interchangable, the standard defines that the DURATION is the difference between DTSTART and DUE. The standard is a bit unclear on exactly what those timestamps are to be used for. I assume the DUE is the due date where a task should be completed. This may be a very hard due date (i.e. the task "packing the suitcase" obviously needs to be done before the plane departure). It makes sense to let DURATION be the time estimate for the task, then DTSTART will be the latest possible start time if the task is to be completed before the DUE date. Obviously, if one expects to spend half an hour packing the suitcase and one needs to rush out the door at 19:30, one ought to start packing the suit case long before 19:30. This breaks with my usage up until now; I've used DTSTART as the earliest point of time I'm planning to consider to start working on the task (and sometimes this may also be a well-defined timestamp - the suitcase probably shouldn't be packed several days before departure). * It is possible to specify that a task should be a recurring task, but there is no explicit support in the RFC of completing an occurrence. In the existing version of calendar-cli, a new "historic" task instance is created and marked complete, while dtstart is bumped in the "open" task. (there is an alternative interpretation of "recurring task", it could mean "let's work on project A every Tuesday after lunch, all until it's completed"). -* Calendar components can be linked through the RELATED-TO-attribute. Valid relationship types are "CHILD", "PARENT" and "SIBLING". I suppose it is intended for direct asynclic graphs, where a calendar component preferably should have only one PARENT, and where there shouldn't be loops (my grandchild cannot possibly also be my grandparent) - and that two SIBLINGs have the same PARENT. +* Calendar components can be linked through the RELATED-TO-attribute. Valid relationship types are "CHILD", "PARENT" and "SIBLING". I suppose it is intended for direct asyclic graphs, where a calendar component preferably should have only one PARENT, and where there shouldn't be loops (my grandchild cannot possibly also be my grandparent) - and that two SIBLINGs have the same PARENT. * RFC6638 gives a framework for inviting and replying to calendar events ("scheduling"), but few calendar servers supports it fully. @@ -50,7 +50,9 @@ A calendar event could be "striked-out" if it has a child VJOURNAL entry. A tas * A VEVENT linked up as a parent to a VTODO means the VTODO needs to be completed before the event. Once the event has passed, the VTODO should probably be cancelled if it wasn't done yet. -* DURATION should be used for time estimates (this breaks with my previous usage of DTSTART for prioritizing tasks). For tasks with children tasks, DURATION in the VEVENT should only indicate the "independent" time usage. Total duration including all children tasks should eventually be calculated and presented by the calendar application. +* A VTODO (A) linked up as a parent to another VTODO (B) means either that B is a subtask of A or that A depends on B. In either case, B needs to be completed before A can be completed. + +* DURATION (efficiently meaning DTSTART, when DUE is set) should be used for time estimates (this breaks with my previous usage of DTSTART for prioritizing tasks). In the case of subtasks, DURATION in the VEVENT should only indicate the "independent" time usage (so the real time estimate for the full task is the sum of the estimate for all the subtasks). (And this is silly, since that means the Total duration including all children tasks should eventually be calculated and presented by the calendar application. * PRIORITY should indicate how important it is to do the task by the indicated DUE date/timestamp. If PRIORITY=1, then the task is extremely important AND the DUE is a hard deadline. PRIORITY=9 may mean either that DUE is a "fanciful wish" OR that the task should simply be cancelled if it's difficult to get it done prior to the DUE date. @@ -64,119 +66,5 @@ A calendar event could be "striked-out" if it has a child VJOURNAL entry. A tas ## New calendar-cli interface -### General thoughts - -* calendar-cli should be a simple command line wrapper over existing python libraries. It should not contain a lot of logic besides parsing command line options and arguments. Logic that may be useful for python programmers should be pushed to other libraries, like the caldav-library, or be split into a new library. -* Old calendar-cli stays for quite some time, for backward compatibility -* We'll split out a new command for the new interface, probably it will be `kal`. I considered a lot of different name options: - * cal ... but `cal(1)` - is a well-established command, so it's out of the question (unless we overload the command by making a wrapper calling `cal` if no subcommand is given ... that could be an idea). - * `calcli`, `cal-cli` and different variants of it. The dash already hurt me with calendar-cli, don't want to repeat that. And "cli" is a bit redundant, when typing a command on the command line it's reasonable to assume it's a cli. - * `cal-add`, or even `cal-add-todo` ... but modern cli frameworks are more often than not built over different variants of `command subcommand subsubcommand`. - * `kal` ... looks a bit like a silly misspelling or an attempt to localize it into some non-english language (which then will look silly when combined with english subcommands and english options). At the other hand, I do see that it's not entirely uncommon to use `klass` when putting a class into a variable in python, `kal` is short to type, easy to remember, and there aren't too many other projects utilizing the `kal`-name as far as I can see. -* We'll use click, which is supposed to support subcommands in an elegant way. -* I'm fairly happy with the todo interface for listing/editing/completing. First options to filter/sort/limit the todo item(s), then a subcommand for what to do on those items. -* Should consider that we at some point may want to support tools that doesn't support caldav. Should als oconsider that we may want to support tools that doesn't support icalendar. For instance, issue tracking through gitlab or github. -* Perhaps a new calendar-tui for increased interactivity? -* Some or all of the commands should be possible to iterate over several calendars. This is almost impossible with `calendar-cli` due to the way the configuration is made (perhaps we should require that connection parameters are given in a config file?) - -### Details - -Add an event, task or journal entry: - -``` -kal --config-section=private_calendar add --set-location="Aker Brygge marina" event 2032-12-31T20:00+5h "new years party" -kal add todo "Buy food for the new years party" --set-due=2032-12-30T20:00 --set-duration=1h - -kal add journal "Captain's log" 2020-12-04 'Started from Świnoujście a bit after 03AM. Due to miscommunication, bad planning and language problems my crew member Bartek managed to throw the whole mooring rope to the sea (clearly the captains fault - I didnt explain the task "release one end of the rope, let it go into the sea and then pull it in" well enough, and he did ask "are you really sure about that?" before throwing both ends of the rope to the sea). Tail wind, between 8-16 knots relative windspeed, changed a bit between broad reach and butterfly. While going butterfly, due to a rather big wave we had an accidental jib, bad enough that the preventer rope broke off the cleat it was attached to (but luckily no damanges to the rig). There seems to be a minor salt water leakage by the rudder. Passed Falsterbo around 21, moored up in the guest harbour in Skanör around 22. Very quiet as it was way outside the season. Didnt find any obvious choice on the payment automat for harbor fee - eventually I payed SEK 100 for "tvättstuga". I got no access to the laundry room, so I decided that 100 SEK was an OK price for staying overnight with electricity off-season in Skanör.' -``` - -While the specification for journal, todo and event are fairly similar, the non-optional parameters will be different due to slightly different typical use-case scenarios: - -* All three should have a summary as the mandatory first parameter. -* For making todos, that should be the only mandatory parameter (as with "calendar-cli todo add"). Not all tasks have a clear due-date. In accordance with my task management ideas above, all tasks should eventually have a due date set, but the idea is also to be able to quickly throw things on the list, and then consider an appropriate priority and due date later. -* dtstart is (according to the rfc) optional for all three classes, but it doesn't make much sense to have an event without a start time - and a journal entry should have a date. For events, the same timestamp format is used as in the existing calendar-cli - duration can be piggybacked in the timestamp. Change of parameter order, with "calendar-cli calendar add" the dtstart should come before the summary. This to make "summary first" consistent for all three calendar object resource classes. -* For journal entries (as they are intended), it doesn't make much sense to add an entry without a description, so it's the mandatory second parameter. - -The todo-item added above has both due timestamp and duration set, which is against the RFC. It will be converted to dtstart and due before it's pushed to the calendar. - -To get things out from the calendar, one can use the kal agenda command. - -``` -kal agenda --config-section=private --config-section=work --agenda-days=30 --event-template="{dtstart} {summary} UID={uid}" --todo-template="{due} {summary} UID={uid}" -``` - -kal agenda should first print out all events starting or ending within the next 30 days, then all tasks with dtstart or due within the next 30 days. (in my revised "task management" above, dtstart is defined as due minus estimated work time). The tasks should be "smart sorted", according to the algorithm given in the "Task management" section above ("based on the ratio between duration and available time until due date"). It should accept several --config-section, take out all it can find from those config sections and sort the things afterwards. Exceptions due to unreachable caldav servers or calendars not supporting tasks etc should be caught and presented nicely. - -The kal agenda is to be considered a convenience-command, it is slightly redundant. The output of the command should be considered to be for direct human consumption, no further processing of the output should be done. The kal select command is the ultimate tool for a lot of things: - -``` -kal select --timespan=2021-12-01+2w list -kal select --todo --nocategories --list -kal select --todo --nocategories -1 edit --add-category=keyboard -kal select --todo --due-before=2021-12-01 --categories=keyboard --smart-sort list -kal select --todo --due-before=2021-12-01 --categories=keyboard --smart-sort -1 complete -kal select --uid=e71a6180-45a2-11ec-9605-fa163e7cfdd5 delete -kal select --due-before=2021-12-24T15:00 --categories=housework calculate-panic-time --work-factor=0.125 -kal select --journal --dtstart-after=2021-10-01 --dtstart-before=2021-11-01 sum_hours -``` - -kal select should select objects based on some criterias and then perform some action (`list`, `edit`, `postpone`, `complete`, `delete`, `calculate-panic-time`, 'sum_hours' and some more - see further below) on the objects. - -The technical differences between tasks, events and journal entries are small - kal select should basically work on all three of them unless `--todo`, `--event` or `--journal` is epxlicitly given. If the action given does not match one or more of the objects selected (say, "completing" a journal does not make sense), the script should raise an exception before doing any modifications of the calendar. `--offset` and `--limit` may be used to specify a handful of objects. "-1" is shortform for "--limit 1", or typically "do this action with the top item at the list" - -`--smart-sort` will give the above mentioned sort algorithm for tasks, and regular sorting by dtstart for events and journals. - -The `calculate-panic-time` command will take out all planned events and todo items, count the duration of those and print out a timestamp for when you need to panic. If it shows a timestamp in the past one should either PANIC!!! or procrastinate some tasks and cancel some events. The command takes the `--work-factor` parameter which specifies how much of the time you will be able to concentrate on the selected tasks. For instance, an "ordinary" parent having kids to take care of, a daytime job, plus the need for sleeping every night may perhaps in average be able to spend 3 hours a day - or 12.5% of the full day - on house work. - -This should cover most regular needs for putting events on a calendar and managing tasks and todo-lists. It does not cover "pinning" tasks to a calendar nor tracking time spent on tasks. There may also be a need for a bit more interactivity. Sending invites and replying to invites is also not covered. - -Logical "and" should be assumed between filter selectors. I feel uncomfortable with implementing support for paranthesis and logical operators, but there could probably be a --union parameter working as a "logical or", and some syntax should be made for the individual filters (but `--limit`, `--offset` and `--sort` should be processed after the union). Perhaps `--categories=housework+gardenwork` should fetch everything with either "housework" or "gardenwork" as category, while `--categories=housework,kitchen` should fetch all housework to be done in the kitchen. Or maybe `--categories=housework&gardenwork` and `--categories=housework|gardenwork` is less ambiguous. It probably needs to be thought more through. - -sum_hours will sum the duration of all objects. Journal entries cannot have duration, so for journal entries it will sum the duration of all parents to all the journals selected. This is supposed to be equal to the total time spent working. - -### Pinning tasks to calendar - -The `pin` subcommand will "pin" one or more todo-items to some specific time on the calendar. Duration will be copied. The tasks will be serialized. If there are conflicting events in the same calendar, the tasks will be put after the conflicting events. No checks will be done to ensure that the tasks ends up within ordinary working hours, outside the night hours or before the due date. Or perhaps some sanity checks should be done ... it will be a lot of cleanup-work to be done if one accidentally forgets "-1" and adds some hundreds of items to the calendar ... - -```kal select --todo --categories=housework --smart-sort --limit=3 pin '2021-12-02 16:00' - -### Time tracking - -The `complete` subcommand takes optional parameters `--spent=4h`, `--log="I just hammered on the keyboard all until eventually all the unit tests finally passed. yay!"`, `--start=2021-10-06T12:00` and `--end=2021-10-06T16:00`. - -Rules: - -* A new journal entry is created, and marked as the child of the completed task or event. -* Both events and tasks can be "completed". If an event is "completed", it is implicit that time was spent, and time will be tracked even without any extra parameters. -* If a task was completed and it has a child event ("pinned task"), it is to be considered as if the child event was completed. -* For an "ordinary" task (one that isn't pinned), time will only be tracked if at least one of the four options above is given. Meaning that if no such option was given, the rest of the logic is ignored. -* If all three time-related parameters are given, the duration should match dtend-dtstart, and this should be validated. -* If two of the three time-related parameters are given, the third will be calculated. -* If only `--spent` is given and it's an event, '--start' is considered to be the dtstart of the event, and `--end` can be calculated. -* If only `--spent` is given and it's an ordinary task, `--end` is considered to be the time the task was marked completed (which is "now") and `--start` can be calculated. -* If only start is given, the duration of the event/task is used to find `--spent`, and from there `--end` can be calculated. -* If no time parameters are given, and it's an event, use dtstart and due/dtend -* If no time parameters are given, and it's a task, set completed (and `--end`) to "now", consider the duration estimate as correct, and find `--start` from there. -* The new journal dtstart date should be set to the date of the `--start` timestamp -* For a pinned task having a child event without extra participants, we consider the event data as unimportant to keep. If the time parameters doesn't match the event dtstart/duration/dtend, then the event should simply be edited and saved back, and used as the parent for the new journal entry. -* For an ordinary event, if `--start` and `--end` doesn't match the dtstart and dtend, duplicate the event, prepend the summary with "Completed:" and let the new event be a parent of the new journal entry. -* For an ordinary task, if the duration matches, the journal entry will be a direct child of the task -* We don't want to edit the duration of a task - that's the original estimate and we may want to keep that information. If it's an ordinary task and the duration of the task does not match, then the task information should be duplicated in a new child event, this child event should be the parent of the journal entry, and the summary should be prepended with "Completed: " - -...clear as mud? :-) - -### Scheduling - -TODO - -### Interactivity - -Quite much can be gained by using any kind of desktop calendar application, mobile calendar app or caldav webui towards the calendar - though as per the cruft in the examples/task-management-examples it could probably be an idea to create some kind of a simple text UI allowing to interactively going through a list of tasks and do things on them, like: - -* Setting one or more categories on all tasks missing a category -* Setting due-date and priority on all tasks missing that -* Go through all overdue and neardue tasks and mark the completed ones as completed -* Go through all events that has just passed and mark up if one really attended or not, and time spent while doing so. -* Easily go through a list of tasks suggested to be postponed and interactively select/unselect tasks from there. +This section has been moved to a separate document, [NEW_CLI.md](NEW_CLI.md) -In examples/task-management-examples I simply used the `list`-command combined with `--todo-template` to create new calendar-cli commands, those were sent to an editor for manual editing. The script looks horrible, but it kind of works. @@ -8,9 +8,18 @@ See https://www.gnu.org/licenses/gpl-3.0.en.html for license information. This is a new cli to be fully released in version 1.0, until then quite much functionality will only be available through the legacy -calendar-cli +calendar-cli. For discussions on the directions, see +https://github.com/tobixen/calendar-cli/issues/88 """ +## This file should preferably just be a thin interface between public +## python libraries and the command line. Logics that isn't strictly +## tied to the cli as such but also does not fit into other libraries +## may be moved out to a separate library file. + +## This file aims to be smaller than the old calendar-cli while +## offering more featuores. + from calendar_cli import __version__ import click @@ -29,6 +38,10 @@ import caldav ## See https://click.palletsprojects.com/en/8.0.x/api/#click.ParamType and ## /usr/lib/*/site-packages/click/types.py on how to do this. +## TODO ... +def _parse_timespec(timespec): + raise NotImplementedError() + @click.group() ## TODO #@click.option('-c', '--config-file', type=click.File("rb"), default=f"{os.environ['HOME']}/.config/calendar.conf") @@ -77,6 +90,13 @@ def test(ctx): """ click.echo("Seems like everything is OK") +attr_txt_one = ['location', 'description', 'geo', 'organizer', 'summary'] +attr_txt_many = ['categories', 'comment', 'contact', 'resources'] + +def set_attr_options(func): + for foo in attr_txt_one: + func = click.option() + @cli.group() @click.option('-l', '--add-ical-line', multiple=True, help="extra ical data to be injected") @click.option('--multi-add/--no-multi-add', default=False, help="Add things to multiple calendars") @@ -93,7 +113,6 @@ def add(ctx, **kwargs): ctx.obj['calendars'] = [ calendar ] else: raise click.Abort() - click.echo("working on something here") ctx.obj['ical_fragment'] = "\n".join(kwargs['add_ical_line']) @add.command() @@ -103,6 +122,8 @@ def add(ctx, **kwargs): def ical(ctx, ical_data, ical_file): if (ical_file): ical = ical_file.read() + if ctx.obj['ical_fragment']: + ical = ical.replace('\nEND:', f"{ctx.obj['ical_fragment']}\nEND:") for c in ctx.obj['calendars']: ## TODO: this may not be an event - should make a Calendar.save_object method c.save_event(ical) @@ -113,9 +134,25 @@ def todo(): raise NotImplementedError("foo") @add.command() -def event(): - click.echo("soon you should be able to add events to your calendar") - raise NotImplementedError("foo") +## TODO +@click.argument('description') +@click.argument('timespec') +@click.pass_context +def event(ctx, description, timespec): + """ + Creates a new event with given DESCRIPTION at the time specifed through TIMESPEC. + + TIMESPEC is an ISO-formatted date or timestamp, optionally with a postfixed interval. + + Examples: + + kal add event "final bughunting session" 2004-11-25+5d + kal add event "release party" 2004-11-30T19:00+2h + """ + for cal in ctx['calendars']: + (dtstart, dtend) = _parse_timespec(timespec) + #event = cal.add_event( + click.echo(uid) def journal(): click.echo("soon you should be able to add journal entries to your calendar") diff --git a/calendar-cli.py b/calendar-cli.py index c8862ad..1891497 100755 --- a/calendar-cli.py +++ b/calendar-cli.py @@ -3,7 +3,9 @@ """ https://github.com/tobixen/calendar-cli/ - high-level cli against caldav servers. -This is the legacy calendar-cli. A new interface is being built in cli.py +This is the legacy calendar-cli. A new interface is being built in cal.py - aka kal +Feedback/wishes/discussions on the new cli can be held at +https://github.com/tobixen/calendar-cli/issues/88 Copyright (C) 2013-2021 Tobias Brox and other contributors. diff --git a/tests/_setup_alias b/tests/_setup_alias index 0d5c302..bfa34f0 100644 --- a/tests/_setup_alias +++ b/tests/_setup_alias @@ -1,6 +1,7 @@ outfile=$(mktemp) error() { + echo "FAILURE" echo "$1" echo "sleeping 3" sleep 3 diff --git a/tests/tests.sh b/tests/tests.sh index a71f8b5..b93d037 100755 --- a/tests/tests.sh +++ b/tests/tests.sh @@ -82,7 +82,7 @@ calendar_cli calendar delete --event-uid=$uid echo "## Same, using kal add ics" kal add ical --ical-file=$tmpfile -#rm $tmpfile +rm $tmpfile calendar_cli --icalendar calendar agenda --from-time=2010-10-13 --agenda-days=1 echo "$output" | grep -q "whole day" || error "could not find the event" echo "$output" | grep -q "20101010" || error "could not find the date" @@ -91,6 +91,19 @@ echo "OK: found the event" echo "## cleanup, delete it" calendar_cli calendar delete --event-uid=$uid +## TODO - procrastinated, waiting for response on https://github.com/dateutil/dateutil/issues/1184 +#echo "## Same, using kal add event" +#kal add event '2010-10-10+4d' 'whole day testing' +#uid=$(echo $output | perl -ne '/uid=(.*)$/ && print $1') +#[ -n "$uid" ] || error "got no UID back" +#calendar_cli --icalendar calendar agenda --from-time=2010-10-13 --agenda-days=1 +#echo "$output" | grep -q "whole day" || error "could not find the event" +#echo "$output" | grep -q "20101010" || error "could not find the date" +#echo "$output" | grep -q "20101010T" && error "a supposed whole day event was found to be with the time of day" +#echo "OK: found the event" +#echo "## cleanup, delete it" +#calendar_cli calendar delete --event-uid=$uid + echo "## A full day event should be implicit when giving dates rather than timestamps" calendar_cli calendar add '2010-10-10+3d' 'whole day testing' uid=$(echo $output | perl -ne '/uid=(.*)$/ && print $1') |