mirror of
https://github.com/SqrtMinusOne/org-clock-agg.git
synced 2025-12-10 14:03:02 +03:00
org-clock-agg: implemented sort & order
This commit is contained in:
parent
baa3672af6
commit
74d4ba8e30
1 changed files with 246 additions and 61 deletions
307
org-clock-agg.el
307
org-clock-agg.el
|
|
@ -71,6 +71,7 @@ See `format-seconds' for the list of available format specifiers."
|
||||||
;; Reset org-ql cache
|
;; Reset org-ql cache
|
||||||
(setq org-ql-cache (make-hash-table :weakness 'key))
|
(setq org-ql-cache (make-hash-table :weakness 'key))
|
||||||
(setq org-clock-agg-groupby nil)
|
(setq org-clock-agg-groupby nil)
|
||||||
|
(setq org-clock-agg-sort nil)
|
||||||
|
|
||||||
;;; Querying
|
;;; Querying
|
||||||
(defun org-clock-agg--parse-clocks (headline)
|
(defun org-clock-agg--parse-clocks (headline)
|
||||||
|
|
@ -130,44 +131,71 @@ See `format-seconds' for the list of available format specifiers."
|
||||||
(defvar org-clock-agg-groupby nil
|
(defvar org-clock-agg-groupby nil
|
||||||
"Group by functions.")
|
"Group by functions.")
|
||||||
|
|
||||||
(defmacro org-clock-agg--extract-params (body &rest params)
|
(defvar org-clock-agg-sort nil
|
||||||
`(while-let ((symbol (and
|
"Sort functions.")
|
||||||
(member (car-safe body) ',params)
|
|
||||||
(car-safe body))))
|
|
||||||
,@(mapcar
|
|
||||||
(lambda (param)
|
|
||||||
`(when (eq symbol ,param)
|
|
||||||
(setq ,(intern (substring (symbol-name param) 1)) (cadr body))))
|
|
||||||
params)
|
|
||||||
(setq body (cddr body))))
|
|
||||||
|
|
||||||
(cl-defmacro org-clock-agg-defgroupby (name doc &body body)
|
;; XXX This looks like reinventing the wheel... IDK.
|
||||||
|
(defmacro org-clock-agg--extract-params (body &rest params)
|
||||||
|
`(let ((body-wo-docstring (if (stringp (car-safe body)) (cdr body) body))
|
||||||
|
(docstring (when (stringp (car-safe body)) (car-safe body))))
|
||||||
|
(while-let ((symbol (and
|
||||||
|
(member (car-safe body-wo-docstring) ',params)
|
||||||
|
(car-safe body-wo-docstring))))
|
||||||
|
,@(mapcar
|
||||||
|
(lambda (param)
|
||||||
|
`(when (eq symbol ,param)
|
||||||
|
(setq ,(intern (substring (symbol-name param) 1)) (cadr body-wo-docstring))))
|
||||||
|
params)
|
||||||
|
(setq body-wo-docstring (cddr body-wo-docstring)))
|
||||||
|
(if docstring
|
||||||
|
(setq body (cons docstring body-wo-docstring))
|
||||||
|
(setq body body-wo-docstring))))
|
||||||
|
|
||||||
|
(cl-defmacro org-clock-agg-defgroupby (name &body body)
|
||||||
(declare (indent defun)
|
(declare (indent defun)
|
||||||
(doc-string 2))
|
(doc-string 2))
|
||||||
(let ((func-name (intern (concat "org-clock-agg--groupby-" (symbol-name name))))
|
(let ((func-name (intern (concat "org-clock-agg--groupby-" (symbol-name name))))
|
||||||
readable-name
|
readable-name hidden default-sort)
|
||||||
hidden)
|
|
||||||
;; Parse keyword arguments in BODY
|
;; Parse keyword arguments in BODY
|
||||||
(org-clock-agg--extract-params body :readable-name :hidden)
|
(org-clock-agg--extract-params body :readable-name :hidden
|
||||||
|
:default-sort)
|
||||||
(unless readable-name
|
(unless readable-name
|
||||||
(setq readable-name (symbol-name name)))
|
(setq readable-name (symbol-name name)))
|
||||||
`(progn
|
`(progn
|
||||||
(defun ,func-name (elem)
|
(defun ,func-name (elem)
|
||||||
,doc
|
,@body)
|
||||||
|
(push (cons ',name '((:symbol . ,name)
|
||||||
|
(:function . ,func-name)
|
||||||
|
(:hidden . ,hidden)
|
||||||
|
(:readable-name . ,readable-name)
|
||||||
|
(:default-sort . ,default-sort)))
|
||||||
|
org-clock-agg-groupby))))
|
||||||
|
|
||||||
|
(cl-defmacro org-clock-agg-defsort (name &body body)
|
||||||
|
(declare (indent defun)
|
||||||
|
(doc-string 2))
|
||||||
|
(let ((func-name (intern (concat "org-clock-agg--sort-" (symbol-name name))))
|
||||||
|
readable-name)
|
||||||
|
(org-clock-agg--extract-params body :readable-name)
|
||||||
|
(unless readable-name
|
||||||
|
(setq readable-name (symbol-name name)))
|
||||||
|
`(progn
|
||||||
|
(defun ,func-name (elems)
|
||||||
,@body)
|
,@body)
|
||||||
(push (cons ',name '((:function . ,func-name)
|
(push (cons ',name '((:function . ,func-name)
|
||||||
(:hidden . ,hidden)
|
|
||||||
(:readable-name . ,readable-name)))
|
(:readable-name . ,readable-name)))
|
||||||
org-clock-agg-groupby))))
|
org-clock-agg-sort))))
|
||||||
|
|
||||||
(org-clock-agg-defgroupby category
|
(org-clock-agg-defgroupby category
|
||||||
"Group org-clock entries by category."
|
"Group org-clock entries by category."
|
||||||
:readable-name "Category"
|
:readable-name "Category"
|
||||||
|
:default-sort total
|
||||||
(list (alist-get :category elem)))
|
(list (alist-get :category elem)))
|
||||||
|
|
||||||
(org-clock-agg-defgroupby org-file
|
(org-clock-agg-defgroupby org-file
|
||||||
"Group org-clock entries by file in `org-directory'."
|
"Group org-clock entries by file in `org-directory'."
|
||||||
:readable-name "Org file"
|
:readable-name "Org file"
|
||||||
|
:default-sort total
|
||||||
(list
|
(list
|
||||||
(file-relative-name (alist-get :file elem)
|
(file-relative-name (alist-get :file elem)
|
||||||
(directory-file-name org-directory))))
|
(directory-file-name org-directory))))
|
||||||
|
|
@ -175,17 +203,70 @@ See `format-seconds' for the list of available format specifiers."
|
||||||
(org-clock-agg-defgroupby outline-path
|
(org-clock-agg-defgroupby outline-path
|
||||||
"Group org-clock entries by outline path."
|
"Group org-clock entries by outline path."
|
||||||
:readable-name "Outline path"
|
:readable-name "Outline path"
|
||||||
|
:default-sort total
|
||||||
(alist-get :outline-path elem))
|
(alist-get :outline-path elem))
|
||||||
|
|
||||||
|
(org-clock-agg-defgroupby tags
|
||||||
|
"Group org-clock entries by tags."
|
||||||
|
:readable-name "Tags"
|
||||||
|
:default-sort total
|
||||||
|
(seq-sort
|
||||||
|
#'string-lessp
|
||||||
|
(alist-get :tags elem)))
|
||||||
|
|
||||||
|
(org-clock-agg-defgroupby headline
|
||||||
|
"Group org-clock entries by headline."
|
||||||
|
:readable-name "Headline"
|
||||||
|
:default-sort total
|
||||||
|
(list (org-element-property :raw-value (alist-get :headline elem))))
|
||||||
|
|
||||||
(org-clock-agg-defgroupby root-group
|
(org-clock-agg-defgroupby root-group
|
||||||
"Return \"Root\". Used for the root group."
|
"Return \"Root\". Used for the root group."
|
||||||
:readable-name "Root"
|
:readable-name "Root"
|
||||||
|
:default-sort total
|
||||||
:hidden t
|
:hidden t
|
||||||
(list "Results"))
|
(list "Results"))
|
||||||
|
|
||||||
|
(org-clock-agg-defsort name
|
||||||
|
"Sort by name."
|
||||||
|
:readable-name "Name"
|
||||||
|
(seq-sort-by (lambda (elem) (alist-get :name elem)) #'string-lessp elems))
|
||||||
|
|
||||||
|
(org-clock-agg-defsort total
|
||||||
|
"Sort by total time spent."
|
||||||
|
:readable-name "Total time"
|
||||||
|
(seq-sort-by (lambda (elem) (alist-get :total elem)) #'> elems))
|
||||||
|
|
||||||
|
(org-clock-agg-defsort start-time
|
||||||
|
"Sort by start time."
|
||||||
|
:readable-name "Start time"
|
||||||
|
(seq-sort-by
|
||||||
|
(lambda (elem)
|
||||||
|
(thread-last elem
|
||||||
|
(list)
|
||||||
|
(org-clock-agg--ungroup)
|
||||||
|
(mapcar (lambda (row-elem) (alist-get :start row-elem)))
|
||||||
|
(seq-min)))
|
||||||
|
#'> elem))
|
||||||
|
|
||||||
|
(org-clock-agg-defsort end-time
|
||||||
|
"Sort by end time."
|
||||||
|
:readable-name "End time"
|
||||||
|
(seq-sort-by
|
||||||
|
(lambda (elem)
|
||||||
|
(thread-last elem
|
||||||
|
(list)
|
||||||
|
(org-clock-agg--ungroup)
|
||||||
|
(mapcar (lambda (row-elem) (alist-get :end row-elem)))
|
||||||
|
(seq-max)))
|
||||||
|
#'> elem))
|
||||||
|
|
||||||
(defun org-clock-agg--groupby-apply (alist groups elem)
|
(defun org-clock-agg--groupby-apply (alist groups elem)
|
||||||
(let* ((key (caar groups))
|
(let* ((group-params (car groups))
|
||||||
(groupby (cdar groups))
|
(key (nth 0 group-params))
|
||||||
|
(groupby (nth 1 group-params))
|
||||||
|
(sort (nth 2 group-params))
|
||||||
|
(sort-order (nth 3 group-params))
|
||||||
(rest (cdr groups))
|
(rest (cdr groups))
|
||||||
(duration (alist-get :duration elem))
|
(duration (alist-get :duration elem))
|
||||||
(prev-val (alist-get key alist nil nil #'equal)))
|
(prev-val (alist-get key alist nil nil #'equal)))
|
||||||
|
|
@ -195,42 +276,96 @@ See `format-seconds' for the list of available format specifiers."
|
||||||
(:groupby . ,groupby)
|
(:groupby . ,groupby)
|
||||||
(:children . ,(org-clock-agg--groupby-apply
|
(:children . ,(org-clock-agg--groupby-apply
|
||||||
(alist-get :children prev-val) rest elem))
|
(alist-get :children prev-val) rest elem))
|
||||||
|
(:sort-symbol . ,sort)
|
||||||
|
(:sort-order . ,sort-order)
|
||||||
(:elems . ,(if rest
|
(:elems . ,(if rest
|
||||||
(alist-get :elems prev-val)
|
(alist-get :elems prev-val)
|
||||||
(cons elem (alist-get :elems prev-val))))))))
|
(cons elem (alist-get :elems prev-val))))))))
|
||||||
alist)
|
alist)
|
||||||
|
|
||||||
(defun org-clock-agg--groupby (elems groupby-list)
|
(defun org-clock-agg--groupby (elems groupby-list sort-list sort-order-list)
|
||||||
(let (res)
|
(let (res)
|
||||||
(dolist (elem elems)
|
(dolist (elem elems)
|
||||||
(let* ((group-symbols (cons 'root-group groupby-list))
|
(let* ((group-symbols (cons 'root-group groupby-list))
|
||||||
|
(sort-symbols (cons 'total sort-list))
|
||||||
|
(sort-orders (cons nil sort-order-list))
|
||||||
(groups
|
(groups
|
||||||
(cl-loop for group-symbol in group-symbols
|
(cl-loop for group-symbol in group-symbols
|
||||||
|
for sort-symbol in sort-symbols
|
||||||
|
for sort-order in sort-orders
|
||||||
for groupby = (alist-get group-symbol org-clock-agg-groupby)
|
for groupby = (alist-get group-symbol org-clock-agg-groupby)
|
||||||
for group-values = (funcall (alist-get :function groupby) elem)
|
for group-values = (funcall (alist-get :function groupby) elem)
|
||||||
append
|
append
|
||||||
(mapcar
|
(mapcar
|
||||||
(lambda (group-value)
|
(lambda (group-value)
|
||||||
(cons group-value groupby))
|
(list group-value groupby sort-symbol sort-order))
|
||||||
group-values))))
|
group-values))))
|
||||||
(setq res (org-clock-agg--groupby-apply res groups elem))))
|
(setq res (org-clock-agg--groupby-apply res groups elem))))
|
||||||
res))
|
res))
|
||||||
|
|
||||||
(defun org-clock-agg--groupby-sort (tree sort)
|
(defun org-clock-agg--ungroup (tree)
|
||||||
(setq tree (seq-sort-by (lambda (elem)
|
(cl-loop for tree-elem in tree
|
||||||
(alist-get :total elem))
|
append (alist-get :elems tree-elem)
|
||||||
#'> tree))
|
append (org-clock-agg--ungroup (alist-get :children elem))))
|
||||||
(dolist (elem tree)
|
|
||||||
(let ((children (alist-get :children elem)))
|
(defun org-clock-agg--groupby-sort (tree)
|
||||||
(when children
|
(let* ((sorted-nodes-by-group
|
||||||
(setf (alist-get :children elem)
|
(thread-last
|
||||||
(org-clock-agg--groupby-sort children sort)))))
|
tree
|
||||||
tree)
|
(mapcar (lambda (node) (cons (cons :name (car node)) (cdr node))))
|
||||||
|
(seq-group-by
|
||||||
|
(lambda (node)
|
||||||
|
(list (alist-get :symbol (alist-get :groupby node))
|
||||||
|
(alist-get :sort-symbol node)
|
||||||
|
(alist-get :sort-order node))))
|
||||||
|
(mapcar
|
||||||
|
(lambda (grouped)
|
||||||
|
(let ((group-symbol (nth 0 (car grouped)))
|
||||||
|
(sort-symbol (nth 1 (car grouped)))
|
||||||
|
(sort-order (nth 2 (car grouped))))
|
||||||
|
(setf (cdr grouped)
|
||||||
|
(funcall (thread-last org-clock-agg-sort
|
||||||
|
(alist-get sort-symbol)
|
||||||
|
(alist-get :function))
|
||||||
|
(cdr grouped)))
|
||||||
|
(when sort-order
|
||||||
|
(setf (cdr grouped) (reverse (cdr grouped))))
|
||||||
|
grouped)))
|
||||||
|
(seq-sort-by
|
||||||
|
(lambda (grouped)
|
||||||
|
(thread-last org-clock-agg-groupby
|
||||||
|
(alist-get (car (car grouped)))
|
||||||
|
(alist-get :readable-name)))
|
||||||
|
#'string-lessp)))
|
||||||
|
(tree (seq-reduce (lambda (acc grouped)
|
||||||
|
(append (cdr grouped) acc))
|
||||||
|
sorted-nodes-by-group nil)))
|
||||||
|
(dolist (node tree)
|
||||||
|
(let ((children (alist-get :children node))
|
||||||
|
(elems (alist-get :elems node)))
|
||||||
|
(when children
|
||||||
|
(setf (alist-get :children node)
|
||||||
|
(org-clock-agg--groupby-sort children)))
|
||||||
|
(when elems
|
||||||
|
(setf (alist-get :elems node)
|
||||||
|
(seq-sort-by (lambda (elem) (alist-get :start elem))
|
||||||
|
#'>
|
||||||
|
(alist-get :elems node))))))
|
||||||
|
(mapcar (lambda (node)
|
||||||
|
(cons (alist-get :name node)
|
||||||
|
node))
|
||||||
|
tree)))
|
||||||
|
|
||||||
;; View & manage results
|
;; View & manage results
|
||||||
(defvar-local org-clock-agg--params nil
|
(defvar-local org-clock-agg--params nil
|
||||||
"Parameters for the current org-clock-agg buffer.")
|
"Parameters for the current org-clock-agg buffer.")
|
||||||
|
|
||||||
|
(defvar-local org-clock-agg--elems nil
|
||||||
|
"Elements for the current org-clock-agg buffer.")
|
||||||
|
|
||||||
|
(defvar-local org-clock-agg--tree nil
|
||||||
|
"Tree for the current org-clock-agg buffer.")
|
||||||
|
|
||||||
(defun org-clock-agg-quit ()
|
(defun org-clock-agg-quit ()
|
||||||
(interactive)
|
(interactive)
|
||||||
(quit-window t))
|
(quit-window t))
|
||||||
|
|
@ -251,9 +386,7 @@ See `format-seconds' for the list of available format specifiers."
|
||||||
"Major mode for viewing org-clock-agg results."
|
"Major mode for viewing org-clock-agg results."
|
||||||
(outline-minor-mode 1))
|
(outline-minor-mode 1))
|
||||||
|
|
||||||
(defun org-clock-agg--render-controls ()
|
(defun org-clock-agg--render-controls-files ()
|
||||||
(remove-overlays)
|
|
||||||
(insert (propertize "* Parameters" 'face 'org-level-1) "\n")
|
|
||||||
(apply
|
(apply
|
||||||
#'widget-create 'menu-choice
|
#'widget-create 'menu-choice
|
||||||
:tag "Files"
|
:tag "Files"
|
||||||
|
|
@ -271,9 +404,20 @@ See `format-seconds' for the list of available format specifiers."
|
||||||
:entry-format "%i %d %v"
|
:entry-format "%i %d %v"
|
||||||
:menu-tag "Custom list"
|
:menu-tag "Custom list"
|
||||||
:value nil
|
:value nil
|
||||||
(editable-field :tag "File" :value "")))))
|
(editable-field :tag "File" :value ""))))))
|
||||||
(insert "\n")
|
|
||||||
|
|
||||||
|
(defun org-clock-agg--validate-date (widget)
|
||||||
|
(let ((date (widget-value widget)))
|
||||||
|
(unless (or (not (stringp date))
|
||||||
|
(and
|
||||||
|
(not (string-match-p (rx bos (? "-") (+ digit) eos) date))
|
||||||
|
(not (and (decoded-time-year val)
|
||||||
|
(decoded-time-month val)
|
||||||
|
(decoded-time-day val)))))
|
||||||
|
(widget-put widget :error "Enter number or date in format YYYY-MM-DD")
|
||||||
|
widget)))
|
||||||
|
|
||||||
|
(defun org-clock-agg--render-controls-date ()
|
||||||
(widget-create 'editable-field
|
(widget-create 'editable-field
|
||||||
:size 20
|
:size 20
|
||||||
:format (concat (propertize "Date from: " 'face 'widget-button) "%v ")
|
:format (concat (propertize "Date from: " 'face 'widget-button) "%v ")
|
||||||
|
|
@ -281,6 +425,7 @@ See `format-seconds' for the list of available format specifiers."
|
||||||
(if (numberp val)
|
(if (numberp val)
|
||||||
(number-to-string val)
|
(number-to-string val)
|
||||||
val))
|
val))
|
||||||
|
:validate #'org-clock-agg--validate-date
|
||||||
:notify (lambda (widget &rest ignore)
|
:notify (lambda (widget &rest ignore)
|
||||||
(let ((val (widget-value widget)))
|
(let ((val (widget-value widget)))
|
||||||
(when (string-match-p (rx bos (? "-") (+ digit) eos) val)
|
(when (string-match-p (rx bos (? "-") (+ digit) eos) val)
|
||||||
|
|
@ -294,34 +439,72 @@ See `format-seconds' for the list of available format specifiers."
|
||||||
(if (numberp val)
|
(if (numberp val)
|
||||||
(number-to-string val)
|
(number-to-string val)
|
||||||
val))
|
val))
|
||||||
|
:validate #'org-clock-agg--validate-date
|
||||||
:notify (lambda (widget &rest ignore)
|
:notify (lambda (widget &rest ignore)
|
||||||
(let ((val (widget-value widget)))
|
(let ((val (widget-value widget)))
|
||||||
(when (string-match-p (rx bos (? "-") (+ digit) eos) val)
|
(when (string-match-p (rx bos (? "-") (+ digit) eos) val)
|
||||||
(setq val (string-to-number val)))
|
(setq val (string-to-number val)))
|
||||||
(setf (alist-get :to org-clock-agg--params) val))))
|
(setf (alist-get :to org-clock-agg--params) val)))))
|
||||||
(insert "\n\n")
|
|
||||||
|
|
||||||
|
(defun org-clock-agg--render-controls-groupby ()
|
||||||
(insert (propertize "Group by: " 'face 'widget-button) "\n")
|
(insert (propertize "Group by: " 'face 'widget-button) "\n")
|
||||||
(widget-create 'editable-list
|
(widget-create 'editable-list
|
||||||
:tag "Group by"
|
:tag "Group by"
|
||||||
:entry-format "%i %d %v"
|
:entry-format "%i %d %v"
|
||||||
:value (alist-get :groupby org-clock-agg--params)
|
:value (cl-loop for group-value in (alist-get :groupby org-clock-agg--params)
|
||||||
|
for sort-value in (alist-get :sort org-clock-agg--params)
|
||||||
|
for sort-order-value in (alist-get :sort-order org-clock-agg--params)
|
||||||
|
collect (list group-value sort-value sort-order-value))
|
||||||
:notify
|
:notify
|
||||||
(lambda (widget &rest ignore)
|
(lambda (widget changed-widget &optional event)
|
||||||
(setf (alist-get :groupby org-clock-agg--params)
|
(let ((group-value (mapcar #'car (widget-value widget)))
|
||||||
(widget-value widget)))
|
(sort-value (mapcar #'cadr (widget-value widget)))
|
||||||
`(menu-choice
|
(sort-order-value (mapcar #'caddr (widget-value widget))))
|
||||||
:tag "Group"
|
(setf (alist-get :groupby org-clock-agg--params) group-value)
|
||||||
,@(thread-last
|
(setf (alist-get :sort org-clock-agg--params) sort-value)
|
||||||
org-clock-agg-groupby
|
(setf (alist-get :sort-order org-clock-agg--params) sort-order-value)))
|
||||||
(seq-filter (lambda (groupby)
|
`(group
|
||||||
(not (alist-get :hidden (cdr groupby)))))
|
:value (outline-path total)
|
||||||
(mapcar (lambda (groupby)
|
(menu-choice
|
||||||
(let ((name (car groupby))
|
:tag "Group"
|
||||||
(readable-name (alist-get :readable-name (cdr groupby))))
|
:notify (lambda (widget _child &optional event)
|
||||||
`(item :tag ,readable-name
|
(if-let* ((value (widget-value widget))
|
||||||
:value ,name
|
(default-sort (alist-get
|
||||||
:menu-tag ,readable-name)))))))
|
:default-sort
|
||||||
|
(alist-get value org-clock-agg-groupby)))
|
||||||
|
(parent (widget-get widget :parent)))
|
||||||
|
(widget-value-set parent (list value default-sort)))
|
||||||
|
(widget-default-action widget event))
|
||||||
|
,@(thread-last
|
||||||
|
org-clock-agg-groupby
|
||||||
|
(seq-filter (lambda (groupby)
|
||||||
|
(not (alist-get :hidden (cdr groupby)))))
|
||||||
|
(mapcar (lambda (groupby)
|
||||||
|
(let ((name (car groupby))
|
||||||
|
(readable-name (alist-get :readable-name (cdr groupby))))
|
||||||
|
`(item :tag ,readable-name
|
||||||
|
:value ,name
|
||||||
|
:menu-tag ,readable-name))))))
|
||||||
|
(menu-choice
|
||||||
|
:tag "Order"
|
||||||
|
,@(mapcar
|
||||||
|
(lambda (sort)
|
||||||
|
(let ((name (car sort))
|
||||||
|
(readable-name (alist-get :readable-name (cdr sort))))
|
||||||
|
`(item :tag ,readable-name
|
||||||
|
:value ,name
|
||||||
|
:menu-tag ,readable-name)))
|
||||||
|
org-clock-agg-sort))
|
||||||
|
(toggle :on "Reverse order" :off "Normal order"))))
|
||||||
|
|
||||||
|
(defun org-clock-agg--render-controls ()
|
||||||
|
(remove-overlays)
|
||||||
|
(insert (propertize "* Parameters" 'face 'org-level-1) "\n")
|
||||||
|
(org-clock-agg--render-controls-files)
|
||||||
|
(insert "\n")
|
||||||
|
(org-clock-agg--render-controls-date)
|
||||||
|
(insert "\n\n")
|
||||||
|
(org-clock-agg--render-controls-groupby)
|
||||||
(insert "\n")
|
(insert "\n")
|
||||||
(widget-create 'push-button
|
(widget-create 'push-button
|
||||||
:notify (lambda (&rest ignore)
|
:notify (lambda (&rest ignore)
|
||||||
|
|
@ -370,12 +553,14 @@ See `format-seconds' for the list of available format specifiers."
|
||||||
|
|
||||||
(defun org-clock-agg-refresh ()
|
(defun org-clock-agg-refresh ()
|
||||||
(interactive)
|
(interactive)
|
||||||
(cl-destructuring-bind (&key from to files groupby sort)
|
(cl-destructuring-bind (&key from to files groupby sort sort-order)
|
||||||
(cl--alist-to-plist org-clock-agg--params)
|
(cl--alist-to-plist org-clock-agg--params)
|
||||||
(let* ((files (org-clock-agg--parse-files files))
|
(let* ((files (org-clock-agg--parse-files files))
|
||||||
(elems (org-clock-agg--query from to files))
|
(elems (org-clock-agg--query from to files))
|
||||||
(tree (org-clock-agg--groupby elems groupby))
|
(tree (org-clock-agg--groupby elems groupby sort sort-order))
|
||||||
(tree (org-clock-agg--groupby-sort tree sort)))
|
(tree (org-clock-agg--groupby-sort tree)))
|
||||||
|
(setq-local org-clock-agg--elems elems)
|
||||||
|
(setq-local org-clock-agg--tree tree)
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(let ((inhibit-read-only t))
|
(let ((inhibit-read-only t))
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
|
|
@ -384,11 +569,10 @@ See `format-seconds' for the list of available format specifiers."
|
||||||
(delete-region (point) (point-max))
|
(delete-region (point) (point-max))
|
||||||
(mapc #'org-clock-agg--render-tree-elem tree))))))
|
(mapc #'org-clock-agg--render-tree-elem tree))))))
|
||||||
|
|
||||||
(defun org-clock-agg (from to files groupby sort)
|
(defun org-clock-agg (from to files groupby sort sort-order)
|
||||||
(interactive (list -7 0 'org-agenda nil nil))
|
(interactive (list -7 0 'org-agenda nil nil nil))
|
||||||
(let* ((buffer (generate-new-buffer "*org-clock-agg*")))
|
(let* ((buffer (generate-new-buffer "*org-clock-agg*")))
|
||||||
(switch-to-buffer-other-window buffer)
|
(switch-to-buffer-other-window buffer)
|
||||||
|
|
||||||
(with-current-buffer buffer
|
(with-current-buffer buffer
|
||||||
(org-clock-agg-tree-mode)
|
(org-clock-agg-tree-mode)
|
||||||
(setq-local org-clock-agg--params
|
(setq-local org-clock-agg--params
|
||||||
|
|
@ -396,7 +580,8 @@ See `format-seconds' for the list of available format specifiers."
|
||||||
(:to . ,to)
|
(:to . ,to)
|
||||||
(:files . ,files)
|
(:files . ,files)
|
||||||
(:groupby . ,groupby)
|
(:groupby . ,groupby)
|
||||||
(:sort . ,sort)))
|
(:sort . ,sort)
|
||||||
|
(:sort-order . ,sort-order)))
|
||||||
(let ((inhibit-read-only t))
|
(let ((inhibit-read-only t))
|
||||||
(org-clock-agg--render-controls)
|
(org-clock-agg--render-controls)
|
||||||
(org-clock-agg-refresh))
|
(org-clock-agg-refresh))
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue