Busy
====
Busy is a personal time management tool, designed to help us all through our crazy busy days with as little stress as possible. It's simple, fast, and fun to use.
Usage
=====
Principles
----------
Busy is built with the following usage principles in mind:
- *Monotasking*: We each focus better when we work on exactly one task at a time. So busy only shows you one task.
- *Keyboard-driven*: Productive people use the keyboard effectively, because muscle memory builds up over time, and it's faster to hit a key than to find an icon on a screen and move the pointer.
- *Offline use*: It's designed to run on your laptop or desktop computer, without needing an internet connection, so it works extremely fast under any conditions.
- *Multi-platform* Because Busy is a terminal-based application, it will run on MacOS, Linux, or Windows.
- *Personal*: Busy is not a collaboration platform or project management application. It's for managing your personal time, not assigning things to others.
- *Importance over Urgency*: Stop stressing out over last-minute tasks and impending deadlines! Busy makes it easy to capture future tasks and remember to do them early enough to reduce the pressure.
- *Editable data*: The data is stored in text files, which can easily be edited outside of Busy itself. (In fact, Busy started as a todo.txt type of approach and grew from there.)
_The idea of Importance over Urgency comes from the book "The 7 Habits of Highly Effective People". Although we firmly disagree with Steven Covey's statements on gay rights, the book contains excellent ideas._
Installation
------------
Beginners, see [INSTALLATION.md](INSTALLATION.md).
Experienced folks, use [pipx](https://pypa.github.io/pipx/) to install Busy.
```bash
pipx install busy
```
To upgrade:
```bash
pipx upgrade busy
```
Overview
--------
Busy ships with two user interfaces, both of them terminal-based and keyboard-driven:
- *Shell UI* - A command-line interface (CLI) using shell conventions and called directly from the shell, one command at a time.
- *Curses UI* - A faster, more visual interface with one-key commands that remains visible the entire time it's being used.
Some commands also use your favorite terminal-based text editor, such as Emacs, vi, or Nano. It's possible to use Busy without a text editor, but functionality is limited.
Busy's core model is a collection of Items, the most interesting of which are Tasks. Items are organized into Queues, which are ordered sets. You work on the top Task in the Queue, and when it's done, that Task gets removed from the Queue to reveal the next one. There is a default Queue (called "tasks") but you can also create other Queues, for example a shopping list or discussion list.
In addition to the "tasks" Queue, Busy maintains the "plans" Queue for future tasks (don't worry about them yet!) and the "done" Queue as a record of what's been completed in the past.
Using the Shell UI
------------------
To get started, add some Tasks to your default Queue.
```
busy add --description "Take a shower"
busy add --description "Do the laundry"
busy add --description "Phone mom"
busy add --description "Donate to the Busy project"
```
Then, when you're ready to start your day, ask Busy what to do first:
```
busy top
```
Returns:
```
Take a shower
```
_Yes, Busy is great for tracking daily, personal, habitual tasks in addition to work tasks. It feels great to mark things as done!_
When you've finished that task, mark it off to find the next task.
```
busy finish
```
It will ask you to confirm that you're done. Then request the next task:
```
busy top
```
Which will tell you what to do next:
```
Do the laundry
```
If you want to see the whole Queue, with sequence numbers, type:
```
busy list
```
Here's the list you will see. Note that the completed Task is gone:
```
1 Do the laundry
2 Phone mom
3 Donate to the Busy project
```
If you decide, in the moment, to wait until later today to perform a task, drop it to the bottom of the Queue using the `drop` command:
```
busy drop
```
Then `busy list` will return:
```
1 Phone mom
2 Donate to the Busy project
3 Do the laundry
```
If you see a task on the list that seems urgent, and you intend to perform it immediately, pop it to the top of the list:
```
busy pop 2
```
_Our use of the term "pop" for a command doesn't quite fit with the computing term "pop". It might change in the future._
Then `busy get` will return:
```
Donate to the Busy project
```
Let's say you realize that it's not an appropriate task for today, but you want to defer it to tomorrow:
```
busy defer
```
It will ask you to confirm "tomorrow" as the day for deferral. Agree with it for now.
At the start of a new day, tell Busy to add all the previously deferred Tasks to the current Queue:
```
busy activate
```
Commands
--------
Here's a summary of the commands in Busy.
- `add` adds a new item to the bottom of the queue. The item description may be included after the command or written to stdin (i.e. typed on the next line).
- `top` gets the top item in the queue, referred to as the "current" item. There are no options.
- `list` lists the items in the queue in order with their sequence numbers.
- `pop` moves a task or set of items to the top of a queue.
- `drop` moves a task or set of items to the bottom of a queue.
- `delete` permanently removes a task or set of items from a queue.
- `edit` opens a text editor to edit items - the default is to edit only the top item.
- `manage` is the same as `edit`, but defaults to edit the whole queue.
- `finish` removes a task or tasks from the `tasks` queue and adds it to the `done` queue, so it's complete. Good job!
- `defer` removes a task or set of tasks from the `tasks` queue and schedules it or them to reappear at a future date in the `plans` queue.
- `activate` moves current tasks from the `plans` queue to the `tasks` queue. Get to work!
- `queues` to list all the queues.
- `tags` to list all the tags.
Except for `add` and `top`, commands allow the designation of specific items to be acted upon. Item designation can be performed using sequence numbers or tags.
Sequence numbers
----------------
Sequence numbers appear in the output from the `list` command. Note that the numbering starts with 1, and is not an ID -- the number of a item will change when the queue is modified. So always reference the most recent output from the `list` command.
To designate more than one item, separate the sequence numbers with a space.
When used to designate items, a range of sequence numbers is separated by a hyphen, with no whitespace, and is inclusive. For example, `4-6` designates items 4, 5, and 6. A hyphen without a number after it includes all the items from that item to the end of the queue. A hyphen on its own indicates the last item in the queue.
Below are some examples of task designations by sequence number.
- `busy pop 5` pops item number 5
- `busy drop 3-7` drops items 3 through 7 (4 items)
- `busy list 3-` lists all the items from number 3 through the end of the list
- `busy delete 3 5 7 9` deletes only the items designated
- `busy defer -` defers the last task
- `busy edit -4` is an error! Use `busy edit 1-4` instead
- `busy manage` allows you to edit the entire queue
Items will always be handled in the order they appear in the queue, regardless of the order the criteria are provided. So for example, if a `pop` command designates some items, they will be moved to the top of the queue in the order, relative to each other, they currently appear in the queue.
The sequence numbers in the `list` command output are from the queue itself. So the `list` command does not modify the sequence numbers, even when item designation is applied.
Tags
----
Items can have tags, which are space-separated hashtags in the item description. An item can have no tags, one tag, or more than one tag. For example the following item description has the tag "errands":
```
go to the supermarket #errands
```
Tags cannot contain punctuation.
Hash tags may be used for item designation, in which case the hash itself ("#") is omitted from the command line. For example, the following command will move all the items with the `#errands` tag to the top of the queue.
```
busy pop errands
```
Whitespace-separated item designation criteria are additive -- that is, a logical OR. For example, the following command will delete all the admin tasks, sales tasks, and tasks 3 and 4.
```
busy delete admin sales 3 4
```
Default item designations
-------------------------
For the most part, commands that accept item designations default to only act on the top item in the queue. The exceptions are:
- `list` defaults to list the entire queue
- `pop` defaults to pop the last item in the queue to the top
- `activate` defaults to activate items for today (more on that below)
Alternate queues
----------------
Busy will manage any number of queues, which are entirely separate ordered sets of items. For example, you might have a `shopping` queue for items to buy at the store, and a `movies` queue for films you'd like to watch. The default queue is called `tasks` and has special properties related to planning.
To designate an alternate queue, use the `--queue` option on a command. For example:
```
busy add "Skimmed Milk" --queue shopping
busy top --queue movies
```
Managing plans
--------------
The default `tasks` queue supports several specific commands related to planning -- that is, scheduling tasks for the future. They are `finish`, `defer`, and `activate`. The task-specific commands do not accept a `--queue` modifier, because they only work on the default `tasks` queue. Planned tasks are kept in another special queue called `plans`, and completed tasks are kept in a queue called `done`.
The task commands accept item designations. The `defer` and `finish` commands reference the `tasks` queue; the `activate` command references the `plans` queue. The default for `defer` and `finish` is the top item in the `tasks` queue; the default for `activate` is to activate only plans deferred to today or earlier.
Planning by date
----------------
Planning is by date, not time, and is relative to the current date according to the system clock.
In the `defer` command, the date can be specified using the `--to` or `--for` option (they are interchangable). If the options are omitted, then the date can be provided as input.
The date may take any of the following forms:
- A specific date in `YYYY-MM-DD` format, such as `2018-10-28`. Slashes are also acceptable, but the order is always year, then month, then day.
- A specific date without the year in `MM-DD` format, such as `7-4`, which will defer the item to that date in the future (even if it's in the next year).
- A specific day of the month as a simple integer, such as `12`, which will defer the item to that day of the month, in either the current month or the next month.
- An integer, a space, and the word `day` or `days`, such as `4 days`, which will defer the item to that number of days from today.
- An integer without a space and the letter `d`, such as `4d`, which is a short form of `4 days`.
- The word `tomorrow`, which is also the default if no date is provided.
- The word `today`, which is a little odd but obvious.
As an example, the following command will defer tasks 4, 5, and 6 from the `tasks` queue to the date 4 days from today, keeping them in the `plans` queue until that date.
```
busy defer 4-6 --for 4 days
```
Note that the `plans` queue is keeping the task information (verbatim from the `tasks` queue) along with the date information (as an absolute date).
To pull tasks off the `plans` queue and put them back on the `tasks` queue, use the `activate` command. There are two ways to use the `activate` command:
- With no item designation, in which case Busy activates all the tasks scheduled for today or earlier, bringing the `tasks` list up to date
- With designated items from the `plans` queue; note that the `activate` command accepts item designation from the `plans` queue itself
Finishing and following up
--------------------------
Like `defer`, the `finish` command only works on the `tasks` queue. It removes the designated Task (or the top task if none is designated) from the queue and adds it to the `done` queue, with today's date to indicate when it was completed.
Optionally, a task can have a followon, which is another task to be added to the queue after the first task is finished. Followons are described in a task using an arrow notation. In the following example, the task "eat" has a followon task "drink":
```
eat --> drink
```
Note that the hyphens and whitespace are optional; really the marker that matters for delimiting a followon is the right angle bracket (">"). Also note that right angle bracket is not a valid character in a task description.
When the `finish` command is executed on the task above, the "eat" task will be recorded as "done" and the "drink" task will be added to the bottom of the `tasks` queue.
Note that followons can be chained. For example, when the `finish` command is run on the task illustrated below, a new task "drink > be merry" will be added to the queue. Only when that Task is finished will the "be merry" task itself appear on the queue.
```
eat > drink > be merry
```
Repeating tasks
---------------
A special type of followon is the repeat. In this case, instead of adding the next task to the bottom of the queue, the entire current task -- including the Followon itself -- is entered into the `plans` queue at some point in the future. Repeats allow for easy management of repeating tasks. Some examples follow.
- `check email --> repeat in 1 day`
- `phone mom --> repeat on sunday`
- `balance the checkbook --> repeat on 6`
The exact syntax for a Repeat is the word "repeat" followed by either "on" or "in" and a relative date phrase -- the same phrases that work with the `defer` command.
Note that the repetition itself only happens on the `finish` command. The completed task (i.e. "check email") is entered in the `done` queue and then the entire task (with the Repeat) is scheduled in the `plans` queue for the appropriate time in the future.
Editing items
-------------
The `edit` and `manage` commands launch the user's default text editor to directly edit a task, the whole queue, or part of a queue. Note that `edit` and `manage` are identical commands except for their defaults.
The definition of the "default text editor" depends on the OS and configuration but here's the logic:
1. Try the EDITOR environment variable
1. If that doesn't exist, try the `sensible-editor` command (Ubuntu)
1. If that doesn't exist, try the `open -W` command (OSX)
You must quit the editor to accept the change back into Busy.
The `edit` command with no criteria will edit the top item in the queue, and the `manage` command with no criteria will edit the entire queue. But it's also possible to designate items to be edited with both commands. The commands do their best to replace the edited items in place in the list order. So if you `edit` or `manage` a tag whose items are recently popped (at the top of the queue), then the edited items will still appear at the top. Even if you add items, they will be inserted after the last item in the edited set, not at the end of the queue. But all the items brought up in the editor will be edited. So if you remove an item in the editor, it will be deleted and the others will be moved up to take its place.
For faster daily use - the Curses UI
------------------------------------
Busy suports multiple user interfaces. The command line interface described above is the shell interface. The alternative is the curses UI, which draws an entirely new terminal in the same window.
_We get it - "curses" is a terrible name. It's a reference to the underlying technology. It's likely to change._
As of now, the curses UI only supports the `tasks` queue. The commands can be triggered with single keystrokes, and only act on their default tasks (usually the top task). The UI always displays the current queue (which is always `tasks` for now) and the current (top) task at the top of the screen.
To invoke the curses UI, type:
```
busy curses
```
Commands within the UI are shown with a single letter underlined. The underlined letter is the keystroke that will invoke the command. Use `q` to quit. When inside a command, use ctrl-C to cancel the command and return to the main menu.
Data storage
------------
Busy keeps the queues in plain text files, so if the tool doesn't do something you want, you may edit the files. The files are in a directory together, referred to as the "root". Each file is the name of the queue with a `.txt` extension. If a required file is missing, it will be created automatically. So typically, the root includes `tasks.txt`, `plans.txt`, `done.txt`, and any number of custom queue files.
Technically, Busy data files are pipe-delimited data files, though `tasks.txt` and any custom queues only have one field ("description") while `plans.txt` and `done.txt` have only two fields (date and description).
Busy is not a database (yet). There is no support for managing separate fields in the Busy tool itself.
The root is designated in one of the following ways, which are tried in order.
- The `--root` option on any command
- The `BUSY_ROOT` environment variable, if no `--root` option is provided
- A directory at `~/.busy`, which will be generated as needed if no `--root` option or `BUSY_ROOT` environment variable are provided,
Note that the `--root` option must come after `busy` but command-specific options (`--yes`, `--to`, `--for`, and `--queue`) must come after commands.
The following example shows the `--root` option with command-specific options on the same command line.
```
busy --root ~/.config/busy defer --to tuesday
```
Note that Busy does not support concurrency in any form. If two commands are executing at the same time, they might overwrite each other. Overwriting is especially risky with the `edit` command, which keeps the user's editor open until they close it.
The format is designed to be simple (i.e. non-default queues are really just lists of items) but not idiot-proof. Experimentation might result in unintended consequences.
Development
===========
The code is intended to demonstrate some Python best practices:
- *Object-oriented* with classes and subclasses.
- *Dynamic configuration* using a unique approach we call "class families" - for example, the names of the commands are properties of the command classes, not in a big "if" statement.
- *Extensive testing* with >90% test coverage, guaranteed by CI.
- *Leverage the standard library* by requiring 3rd party PIP modules for development, but not for usage.
To set everything up:
```
sudo pip3 install vernum coverage pycodestyle twine
```
To get the full repo:
```
git clone git@gitlab.com:fpotter/tools/busy.git
```
We use Visual Studio Code to build Busy, so there is a VS Code configuration file in the repository.
Then to run the test suite:
```
make test
```
Or to run test coverage:
```
make cover
```
And to check style:
```
make style
```
_Note to self: To publish a new build, use 'vernum' with 'major', 'minor', or 'patch' depending on how major the changes were since the last build. Then push. GitLab allows you to publish to PyPI in its UI, and only when Vernum has been run._
Command summary
===============
Below is a reference list of all commands, handy to correlate the one-letter version with the full version. The one-letter version is used in the curses UI, and is an alternative option in the shell UI. Some of the listed commands are yet to be implemented; they are listed here merely to reserve their names.
| Short | Full |
| --- | --- |
| a | add |
| c | activate |
| d | delete |
| e | edit |
| f | defer |
| l | list |
| m | manage |
| n | finish |
| p | pop |
| q | quit (only in interactive UI) |
| r | drop |
| s | shuffle |
| t | tags |
| u | queues (list) |
| w | switch (queues) |
| | curses (only in shell UI) |
| | top |