Skip to content
This repository has been archived by the owner on May 11, 2021. It is now read-only.

Latest commit

 

History

History
373 lines (346 loc) · 28.7 KB

TODO.org

File metadata and controls

373 lines (346 loc) · 28.7 KB

The Chronometrist TODO List

  1. [-] Move time operations into a chronometrist-time file
  2. -report - highlight the current day

v0.3.0 [100%]

  1. [X] Release or bundle plist-pp.el
  2. [X] -report - error opening when clocked in

Chronometrist

  1. implement point restore for chronometrist=/=chronometrist-report=/=chronometrist-statistics in a kill-buffer-hook, so it works whenever the buffer is killed, not just when we call the command.

Bugs [57%]

  1. [X] fix -current-task to return correct results if the last one crosses a midnight
  2. [ ] Clocking-in/out doesn’t result in updated display, sometimes (2019-09-12)
  3. [ ] Sorting by clicking the columns makes non-tabular data disappear
    • Advise tabulated-list-col-sort to run either chronometrist-refresh or the relevant -print-non-tabular afterwards
  4. [X] kv-accept with no key values should not modify file
  5. [ ] kv-add and tags-add should not remove other keys from last sexp
  6. [X] kv-accept with no key values -> Chronometrist buffer not updated
    • timer will only refresh when clocked in…
  7. [X] regression - no value history
  8. [ ] Possible to add the same key-value twice
    • Clock in, clock out, add key-value and accept, delete :stop time and save, clock out again, accept the already-inserted key-value - duplicate!

Features [25%]

  1. [ ] Create chronometrist-unused-projects-list + chronometrist-projects-list.
  2. [ ] New commands
    1. [ ] Kill/discard (bind to ‘k’) - which will delete the interval currently being recorded.
      • Most conservative option - it will only operate on the project at point, and will only kill for a clocked-in project.
      • Somewhat less conservative option - it will operate on the currently clocked-in project, no matter where point is.
      • It should ask for confirmation.
      • Alternatively, or as a complement - an undo command, which will undo your last action (clock in or clock out).
        • Undo and redo seem like the best bets.
  3. [ ] Hook enhancement - can we supply the whole plist (including tags and key-values) to the task-start hooks, so users can have even smarter hook functions?
    • That would mean ensuring that -kv-read runs before other hooks.
    • Actually, it should be trivial to access the last expression in the file, so maybe this is unnecessary.
  4. [X] Revisit ‘no reason’ commands - maybe we should ask for tags and key-values with the regular commands, and skip them with the ‘no reason’ variants?

Key-values [66%]

  1. [X] bug - value-history appears in chronological rather than reverse chronological order
  2. [X] generate history hash table from chronometrist-file.
    • [X] generate value history hash table from chronometrist-file
    • [X] change “press X to quit” in prompt to suggest keys for ido, helm, and ivy
  3. [ ] create text button to add key-values to last entry (whether clocked in or out)
  4. [X] insert value as string if it contains spaces and isn’t a list
    • Sometimes you want single-word values to be converted to a string, too. Maybe check for capital letters too?
    • Preserve type in history?
      • Might create inconsistency in prompts? We don’t want to expect Lisp knowledge from users.
    • Ask user to define types for keys, and handle the syntax for them behind the scenes?
  5. [ ] when reading values, add quit keybinding (consistent with output of chronometrist-kv-completion-quit-key) by passing MAP to read-from-minibuffer
  6. [X] bug - missing values in history
  7. [X] enh - remove key-values from suggestions which have already been added
  8. [ ] enh - create custom variable to auto-insert key-values used in previous task of same :name in the key-value buffer.
  9. [X] bug - incorrect indenting in -kv-buffer
  10. [X] bug - I think -append-to-last-expr is eating key-values
    • to reproduce - clock-in, add tags, add key-values, clock-out, keep tags - kv-add buffer has (), whereas it should have the earlier key-values.
  11. bug - key-values from clock-in expression not displayed, shows () instead
    • cause - if -kv-add is run after chronometrist-out, chronometrist-current-task will return nil
  12. [ ] observe interaction of -kv-add with next function in hook which modifies window configuration
    • code which deletes the window, or switches to a new buffer, interferes with the key-value addition flow
    • [ ] add a kv-finished-hook? (run after kv-accept/reject)
  13. how do we handle a blank string as a plist value?
    • some way to require the user to enter a non-empty value (e.g. like the ‘require-match’ argument to completing-read, except read-from-minibuffer doesn’t have that…)
    • discard last-entered key?
  14. optimize - going through key (?) and value histories (M-p/M-n) takes a while. Is this because we’re using lists?
    • It doesn’t, it’s the delay from the hash table update from the fs watch
  15. [X] bug - tag history starts at the beginning (wtf?), value history is empty (wtf?)
    • Does not occur on master, only on dev
    • Does not occur if you disable lexical binding (introduced in 4e89836)

Values

What forms can they take?

  1. Integers, floating point numbers - easy to identify via regexp
  2. If it starts and ends with “(” and “)” or “[” and “]”, it’s a list or a vector
  3. otherwise - string

Observations

  • This means you can’t enter symbols via prompt. Can be added if the demand is there…
  • This also means you can’t have multiple atom values for a keyword…but that’s irrelevant, because plists can’t have multiple values anyway. :)

Tags [100%]

  1. [X] generate history from chronometrist-file
    • [X] narrow it down to the :name
  2. [X] write tags to last expression
  3. [X] show task name in prompt
  4. [X] bug - tags being added twice

Code [28%]

  1. [-] Write tests (in buttercup)
  2. refactor repetitive calls to (format “%04d-%02d-%02d” (elt seq a) (elt seq b) (elt seq c))
  3. See if it is possible to store buttons in a variable, so *-print-non-tabular functions can be made shorter and less imperative. (see make-text-button)
  4. Merge all event-querying functions so that they always operate on an entire hash table (so no ‘day’ variants),
  5. [ ] Use substitute-command-keys instead of chronometrist-format-keybinds
  6. [ ] recreate -events-clean, remove splitting code from -events-populate
    • How should we deal with the active event?
      • Earlier, we would add a closing entry and update that on a timer.
  7. [ ] Make docstrings consistent - describe inputs and then the return value, in that order.
  8. [ ] chronometrist-seconds->alert-string can probably be replaced by org-duration-from-minutes - read the format for FMT
  9. [X] Decouple storage-related code from rest of the program.
  10. [X] See if using iteration constructs (especially loop) can lead to nicer code than nested maps

1. use variables instead of hardcoded numbers to determine spacing

  • Don’t see the benefit

6. Timeclock already _has_ hooks! :| Why do we re-implement them?

  • I don’t know of a way to know the project being clocked into using timeclock hooks.
  • With v0.2.0 Chronometrist also has a before-project-stop-functions, which runs before the project is stopped, and can control whether the project actually is stopped.

Maybe

  1. Add a new kind of plist - (:name "NAME" :time "TIME" ...) To record events for which the time interval is not relevant. These won’t be shown in chronometrist - perhaps in a different buffer.

Optimization [33%]

Some options and ideas -

  1. [X] Defer (tag/key/value) history generation from file-change-time to prompt-time, and make it per-task instead of all tasks at once
    • The biggest resource hog is splitting of midnight-spanning intervals, however.
    • Reduce memory use by allowing user to restrict number of s-expressions read.
    • Per-task history generation will create problems - e.g. values for a given key for one task won’t be suggested for values for the same key in another 🤦
      • Tags and keys are already task-sensitive; just don’t make values task-sensitive.
  2. [X] Compare partial hashes of file to know what has changed - only update memory when necessary.
  3. [ ] In-memory cache - don’t store entire file into memory; instead, split midnight-spanning intervals just for the requested data.
    • Will increase load time for the first time chronometrist, chronometrist-report, or chronometrist-statistics are run (including forward/backward commands in the latter two)
      • Can try pre-emptively loading data for the latter two
    • Will reduce memory used by chronometrist-events.
      • Further reductions can take place, if we automatically discard cache entries past a certain limit. (perhaps excluding data for the current day, week, or month)
  4. [ ] Mix of 2 and 3 - in-memory cache with partial updates
  5. [ ] Split and save midnight-spanning intervals to disk - remove the need for an in-memory version of data with split midnight-spanning intervals.
    • Least memory use?
    • Might make the file harder for a user to edit.
  6. [ ] Save timestamps as UNIX epoch time.
    • Will (probably) greatly speed up time parsing and interval splitting.
    • Will greatly impede human editing of the file, too. 🤔
      • An editing UI could help - pretty sure every timestamp edit I’ve ever made has been for the last interval, or at most an interval in today’s data.
  7. [ ] Use an SQL database instead of a text file. Assuming SQL can
    1. find the difference between ISO-8601 timestamps
    2. compare ISO-8601 timestamps, and
    3. do 1 and 2 faster than Elisp.
  8. [ ] Change data structure - instead of storing each plist as-is, split each into two, one with the :start and one with the :end. Now we have the elegance of the one-plist-is-a-complete-interval schema in the file, and the ease and speed of detection of midnight spanning intervals in memory.

    So this

    (:name "Task" ... :start "<timestamp>" :stop "<timestamp>")
        

    is stored in hash table values as

    ((:name "Task" ... :start "<timestamp>")
     (:stop "<timestamp>")
     ...)
        
  9. [ ] Change file timestamp format to ("<iso-date>" "<iso-time>")

