Compare commits

...

3 Commits

Author SHA1 Message Date
contrapunctus f7b2defcee Update CL port manual 2022-05-03 10:45:18 +05:30
contrapunctus be32efd73b Update custom IDs 2022-05-03 10:45:10 +05:30
contrapunctus 339d5da1e7 Display durations using format-seconds 2022-05-03 10:43:50 +05:30
2 changed files with 56 additions and 42 deletions

View File

@ -95,7 +95,7 @@ One of the earliest 'optimizations' of great importance turned out to simply be
*** Preserve hash table state for some commands
:PROPERTIES:
:CUSTOM_ID: preserve-hash-table-state-for-some-commands
:CUSTOM_ID: preserve-hash-table-state-some-commands
:END:
NOTE - this has been replaced with a more general optimization - see next section.
@ -153,14 +153,14 @@ There are a few different approaches of dealing with them. (Currently, Chronomet
*** Check the code of the first event of the day (timeclock format)
:PROPERTIES:
:DESCRIPTION: When the code of the first event in the day is "o", it's a midnight-spanning event.
:CUSTOM_ID: check-the-code-of-the-first-event-of-the-day-(timeclock-format)
:CUSTOM_ID: check-code-of-first-event-of-day
:END:
+ Advantage - very simple to detect
+ Disadvantage - "in" and "out" events must be represented separately
*** Split them at the file level
:PROPERTIES:
:CUSTOM_ID: split-them-at-the-file-level
:CUSTOM_ID: split-in-file
:END:
+ Advantage - operation is performed only once for each such event + simpler data-consuming code + reduced post-parsing load.
+ What happens when the user changes their day-start-time? The split-up events are now split wrongly, and the second event may get split /again./
@ -176,14 +176,14 @@ This strategy is implemented in the [[#program-backend-plist-group][plist-group]
*** Split them at the hash-table-level
:PROPERTIES:
:CUSTOM_ID: split-them-at-the-hash-table-level
:CUSTOM_ID: split-in-hash-table
:END:
Handled by ~sexp-events-populate~
+ Advantage - simpler data-consuming code.
*** Split them at the data-consumer level (e.g. when calculating time for one day/getting events for one day)
:PROPERTIES:
:CUSTOM_ID: split-them-at-the-data-consumer-level-(e.g.-when-calculating-time-for-one-day-getting-events-for-one-day)
:CUSTOM_ID: split-at-data-consumer-level
:END:
+ Advantage - reduced repetitive post-parsing load.
@ -380,7 +380,7 @@ There are many operations which are file-oriented, whereas I have tried to treat
** generic loop interface for iterating over records
:PROPERTIES:
:CUSTOM_ID: generic-loop-interface-for-iterating-over-records
:CUSTOM_ID: generic-loop-interface-iterating-over-records
:END:
Of all the ways to work with Chronometrist data, both as part of the program and as part of my occasional "queries", my favorite was to use =cl-loop=.
@ -403,7 +403,7 @@ The macro still exists in its non-generic form as =loop-sexp-file=, providing a
* How-to guides for maintainers
:PROPERTIES:
:CUSTOM_ID: how-to-guides-for-maintainers
:CUSTOM_ID: how-to-guides-maintainers
:END:
** How to set up Emacs to contribute
:PROPERTIES:
@ -474,7 +474,7 @@ Use =org-babel= (=org-babel-tangle= / =org-babel-tangle-file=), /not/ =literate-
* The Program
:PROPERTIES:
:CUSTOM_ID: the-program
:CUSTOM_ID: program
:END:
** chronometrist :package:
:PROPERTIES:
@ -546,7 +546,7 @@ Use =org-babel= (=org-babel-tangle= / =org-babel-tangle-file=), /not/ =literate-
*** *user-configuration-file* :custom:variable:
:PROPERTIES:
:CUSTOM_ID: *user-configuration-file*
:CUSTOM_ID: user-configuration-file
:END:
#+BEGIN_SRC lisp
(defvar *user-configuration-file*
@ -555,7 +555,7 @@ Use =org-babel= (=org-babel-tangle= / =org-babel-tangle-file=), /not/ =literate-
*** *user-data-file* :custom:variable:
:PROPERTIES:
:CUSTOM_ID: *user-data-file*
:CUSTOM_ID: user-data-file
:END:
#+BEGIN_SRC lisp
(defvar *user-data-file* (merge-pathnames "chronometrist" *xdg-data-dir*)
@ -574,7 +574,7 @@ Use =org-babel= (=org-babel-tangle= / =org-babel-tangle-file=), /not/ =literate-
*** *day-start-time* :custom:variable:
:PROPERTIES:
:CUSTOM_ID: *day-start-time*
:CUSTOM_ID: day-start-time
:END:
=chronometrist-events-maybe-split= refers to this, but I'm not sure this has the desired effect at the moment—haven't even tried using it.
#+BEGIN_SRC lisp
@ -822,8 +822,9 @@ treated as though their time is 00:00:00."
:CUSTOM_ID: task-duration-one-day
:END:
#+BEGIN_SRC lisp
(defun task-duration-one-day (task &optional (date (timestamp-to-unix (today)))
(backend (active-backend)))
(defun task-duration-one-day (task &optional
(date (timestamp-to-unix (today)))
(backend (active-backend)))
"Return total time spent on TASK today or on DATE.
The return value is seconds, as an integer."
(let ((task-intervals (task-records-for-date backend task date)))
@ -867,7 +868,7 @@ which span midnights."
*** *task-list* :custom:variable:
:PROPERTIES:
:VALUE: list
:CUSTOM_ID: *task-list*
:CUSTOM_ID: task-list
:END:
#+BEGIN_SRC lisp
(defvar *task-list* nil
@ -1088,7 +1089,7 @@ The backend may use no files, a single file, or multiple files. Thus, =backend=
**** *backends-alist* :variable:
:PROPERTIES:
:CUSTOM_ID: *backends-alist*
:CUSTOM_ID: backends-alist
:END:
#+BEGIN_SRC lisp
(defvar *backends-alist* nil
@ -1100,7 +1101,7 @@ EIEIO object such as one returned by `make-instance'.")
**** *active-backend* :custom:variable:
:PROPERTIES:
:CUSTOM_ID: *active-backend*
:CUSTOM_ID: active-backend-variable
:END:
#+BEGIN_SRC lisp
(defvar *active-backend* :sqlite
@ -1111,7 +1112,7 @@ Value must be a keyword corresponding to a key in
**** active-backend :reader:
:PROPERTIES:
:CUSTOM_ID: active-backend
:CUSTOM_ID: active-backend-function
:END:
#+BEGIN_SRC lisp
(defun active-backend ()
@ -1136,7 +1137,7 @@ be replaced."
**** task-list :function:
:PROPERTIES:
:CUSTOM_ID: task-list
:CUSTOM_ID: task-list-1
:END:
#+BEGIN_SRC lisp
(defun task-list ()
@ -1360,7 +1361,7 @@ entire (unsplit) record must be returned."))
**** task-records-for-date :generic:function:
:PROPERTIES:
:CUSTOM_ID: task-records-for-date
:CUSTOM_ID: task-records-date
:END:
#+BEGIN_SRC lisp
(declaim (ftype (function (chronometrist:backend
@ -1382,7 +1383,7 @@ Return nil if BACKEND contains no records.")
***** task-records-for-date :before:method:
:PROPERTIES:
:CUSTOM_ID: task-records-for-date-1
:CUSTOM_ID: before-task-records-for-date
:END:
#+BEGIN_SRC lisp
#+(or)
@ -1570,7 +1571,7 @@ These can be implemented in terms of the minimal protocol above.
*** Common definitions for s-expression backends
:PROPERTIES:
:CUSTOM_ID: common-definitions-for-s-expression-backends
:CUSTOM_ID: common-definitions-sexp-backends
:END:
**** file-backend-mixin :mixin:class:
:PROPERTIES:
@ -1806,7 +1807,7 @@ expression first)."
**** indices and hashes
:PROPERTIES:
:CUSTOM_ID: indices-and-hashes
:CUSTOM_ID: indices-hashes
:END:
#+BEGIN_SRC lisp
(defun rest-start (file)
@ -2533,7 +2534,7 @@ Return value is either a list in the form
***** task-records-for-date :reader:method:
:PROPERTIES:
:CUSTOM_ID: task-records-for-date-2
:CUSTOM_ID: plist-group-task-records-for-date
:END:
#+BEGIN_SRC lisp
(defmethod chronometrist:task-records-for-date
@ -3019,26 +3020,27 @@ s-expressions in a text column.")
**** task-records-for-date
:PROPERTIES:
:CUSTOM_ID: task-records-for-date-3
:CUSTOM_ID: sqlite-task-records-for-date
:END:
#+BEGIN_SRC lisp
(defmethod chronometrist:task-records-for-date
((backend sqlite-backend) task date &key &allow-other-keys)
(let ((list (execute-sxql #'execute-to-list
(select (:name :start_time :stop_time :properties)
(from :intervals)
(left-join :interval_names :using (:name_id))
(left-join :properties :using (:prop_id))
(where (:and
(:in :interval_id
(select (:interval_id)
(from :date_intervals)
(where (:= :date_id
(select (:date_id)
(from :dates)
(where (:= :date date)))))))
(:= :name task))))
(backend-connection backend))))
(let ((list (execute-sxql
#'execute-to-list
(select (:name :start_time :stop_time :properties)
(from :intervals)
(left-join :interval_names :using (:name_id))
(left-join :properties :using (:prop_id))
(where (:and
(:in :interval_id
(select (:interval_id)
(from :date_intervals)
(where (:= :date_id
(select (:date_id)
(from :dates)
(where (:= :date date)))))))
(:= :name task))))
(backend-connection backend))))
(loop for (name start stop prop-string) in list
collect (make-interval name start stop prop-string))))
#+END_SRC
@ -3091,11 +3093,21 @@ s-expressions in a text column.")
(defpackage :chronometrist.clim
(:use :clim :clim-lisp)
(:import-from :local-time :now :today :timestamp-to-unix)
(:import-from :format-seconds :format-seconds)
(:import-from :chronometrist :task-list :task-duration-one-day)
(:export :run-chronometrist))
(in-package :chronometrist.clim)
#+END_SRC
**** *duration-format-string* :variable:
:PROPERTIES:
:CUSTOM_ID: duration-format-string
:END:
#+BEGIN_SRC lisp
(defvar *duration-format-string* "~2h:~2,'0m:~2,'0s"
"Format string used for durations, acceptable to `format-seconds'.")
#+END_SRC
**** chronometrist :application:frame:
:PROPERTIES:
:CUSTOM_ID: chronometrist-1
@ -3195,12 +3207,14 @@ FRAME and PANE are the CLIM frame and pane as passed to the display function."))
duration
frame pane)
(with-output-as-presentation (pane duration 'number)
(format t "~A" duration)))
(if (zerop duration)
(format t "~10@A" "-")
(format-seconds t *duration-format-string* duration))))
#+END_SRC
***** *task-duration-table-spec* :custom:variable:
:PROPERTIES:
:CUSTOM_ID: *task-duration-table-spec*
:CUSTOM_ID: task-duration-table-spec
:END:
#+BEGIN_SRC lisp
(defvar *task-duration-table-spec*

View File

@ -25,7 +25,7 @@ Currently, only one CLIM pane has been implemented, called the [[file:chronometr
:PROPERTIES:
:CUSTOM_ID: tables
:END:
The tables in the CLIM frontend are meant to be easy to extend. Thus -
The tables in the CLIM frontend are designed with ease of extensibility in mind. Thus -
1. The columns displayed in this table are controlled by [[file:chronometrist.org::#*task-duration-table-spec*][=*task-duration-table-spec*=]], which contains a list of [[file:chronometrist.org::#column-specifier][=column-specifier=]] objects.
2. Each [[file:chronometrist.org::#column-specifier][=column-specifier=]] has two methods specializing on it, a [[file:chronometrist.org::#cell-data][=cell-data=]] method and a [[file:chronometrist.org::#cell-print][=cell-print=]] method. These determine the data contained by the cells of the column, and how that data is printed in the CLIM pane.