Merge branch 'dev' into sql

This commit is contained in:
contrapunctus 2020-11-26 02:09:59 +05:30
commit e183e463cd
11 changed files with 147 additions and 204 deletions

View File

@ -171,7 +171,18 @@ ppp.el doesn't align plist values along the same column. It's also GPL, and I'm
: (foo (1 . bar))
Yikes!
** chronometrist [7%]
** New features [0%]
1. [ ] 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.
2. [ ] *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.
3. [ ] *Rename* a project (updating all records)
4. [ ] *Delete* a project (erasing all records)
5. [ ] *Hide* a project (don't show it in any Chronometrist-* buffer, effectively deleting it non-destructively)
6. [ ] *Reset* current interval - update the =:start= time to the current time.
** chronometrist [16%]
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=.
@ -180,28 +191,19 @@ ppp.el doesn't align plist values along the same column. It's also GPL, and I'm
- 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?
* 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. [ ] *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.
4. [ ] *Rename* a project (updating all records)
5. [ ] *Delete* a project (erasing all records)
6. [ ] *Hide* a project (don't show it in any Chronometrist-* buffer, effectively deleting it non-destructively)
7. [ ] *Reset* current interval - update the =:start= time to the current time.
8. [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).
2. [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.
9. [ ] Expandable items - show intervals for task today
3. [ ] Expandable items - show intervals for task today
* [ ] Switch between intervals and tag-combination breakdown
10. [ ] Magit 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.
11. [ ] Pretty printer - add support for alists as values
12. [ ] 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.
13. [ ] key-values - create transformer for key-values, to be run before they are added to the file. This will allow users to do things like sorting the key-values.
4. [ ] 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.
5. [ ] 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.
6. [ ] 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.
*** Migration [0%]
1. [ ] Implement readers (format -> hash table), emitters (hash table -> format), and predicates for each format. Then implement a single =migrate= command to convert between any supported formats.
* sounds like a job for EIEIO - each format could be defined as an object, with slots for information such as the file extension.
@ -209,6 +211,7 @@ ppp.el doesn't align plist values along the same column. It's also GPL, and I'm
3. [ ] Make migration asynchronous, and use output from the sub-process to make a progress indicator.
4. [ ] Optimization - (SQL) read all keywords once, remove duplicates, and create columns for them, instead of checking =pragma= for each plist.
5. [ ] (SQL) Use transactions.
** chronometrist-report [0%]
1. [ ] Show week counter and max weeks; don't scroll past first/last weeks
2. [ ] Highlight column of current day
@ -220,8 +223,8 @@ ppp.el doesn't align plist values along the same column. It's also GPL, and I'm
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
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. [ ] Remove duplication - the three =chronometrist-*-history-populate= functions seem to have a common pattern of iterating over each hash value (a list of plists) in =chronometrist-events=, and over each element of that list.
@ -268,26 +271,36 @@ ppp.el doesn't align plist values along the same column. It's also GPL, and I'm
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.
* "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
#+BEGIN_SRC
("A Task Name"
("Another Task Name" :key-prompt nil)
...)
#+END_SRC
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.
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.
** plist-pp
1. Represent sublists by depth (integer) instead of a boolean.
** a task list
#+BEGIN_SRC
("A Task"
("Another Task" :key-prompt nil))
#+END_SRC
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, or a function. If nil, don't ask for tags/keys for this task. If t (the default), ask for tags/keys for this task using =chronometrist-tags-add=/=chronometrist-key-add=. If it's a function, use that as the prompt.
...
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)
** 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.
@ -301,8 +314,6 @@ Useful for
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. 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? Currently such sub-plists don't get any completion 🤔
* Maybe generate the completion hash table when the plist is created, since this is likely to be less-used.
6. Change precision of timestamps from seconds to minutes. (like Org)
** chronometrist-report [0%]

View File

@ -18,8 +18,6 @@
(require 'cl-lib)
(require 'ts)
(require 'chronometrist-custom)
(require 'chronometrist-report-custom)
(require 'chronometrist-time)
(require 'chronometrist-sexp)

View File

@ -1,78 +0,0 @@
;;; chronometrist-custom.el --- Custom definitions for Chronometrist -*- lexical-binding: t; -*-
;; Author: contrapunctus <xmpp:contrapunctus@jabber.fr>
;; This is free and unencumbered software released into the public domain.
;;
;; Anyone is free to copy, modify, publish, use, compile, sell, or
;; distribute this software, either in source code form or as a compiled
;; binary, for any purpose, commercial or non-commercial, and by any
;; means.
;;
;; For more information, please refer to <https://unlicense.org>
;;; Commentary:
;;
;;; Code:
(defgroup chronometrist nil
"A time tracker with a nice UI."
:group 'applications)
(defcustom chronometrist-file
(locate-user-emacs-file "chronometrist")
"Default path and name of the Chronometrist database, without an extension.
It should be a text file containing plists in the form -
\(:name \"task name\"
[:tags TAGS]
[:comment \"comment\"]
[KEY-VALUE-PAIR ...]
:start \"TIME\"
:stop \"TIME\"\)
Where -
TAGS is a list. It can contain any strings and symbols.
KEY-VALUE-PAIR can be any keyword-value pairs. Currently,
Chronometrist ignores them.
TIME must be an ISO-8601 time string.
\(The square brackets here refer to optional elements, not
vectors.\)"
:type 'file)
(defcustom chronometrist-buffer-name "*Chronometrist*"
"The name of the buffer created by `chronometrist'."
:type 'string)
(defcustom chronometrist-hide-cursor nil
"If non-nil, hide the cursor and only highlight the current line in the `chronometrist' buffer."
:type 'boolean)
(defcustom chronometrist-update-interval 5
"How often the `chronometrist' buffer should be updated, in seconds.
This is not guaranteed to be accurate - see (info \"(elisp)Timers\")."
:type 'integer)
(eval-when-compile (require 'subr-x))
(defcustom chronometrist-activity-indicator "*"
"How to indicate that a task is active.
Can be a string to be displayed, or a function which returns this string.
The default is \"*\""
:type '(choice string function))
(defcustom chronometrist-day-start-time "00:00:00"
"The time at which a day is considered to start, in \"HH:MM:SS\".
The default is midnight, i.e. \"00:00:00\"."
:type 'string)
(provide 'chronometrist-custom)
;;; chronometrist-custom.el ends here

View File

@ -1,44 +0,0 @@
;;; chronometrist-report-custom --- custom definitions for `chronometrist-report' -*- lexical-binding: t; -*-
;; Author: contrapunctus <xmpp:contrapunctus@jabber.fr>
;; This is free and unencumbered software released into the public domain.
;;
;; Anyone is free to copy, modify, publish, use, compile, sell, or
;; distribute this software, either in source code form or as a compiled
;; binary, for any purpose, commercial or non-commercial, and by any
;; means.
;;
;; For more information, please refer to <https://unlicense.org>
;;; Commentary:
;;
;;; Code:
(defgroup chronometrist-report nil
"Weekly report for the `chronometrist' time tracker."
:group 'chronometrist)
(defcustom chronometrist-report-buffer-name "*Chronometrist-Report*"
"The name of the buffer created by `chronometrist-report'."
:type 'string)
(defcustom chronometrist-report-week-start-day "Sunday"
"The day used for start of week by `chronometrist-report'."
:type 'string)
(defcustom chronometrist-report-weekday-number-alist
'(("Sunday" . 0)
("Monday" . 1)
("Tuesday" . 2)
("Wednesday" . 3)
("Thursday" . 4)
("Friday" . 5)
("Saturday" . 6))
"Alist in the form (\"NAME\" . NUMBER), where \"NAME\" is the name of a weekday and NUMBER its associated number."
:type 'alist)
(provide 'chronometrist-report-custom)
;;; chronometrist-report-custom.el ends here

View File

@ -19,7 +19,6 @@
(require 'chronometrist-common)
(require 'chronometrist-queries)
(require 'chronometrist-timer)
(require 'chronometrist-report-custom)
(require 'chronometrist-migrate)
(declare-function chronometrist-refresh-file "chronometrist.el")
@ -36,6 +35,29 @@
;;; Code:
(defgroup chronometrist-report nil
"Weekly report for the `chronometrist' time tracker."
:group 'chronometrist)
(defcustom chronometrist-report-buffer-name "*Chronometrist-Report*"
"The name of the buffer created by `chronometrist-report'."
:type 'string)
(defcustom chronometrist-report-week-start-day "Sunday"
"The day used for start of week by `chronometrist-report'."
:type 'string)
(defcustom chronometrist-report-weekday-number-alist
'(("Sunday" . 0)
("Monday" . 1)
("Tuesday" . 2)
("Wednesday" . 3)
("Thursday" . 4)
("Friday" . 5)
("Saturday" . 6))
"Alist in the form (\"NAME\" . NUMBER), where \"NAME\" is the name of a weekday and NUMBER its associated number."
:type 'alist)
(defvar chronometrist-report--ui-date nil
"The first date of the week displayed by `chronometrist-report'.
A value of nil means the current week. Otherwise, it must be a

View File

@ -3,9 +3,12 @@
;;; Commentary:
;;
<<<<<<< HEAD
(require 'chronometrist-backend)
(require 'chronometrist-custom)
=======
>>>>>>> dev
;;; Code:
;; chronometrist-file (-custom)

View File

@ -1,29 +0,0 @@
;;; chronometrist-statistics-custom.el --- Custom definitions for chronometrist-statistics -*- lexical-binding: t; -*-
;; Author: contrapunctus <xmpp:contrapunctus@jabber.fr>
;; This is free and unencumbered software released into the public domain.
;;
;; Anyone is free to copy, modify, publish, use, compile, sell, or
;; distribute this software, either in source code form or as a compiled
;; binary, for any purpose, commercial or non-commercial, and by any
;; means.
;;
;; For more information, please refer to <https://unlicense.org>
;;; Commentary:
;;
;;; Code:
(defgroup chronometrist-statistics nil
"Statistics buffer for the `chronometrist' time tracker."
:group 'chronometrist)
(defcustom chronometrist-statistics-buffer-name "*Chronometrist-Statistics*"
"The name of the buffer created by `chronometrist-statistics'."
:type 'string)
(provide 'chronometrist-statistics-custom)
;;; chronometrist-statistics-custom.el ends here

View File

@ -22,7 +22,6 @@
(require 'chronometrist-time)
(require 'chronometrist-timer)
(require 'chronometrist-events)
(require 'chronometrist-statistics-custom)
(require 'chronometrist-migrate)
(require 'chronometrist-queries)
@ -59,6 +58,14 @@
;; ## VARIABLES ##
(defgroup chronometrist-statistics nil
"Statistics buffer for the `chronometrist' time tracker."
:group 'chronometrist)
(defcustom chronometrist-statistics-buffer-name "*Chronometrist-Statistics*"
"The name of the buffer created by `chronometrist-statistics'."
:type 'string)
(defvar chronometrist-statistics--ui-state nil
"Stores the display state for `chronometrist-statistics'.

View File

@ -5,7 +5,6 @@
(require 'parse-time)
(require 'dash)
(require 's)
(require 'chronometrist-report-custom)
(declare-function chronometrist-day-start "chronometrist-events.el")

View File

@ -15,9 +15,6 @@
;;
;;; Code:
(require 'chronometrist-custom)
(require 'chronometrist-statistics-custom)
(require 'chronometrist-report-custom)
(require 'chronometrist)
(declare-function chronometrist-refresh "chronometrist.el")

View File

@ -19,7 +19,6 @@
(require 'run-transformers)
(require 'chronometrist-common)
(require 'chronometrist-custom)
(require 'chronometrist-key-values)
(require 'chronometrist-queries)
(require 'chronometrist-migrate)
@ -72,12 +71,70 @@
;; For information on usage and customization, see https://github.com/contrapunctus-1/chronometrist/blob/master/README.md
;;; Code:
(eval-when-compile (defvar chronometrist-mode-map))
(eval-when-compile
(defvar chronometrist-mode-map)
(require 'subr-x))
(autoload 'chronometrist-maybe-start-timer "chronometrist-timer" nil t)
(autoload 'chronometrist-report "chronometrist-report" nil t)
(autoload 'chronometrist-statistics "chronometrist-statistics" nil t)
;; ## VARIABLES ##
(defgroup chronometrist nil
"A time tracker with a nice UI."
:group 'applications)
(defcustom chronometrist-file
(locate-user-emacs-file "chronometrist.sexp")
"Default path and name of the Chronometrist database.
It should be a text file containing plists in the form -
\(:name \"task name\"
[:tags TAGS]
[:comment \"comment\"]
[KEY-VALUE-PAIR ...]
:start \"TIME\"
:stop \"TIME\"\)
Where -
TAGS is a list. It can contain any strings and symbols.
KEY-VALUE-PAIR can be any keyword-value pairs. Currently,
Chronometrist ignores them.
TIME must be an ISO-8601 time string.
\(The square brackets here refer to optional elements, not
vectors.\)"
:type 'file)
(defcustom chronometrist-buffer-name "*Chronometrist*"
"The name of the buffer created by `chronometrist'."
:type 'string)
(defcustom chronometrist-hide-cursor nil
"If non-nil, hide the cursor and only highlight the current line in the `chronometrist' buffer."
:type 'boolean)
(defcustom chronometrist-update-interval 5
"How often the `chronometrist' buffer should be updated, in seconds.
This is not guaranteed to be accurate - see (info \"(elisp)Timers\")."
:type 'integer)
(defcustom chronometrist-activity-indicator "*"
"How to indicate that a task is active.
Can be a string to be displayed, or a function which returns this string.
The default is \"*\""
:type '(choice string function))
(defcustom chronometrist-day-start-time "00:00:00"
"The time at which a day is considered to start, in \"HH:MM:SS\".
The default is midnight, i.e. \"00:00:00\"."
:type 'string)
(defvar chronometrist--task-history nil)
(defvar chronometrist--point nil)
(defvar chronometrist--inhibit-read-p nil)