Cache

  • Lessons from the parsimonious-reading branch - iterating read over the whole file is fast; splitting the intervals is not.
  • Things we need to read the whole file for - task list, tag/key/value history.
  • Fill chronometrist-events only as much as the buffer needing split intervals requires. e.g. for chronometrist, just a day; for chronometrist-report, a week; etc.
  • Anything requiring split intervals will first look in chronometrist-events, and if not found, will read from the file and update chronometrist-events.
  • When the file changes, use the file byte length and hash strategy described below to know whether to keep the cache.
  • Save cache to a file, so that event splitting is avoided by reading from that.

Ideas to make -refresh-file faster

  1. Support multiple files, so we read and process lesser data when one of them changes.
  2. Make file writing async
  3. Don’t refresh from file when clocking in.
  4. Only write to the file when Emacs is idle or being killed, and store data in memory (in the intervals hash table) in the meantime
  5. What if commands both write to the file and add to the hash table, so we don’t have to re-read the file and re-populate the table for commands? The expensive reading+parsing could be avoided for commands, and only take place for the user changing the file.
    • [X] jonasw - store length and hash of previous file, see if the new file has the same hash until old-length bytes.
      • Rather than storing and hashing the full length, we could do it until (before) the last s-expression (or last N s-expressions?). That way, we know if the last expression (or last N expressions) have changed.
        • Or even the first expression of the current date. That way, we just re-read the intervals for today. Because chronometrist-events uses dates as keys, it’s easy to work on the basis of dates.
  6. [ ] Don’t generate tag/keyword/value history from the entire log, just from the last N days (where N is user-customizable).
  7. [ ] Just why are we reading the whole file? chronometrist should not read more than a day; chronometrist-report should not read more than a week at a time, and so on. Make a branch which works on this logic, see if it is faster.

Certain [0%]

plist-pp [66%]

pp.el doesn’t align plist keys along the same column. ppp.el doesn’t align plist values along the same column. It’s also GPL, and I’m trying to cut down GPL dependencies.

  1. [X] plist-pp - work recursively for plist/alist values
  2. [ ] Fix alignment of alist dots
    • While also handling alist members which are proper lists
  3. [X] Add variable (to chronometrist-sexp.el) to set pretty-printing function. Default to ppp.el if found, fallback to internal Emacs pretty printer, and let users set their own pretty printing function.

Bugs [33%]

  1. [ ] With tags and key-value query functions in before-out-functions, clock in Task A -> clock in Task B -> prompted for tags and key values for Task A, add some -> they get added to Task B 😱
  2. [ ] I clocked into a task -
    (:name  "Arrangement/new edition"
     :tags  (new edition)
     :start "2020-08-17T00:33:24+0530")
        

    I added some key values to it. What it should have looked like -

    (:name     "Arrangement/new edition"
     :tags     (new edition)
     :composer "Schubert, Franz"
     :song     "Die schöne Müllerin"
     :start    "2020-08-17T00:33:24+0530"
     :stop     "2020-08-17T01:22:40+0530")
        

    What it actually looked like -

    (:name     "Arrangement/new edition"
     :tags     (new edition)
     :composer "Schubert, Franz"
     :song     "Die schöne Müllerin"
     :start    "2020-08-17T00:33:24+0530"
    ...)
        

    And of course, that results in an error trying to process it.

  3. [X] When you enter a list containing a string - e.g.
    ("foo" (1 . "bar"))
        

    as a value, when suggested in the history it is presented rather differently -

    (foo (1 . bar))
        

    Yikes!

  4. [ ] Midnight spanning intervals currently display the full time when clocked out. e.g. this…
    (:name      "Programming"
     :start     "2020-12-22T23:01:00+0530"
     :stop      "2020-12-23T00:54:52+0530")
        

    …is displayed as 1:53:52 (rather than 00:54:52) after clocking out. :\

chronometrist [6%]

  1. [ ] Add :stop time when we call chronometrist-kv-accept, not when we quit the key-value prompt with a blank input.
    • It might be nice to be able to quit chronometrist-kv-add with C-g instead, actually.
      • C-g stops execution of chronometrist-run-functions-and-clock-in=/=chronometrist-run-functions-and-clock-out, so they can’t reach the calls for chronometrist-in=/=chronometrist-out.

        We can make the clock-in/out happen in an unwind-protect, but that means clock-in/out always takes place, e.g. even when a function asks if you’d really like to clock out (like the Magit commit prompt example does), and you respond with “no”.

        • What if we call chronometrist-before-out-functions with run-hook-with-args like all other hooks, so it runs all functions unconditionally and any function wishing to abort clocking in/out can use catch/throw?

          chronometrist-kv-add could quit nonlocally when the user enters a blank input (or hits C-g? Maybe by using unwind-protect?), cancelling the clock in/out, and thereby letting chronometrist-kv-accept resume clock in/out. (It can determine whether to clock in or out using chronometrist-current-task)

  2. [ ] Implement undo/redo by running undo-tree commands on chronometrist.sexp
    • [ ] Possibly show what changes would be made, and prompt the user to confirm it.
    • How will this work with the SQLite backend? Rollbacks?
    • It might be easier to just have a ‘remove last interval’ (the operation I use undo for most often), so we don’t reimplement an undo for SQLite.
  3. [X] Enhanced tag/key-value prompt - before asking for tags/key-values, if the last occurence of task had tags/key-values, ask if they should be reused. y - yes, n - no (continue to usual prompts).
    • [X] Show what those tags/key-values are, so the user knows what will be added.
  4. [ ] “Explain” command - show intervals for task today
    • [ ] Switch between intervals and tag-combination breakdown
  5. [ ] Magit/other VCS integration
    • [ ] Add support for using key-values to point to a commit (commit hash + repo path?)
      • Need some way to extend the key-value prompt, so we can provide completion for commit hashes + commit messages…
    • [ ] Add command to open the commit associated with the interval in Magit
    • [ ] Make a user-customizable alist of project names and repo locations (local or remote), so shorter project names can be used instead of repo locations, saving space and reducing duplication.
  6. [ ] key-values - make detection of Lisp values more robust.
    • If the input string can be read in a single call to read, treat it as an s-expression; else, use the current heuristics.
  7. [ ] key-values - create transformer for key-values, to be run before they are added to the file. This will allow users to do cool things like sorting the key-values.
  8. [ ] Convert current interval - change the :name of the currently clocked-in interval. Tags and key-values may be re-queried. Clock-in hook functions will be run again with the new task as the argument.
  9. [ ] Rename a project (updating all records)
  10. [ ] Delete a project (erasing all records)
  11. [ ] Hide a project (don’t show it in any Chronometrist-* buffer, effectively deleting it non-destructively)
  12. [ ] Reset current interval - update the :start time to the current time.
  13. [ ] Alternative query function for tags and key-values - a single query. Either with tags and key-values as a single plist, or something like the multi-field query-replace prompt.
  14. [ ] Customizable field widths
  15. [ ] Ask existing users if they’d like to have a prop line added to chronometrist-file
    • check if chronometrist-sexp-mode is active in the buffer
    • offer to never ask again

chronometrist-report [0%]

  1. [ ] Show week counter and max weeks; don’t scroll past first/last weeks
  2. [ ] Highlight column of current day
  3. [ ] Command to narrow report to specific project(s)
  4. [ ] Jump to beginning/end of data (keys B/F)
  5. [ ] “Explain” command - show tag-combination-based breakdown

Code quality [25%]

  1. [ ] Remove duplication between chronometrist-toggle-task and chronometrist-toggle-task-button
  2. [ ] Make functions more test-friendly. Quite a few can get away with returning values instead of writing to a file - this will make it easier to test them. Other functions can handle the file operations for them.
  3. [ ] Rewrite using cl-loop
    1. [ ] chronometrist-statistics-entries-internal
    2. [ ] chronometrist-statistics-count-active-days
  4. [ ] Write integration tests using ecukes.
    1. Some feature definitions already exist in features/, write step definitions for them.
  5. [X] Remove duplication - the three chronometrist-*-history-populate functions
  6. [ ] Remove duplication - extracting user key-values from a plist seems to be a common operation.
  7. [X] Extensions - redesign chronometrist such that it does not need to check for the availability of extensions (such as chronometrist-goal)
    • Could make two “transformer lists” - chronometrist-list-format-transformers and chronometrist-entry-transformers.

      The former would be called before tabulated-list-format is set. The latter would be called by chronometrist-entries, with each individual entry as an argument.

      chronometrist-goal will simply added a function to each of those.

    • Actually, are transformers really necessary? It could be done with a function inserted by chronometrist-goal into chronometrist-mode-hook. The function itself would become a little more complex, but it would remove the two transformer lists + the call-transformers dependency from the code. chronometrist-mode-hook is required either way, to set up chronometrist-goal.
      • Turns out, they are. We set tabulated-list-entries to a function. To modify the value, we must hook into that function in some way. tabulated-list-format could be modified in a regular hook, but it feels more consistent to make it a transformer too 🤔
  8. [ ] Ugly code - chronometrist-print-non-tabular; insert-text-button can be replaced with make-text-button

Documentation [0%]

  1. [ ] Move usage and customization sections to manual.org (The user may not see the README, if they are installing from MELPA.)
    1. [ ] convert README to Org
    2. [ ] transclude these sections from the manual to the readme
  2. [ ] Make Texinfo documentation
    • [ ] setup auto-export of Org to texinfo - git pre-commit hook?
  3. [ ] Link identifiers in manual.org to the source.
    • [ ] For HTML export, link to GitHub using line number anchors.
    • [ ] Try to make describe-function/helpful-at-point work with Org inline code syntax. Then we won’t need to make links.
      • Incidentally, a link like [[elisp:(describe-function 'file-notify-add-watch)][file-notify-add-watch]]
        1. if opened from an Org buffer, shows the return value in the echo area, which is ugly
        2. is exported to Info as
          ‘file-notify-add-watch’ ((describe-function 'file-notify-add-watch))
                          

          …yuck :\

    • Currently using file: links with text search - [file:../elisp/file.el::defun identifier (], [file:../elisp/file.el::defvar identifier (], etc.
  4. [ ] Fix heading link to “midnight-spanning intervals” - jumps to the correct heading in HTML export, but jumps to its own self in Org mode.
  5. [ ] Figure out some way to hide package prefixes in identifiers in Org mode (without actually affecting the contents, a la nameless-mode)

UX [30%]

  1. [X] Optimization - (jonasw) store length and hash of previous file, see if the new file has the same hash until old-length bytes.
    • [X] Check for type of change to file
      • [X] Handle last expression being removed
    • [X] Implement optimized operations
    • [X] BUG - if something was removed from the last expression (thereby decreasing the length of the file), chronometrist-file-change-type returns t instead of :last
    • [X] BUG - args out of range error when last plist is removed
  2. [X] Optimization - generate history before querying, not when the file changes.
  3. [ ] Don’t suggest nil when asking for first project on first run
  4. [ ] When starting a project with time of “-” (i.e. not worked on today until now), immediately set time to 0 instead of waiting for the first timer refresh
  5. [ ] Mouse commands should work only on buttons.
  6. [X] Button actions should accept prefix arguments and behave exactly like their keyboard counterparts.
  7. [ ] mouse-3 should clock-out without asking for reason.
  8. [ ] Some way to ask for the reason just before starting a project. Even when clocking out, the reason is asked before clocking out, which adds time to the project.
  9. [ ] Allow calling chronometrist-in/out from anywhere-within-Emacs (a la timeclock) as well as from the chronometrist buffer.
  10. [ ] chronometrist-timer - if chronometrist-file is being edited (buffer exists and modified), don’t refresh - this will (hopefully) prevent Emacs from going crazy with errors in trying to parse malformed data.

Maybe [0%]

New features [0%]

  1. [ ] Some way to use markup (Markdown, Org, etc) for certain plist values.

    Implementation ideas -

    • A list of keys whose values are to be edited in a user-specified major mode.
      • Multiple windows - instead of a single key-value buffer, we’ll have multiple buffers in multiple visible windows. The accept command will use the data from all involved buffers.
        • The buffer and window will be created when a key associated with that mode is selected at the prompt.
      • Alternatively, the whole plist goes into a single buffer of the markup’s major mode - the markup bits as markup, the rest of the plist in a code block 🤷‍
    • “Input frontends” - a way to represent s-expressions as Markdown, Org, etc, so the entire plist can be edited in that mode. As a side-effect, this will permit use of Markdown, Org, etc in keyword-values - e.g. to use markup in comments or notes.
    • A binding in the key-value buffer, which will insert the string at point in a buffer of a certain mode.
  2. [ ] A custom variable containing a list of tasks
    ("A Task Name"
     ("Another Task Name" :key-prompt nil)
     ...)
        

    Elements can be

    1. the task name as a string
    2. a list, with the first element being the task name as a string, followed by keyword-value pairs

    Keywords can be

    1. =:tag-prompt=, =:key-prompt= - values can be nil, t (the default), or a function. If nil, don’t ask for tags/keys for this task. If t, ask for tags/keys for this task using =chronometrist-tags-add=/=chronometrist-key-add=. If it’s a function, use that as the prompt.
      • Tags and key-values are optional extensions; we don’t want Chronometrist to know about them.
        • Well, even with this style of configuration, Chronometrist doesn’t necessarily have to…it could use the fields it knows about, ignoring the rest; the extensions could check for the fields they know about.
      • Instead of setting the prompt function, set hooks (chronometrist-before-in-functions=/=chronometrist-after-in-functions=/=chronometrist-before-out-functions=/=chronometrist-after-out-functions) per-task. This is preferable, because if you define a custom prompt function, you probably also want to remove certain functions coming earlier in the hook, such as chronometrist-skip-query-prompt, for that task.
    2. :hide - values can be nil (the default) or t - if t, hide this task from being displayed in chronometrist=/=chronometrist-report=/=chronometrist-statistics buffers. (effectively a non-destructive deletion of all intervals of the task)

    Useful for

    1. Adding tasks without clocking into them (the list is stored in a separate file)
    2. Not asking for tags and/or key-values for a particular task, or having a special behaviour for a task. (e.g. some tasks I use follow certain patterns, which I’d like to automate away)
  3. [ ] Completion for sub-plists - if the value of a user keyword-value pair is a plist (heuristic - list with keyword as first element), can we reuse the keyword-value prompt for it? 🤔
    • Maybe generate the completion hash table when the plist is created, since this is likely to be less-used.
  4. [ ] Create a debug mode
  5. [ ] Create a verification command to test chronometrist-file for errors.

plist-pp

  1. Represent sublists by depth (integer) instead of a boolean.

UX [0%]

  1. [ ] Provide a command which tries to auto-configure Chronometrist keys in a way which is consistent with the user’s other keymaps.
  2. [ ] Do basic checks on values of all customizable variables when they are changed by the user, and provide meaningful errors if they can’t be used by the program.
  3. [ ] Task-sensitive value suggestions - if you use the key :key for two different tasks, and don’t want the values for :key in one task being suggested for :key in another…
    • The problem is that sometimes you do want that, and changing it can lead to duplication of user effort.
    • Maybe make it a switch, enabled by default.
    • …or a list of keys to exclude from task-sensitivity?
      • So chronometrist-value-history will have ("task" . "key") as hash key and ("value" ...) as hash value. Keys which are present in the ‘blacklist’ are stored the same way as now - "key" as hash key, ("value" ...) as hash value.
    • Can we figure it out automatically, without requiring configuration? 🤔
    • Maybe suggest values for the current task first, and only after that for other tasks? Solves the problem of ‘mixed up’ value histories, removes the need for a switch to turn it off/have the user configure a blacklist of keys…
  4. [ ] Tag-sensitive key suggestions, tag-sensitive value suggestions…?
    • Might complicate things quite a bit.
    • Lack of task-sensitive value suggestions (#3) is an inconsistency, because tags and keys are already task-sensitive. From that perspective, tag-sensitive key and value suggestions are a whole new can of worms.
  5. Change precision of timestamps from seconds to minutes. (like Org)

chronometrist-report [0%]

  1. [ ] Add support for other locale weeks/weekday names

chronometrist-goals [0%]

  1. [ ] Colorize times in Chronometrist buffer
    • untouched project with target defined - red
    • target ±5 minutes - green
    • target*2 and above - red