Compare commits
16 Commits
production
...
dev
Author | SHA1 | Date |
---|---|---|
contrapunctus | 01db31e44d | |
contrapunctus | 65d36aa83a | |
contrapunctus | 5301d0327a | |
contrapunctus | 3e9244eb09 | |
contrapunctus | a1e305fb8c | |
contrapunctus | 5068bca3d6 | |
contrapunctus | ab38cf29d2 | |
contrapunctus | c0597098fe | |
contrapunctus | 1474c7fa5a | |
contrapunctus | 0e6e57cdee | |
contrapunctus | 858da9341b | |
contrapunctus | 79c73cbb7f | |
contrapunctus | b9d910f4d6 | |
contrapunctus | b115c8644d | |
contrapunctus | 53ed966671 | |
contrapunctus | b52ddb3e03 |
|
@ -0,0 +1,42 @@
|
|||
.phony: all setup tangle compile lint-check-declare lint-checkdoc lint-package-lint lint-relint lint clean-elc
|
||||
|
||||
all: clean-elc setup tangle compile lint
|
||||
|
||||
setup:
|
||||
emacs --batch --eval="(package-initialize)" \
|
||||
--eval="(mapcar #'package-install '(indent-lint package-lint relint))"
|
||||
|
||||
# No -q or -Q without ORG_PATH - if the user has a newer version of
|
||||
# Org, we want to use it.
|
||||
tangle:
|
||||
emacs --batch \
|
||||
--eval="(package-initialize)" --eval="(require 'ob-tangle)" \
|
||||
--eval='(org-babel-tangle-file "chronometrist-goal.org")'
|
||||
|
||||
compile: tangle
|
||||
emacs --batch \
|
||||
--eval="(progn (package-initialize) (require 'chronometrist) (require 'alert))" \
|
||||
--eval='(byte-compile-file "chronometrist-goal.el")'
|
||||
|
||||
lint-check-declare: tangle
|
||||
emacs -q -Q --batch --eval='(check-declare-file "chronometrist-goal.el")'
|
||||
|
||||
lint-checkdoc: tangle
|
||||
emacs -q -Q --batch --eval='(checkdoc-file "chronometrist-goal.el")'
|
||||
|
||||
lint-package-lint: setup tangle
|
||||
emacs --batch \
|
||||
--eval="(progn (package-initialize) (require 'chronometrist) (require 'alert))" \
|
||||
--eval="(require 'package-lint)" \
|
||||
-f 'package-lint-batch-and-exit' chronometrist-goal.el \
|
||||
|
||||
lint-relint: setup tangle
|
||||
emacs -q -Q --batch \
|
||||
--eval="(package-initialize)" \
|
||||
--eval="(require 'relint)" \
|
||||
--eval='(relint-file "chronometrist-goal.el")'
|
||||
|
||||
lint: lint-check-declare lint-checkdoc lint-package-lint lint-relint
|
||||
|
||||
clean-elc:
|
||||
-rm *.elc
|
|
@ -7,7 +7,7 @@
|
|||
;; Package-Requires: ((emacs "25.1") (alert "1.2") (chronometrist "0.6.0"))
|
||||
;; Version: 0.2.1
|
||||
|
||||
(require 'chronometrist-queries)
|
||||
(require 'chronometrist)
|
||||
(require 'alert)
|
||||
|
||||
;; This is free and unencumbered software released into the public domain.
|
||||
|
@ -26,7 +26,7 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(declare-function chronometrist-last "chronometrist-queries")
|
||||
(declare-function chronometrist-last "chronometrist")
|
||||
|
||||
(defvar chronometrist-goal--timers-list nil)
|
||||
|
||||
|
@ -42,8 +42,8 @@ There can be more than one TASK, to specify that you would
|
|||
like to spend GOAL time on any one of those tasks."
|
||||
:group 'chronometrist
|
||||
:type '(repeat
|
||||
(list integer :value 15
|
||||
(repeat :inline t string))))
|
||||
(list (integer :value 15)
|
||||
(set :inline t (repeat string)))))
|
||||
|
||||
(defun chronometrist-goal-run-at-time (time repeat function &rest args)
|
||||
"Like `run-at-time', but append timers to `chronometrist-goal--timers-list'.
|
||||
|
@ -203,49 +203,48 @@ To use, add this to `chronometrist-after-out-functions', and
|
|||
|
||||
(defun chronometrist-goal-on-file-change ()
|
||||
"Manage timed alerts when `chronometrist-file' changes."
|
||||
(let ((last (chronometrist-last)))
|
||||
(let ((last (chronometrist-latest-record (chronometrist-active-backend))))
|
||||
(chronometrist-goal-stop-alert-timers)
|
||||
;; if there's a task running, start timed alerts for it
|
||||
(unless (plist-get last :stop)
|
||||
(chronometrist-goal-run-alert-timers (plist-get last :name)))))
|
||||
|
||||
;;;; minor mode
|
||||
(defun chronometrist-goal-entry-transformer (entry)
|
||||
"Add goal information to the return value of `chronometrist-entries'.
|
||||
ENTRY must be a valid element in the list specified by
|
||||
`tabulated-list-entries'."
|
||||
(-let* (((task vector) entry)
|
||||
(goal (aif (chronometrist-goal-get task) (format "% 4d" it) "")))
|
||||
(list task (vconcat vector `[,goal]))))
|
||||
(defun chronometrist-goal-row-transformer (row)
|
||||
"Add a goal cell to ROW.
|
||||
Used to add a goal column to `chronometrist-rows'.
|
||||
|
||||
(defun chronometrist-goal-list-format-transformer (format)
|
||||
"Add a goal column to the return value of `tabulated-list-format'.
|
||||
FORMAT should be a vector (see `tabulated-list-format')."
|
||||
(vconcat format `[("Target" 3 t)]))
|
||||
ROW must be a valid element of the list specified by
|
||||
`tabulated-list-entries'."
|
||||
(-let* (((task vector) row)
|
||||
(goal-minutes (chronometrist-goal-get task))
|
||||
(goal-string (if goal-minutes (format "% 4d" goal-minutes) "")))
|
||||
(list task (vconcat vector `[,goal-string]))))
|
||||
|
||||
(defun chronometrist-goal-schema-transformer (schema)
|
||||
"Add a goal column to SCHEMA.
|
||||
Used to add a goal column to `chronometrist-schema-transformers'.
|
||||
SCHEMA should be a vector as specified by `tabulated-list-format'."
|
||||
(vconcat schema `[("Target" 5 t :pad-right 3)]))
|
||||
|
||||
(defun chronometrist-goal-setup ()
|
||||
"Add `chronometrist-goal' functions to `chronometrist' hooks."
|
||||
(add-to-list 'chronometrist-entry-transformers #'chronometrist-goal-entry-transformer)
|
||||
(add-to-list 'chronometrist-list-format-transformers #'chronometrist-goal-list-format-transformer)
|
||||
(add-hook 'chronometrist-after-in-functions #'chronometrist-goal-run-alert-timers)
|
||||
(add-hook 'chronometrist-after-out-functions #'chronometrist-goal-stop-alert-timers))
|
||||
(add-to-list 'chronometrist-row-transformers #'chronometrist-goal-row-transformer)
|
||||
(add-to-list 'chronometrist-schema-transformers #'chronometrist-goal-schema-transformer)
|
||||
(add-hook 'chronometrist-after-in-functions #'chronometrist-goal-run-alert-timers)
|
||||
(add-hook 'chronometrist-after-out-functions #'chronometrist-goal-stop-alert-timers))
|
||||
|
||||
(defun chronometrist-goal-teardown ()
|
||||
"Remove `chronometrist-goal' functions from `chronometrist' hooks."
|
||||
(setq chronometrist-entry-transformers
|
||||
(remove #'chronometrist-goal-entry-transformer chronometrist-entry-transformers)
|
||||
chronometrist-list-format-transformers
|
||||
(remove #'chronometrist-goal-list-format-transformer chronometrist-list-format-transformers))
|
||||
(setq chronometrist-row-transformers
|
||||
(remove #'chronometrist-goal-row-transformer chronometrist-row-transformers)
|
||||
chronometrist-schema-transformers
|
||||
(remove #'chronometrist-goal-schema-transformer chronometrist-schema-transformers))
|
||||
(remove-hook 'chronometrist-after-in-functions #'chronometrist-goal-run-alert-timers)
|
||||
(remove-hook 'chronometrist-after-out-functions #'chronometrist-goal-stop-alert-timers))
|
||||
|
||||
(define-minor-mode chronometrist-goal-minor-mode
|
||||
"Toggle `chronometrist-goal-minor-mode'.
|
||||
With a prefix argument ARG, enable
|
||||
`chronometrist-goal-minor-mode' if ARG is positive, and disable
|
||||
it otherwise. If called from Lisp, enable the mode if ARG is
|
||||
omitted or nil."
|
||||
nil nil nil
|
||||
nil nil nil nil
|
||||
;; when being enabled/disabled, `chronometrist-goal-minor-mode' will already be t/nil here
|
||||
(if chronometrist-goal-minor-mode (chronometrist-goal-setup) (chronometrist-goal-teardown)))
|
||||
|
||||
|
|
|
@ -0,0 +1,396 @@
|
|||
#+TITLE: chronometrist-goal
|
||||
#+SUBTITLE: Third Time System extension for Chronometrist
|
||||
|
||||
* Explanation
|
||||
** Structure
|
||||
The [[#goal-list][goal-list]] associates each Chronometrist task with a goal.
|
||||
|
||||
Enabling the [[#goal-minor-mode][minor-mode]] sets up hooks to
|
||||
1. display a goal column in the Chronometrist buffer, and
|
||||
2. display alerts about the time spent relative to the defined time goal.
|
||||
|
||||
Alerts are functions which start timers - at the end of the timer, a notification is displayed. Alerts are stored in the custom variable [[#alert-functions][alert-functions]] (used by [[#run-alert-timers][run-alert-timers]] to start the timers). The timers created are stored in [[#timers-list][timers-list]] (used by [[#stop-alert-timers][stop-alert-timers]] to stop the timers).
|
||||
|
||||
* Program source
|
||||
** Library headers and commentary
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
;;; chronometrist-goal.el --- Adds support for time goals to Chronometrist -*- lexical-binding: t; -*-
|
||||
|
||||
;; Author: contrapunctus <xmpp:contrapunctus@jabber.fr>
|
||||
;; Maintainer: contrapunctus <xmpp:contrapunctus@jabber.fr>
|
||||
;; Keywords: calendar
|
||||
;; Homepage: https://tildegit.org/contrapunctus/chronometrist
|
||||
;; Package-Requires: ((emacs "25.1") (alert "1.2") (chronometrist "0.6.0"))
|
||||
;; Version: 0.2.1
|
||||
|
||||
;; 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:
|
||||
;; Add support for time goals to Chronometrist
|
||||
|
||||
;; For information on usage and customization, see https://tildegit.org/contrapunctus/chronometrist-goal/src/branch/production/README.md
|
||||
#+END_SRC
|
||||
|
||||
** Dependencies
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
;;; Code:
|
||||
(require 'chronometrist)
|
||||
(require 'alert)
|
||||
(declare-function chronometrist-last "chronometrist")
|
||||
#+END_SRC
|
||||
|
||||
** goal-list
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: goal-list
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defcustom chronometrist-goal-list nil
|
||||
"List to specify daily time goal for each task.
|
||||
Each element must be in the form (GOAL TASK *).
|
||||
|
||||
GOAL is an integer specifying number of minutes.
|
||||
|
||||
TASK is the task on which you would like spend GOAL time.
|
||||
|
||||
There can be more than one TASK, to specify that you would
|
||||
like to spend GOAL time on any one of those tasks."
|
||||
:group 'chronometrist
|
||||
:type '(repeat
|
||||
(list (integer :value 15)
|
||||
(set :inline t (repeat string)))))
|
||||
#+END_SRC
|
||||
|
||||
** TODO goal-get
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: goal-get
|
||||
:END:
|
||||
TODO - if there are multiple tasks associated with a single time goal (i.e. =(int "task1" "task2" ...)=), and the user has reached the goal for one of those tasks, don't display the goal for the other associated tasks.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(cl-defun chronometrist-goal-get (task &optional (goal-list chronometrist-goal-list))
|
||||
"Return time goal for TASK from GOAL-LIST.
|
||||
Return value is minutes as an integer, or nil.
|
||||
|
||||
If GOAL-LIST is not supplied, `chronometrist-goal-list' is used."
|
||||
(cl-loop for list in goal-list
|
||||
when (member task list)
|
||||
return (car list)))
|
||||
#+END_SRC
|
||||
|
||||
** Alerts
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: Alerts
|
||||
:END:
|
||||
*** timers-list
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: timers-list
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defvar chronometrist-goal--timers-list nil)
|
||||
#+END_SRC
|
||||
|
||||
*** run-at-time
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: run-at-time
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-goal-run-at-time (time repeat function &rest args)
|
||||
"Like `run-at-time', but append timers to `chronometrist-goal--timers-list'.
|
||||
TIME, REPEAT, FUNCTION, and ARGS are as used in `run-at-time'."
|
||||
(->> (apply #'run-at-time time repeat function args)
|
||||
(list)
|
||||
(append chronometrist-goal--timers-list)
|
||||
(setq chronometrist-goal--timers-list)))
|
||||
#+END_SRC
|
||||
|
||||
*** seconds->alert-string
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: seconds->alert-string
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
;; (mapcar #'chronometrist-goal-seconds->alert-string '(0 1 2 59 60 61 62 120 121 122))
|
||||
(defun chronometrist-goal-seconds->alert-string (seconds)
|
||||
"Convert SECONDS to a string suitable for displaying in alerts.
|
||||
SECONDS should be a positive integer."
|
||||
(-let [(h m _) (chronometrist-seconds-to-hms seconds)]
|
||||
(let* ((h-str (unless (zerop h)
|
||||
(number-to-string h)))
|
||||
(m-str (unless (zerop m)
|
||||
(number-to-string m)))
|
||||
(h-unit (cl-case h
|
||||
(0 nil)
|
||||
(1 " hour")
|
||||
(t " hours")))
|
||||
(m-unit (cl-case m
|
||||
(0 nil)
|
||||
(1 " minute")
|
||||
(t " minutes")))
|
||||
(and (if (and h-unit m-unit)
|
||||
" and "
|
||||
"")))
|
||||
(concat h-str h-unit
|
||||
and
|
||||
m-str m-unit))))
|
||||
#+END_SRC
|
||||
|
||||
*** approach-alert
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: approach-alert
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-goal-approach-alert (task goal spent)
|
||||
"Alert the user when they are 5 minutes away from reaching GOAL for TASK.
|
||||
TASK is the name of the current task (as a string).
|
||||
GOAL is the goal time for that task (minutes as an integer).
|
||||
SPENT is the time spent on that task (minutes as an integer)."
|
||||
(and goal
|
||||
(< spent goal)
|
||||
(chronometrist-goal-run-at-time (* 60 (- goal 5 spent)) ;; negative seconds = run now
|
||||
nil
|
||||
(lambda (task)
|
||||
(alert (format "5 minutes remain for %s" task)))
|
||||
task)))
|
||||
#+END_SRC
|
||||
|
||||
*** complete-alert
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: complete-alert
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-goal-complete-alert (task goal spent)
|
||||
"Alert the user when they have reached the GOAL for TASK.
|
||||
TASK is the name of the current task (as a string).
|
||||
GOAL is the goal time for that task (minutes as an integer).
|
||||
SPENT is the time spent on that task (minutes as an integer)."
|
||||
(and goal
|
||||
;; In case the user reaches GOAL but starts tracking again -
|
||||
;; CURRENT is slightly over GOAL, but we notify the user of
|
||||
;; reaching the GOAL anyway.
|
||||
(< spent (+ goal 5))
|
||||
(chronometrist-goal-run-at-time (* 60 (- goal spent)) ;; negative seconds = run now
|
||||
nil
|
||||
(lambda (task)
|
||||
(alert (format "Goal for %s reached" task)))
|
||||
task)))
|
||||
#+END_SRC
|
||||
|
||||
*** exceed-alert
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: exceed-alert
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-goal-exceed-alert (task goal spent)
|
||||
"Alert the user when they have exceeded the GOAL for TASK.
|
||||
TASK is the name of the current task (as a string).
|
||||
GOAL is the goal time for that task (minutes as an integer).
|
||||
SPENT is the time spent on that task (minutes as an integer)."
|
||||
(and goal
|
||||
(chronometrist-goal-run-at-time (* 60 (- (+ goal 5) spent)) ;; negative seconds = run now
|
||||
nil
|
||||
(lambda (task)
|
||||
(alert (format "You are exceeding the goal for %s!" task)
|
||||
:severity 'medium))
|
||||
task)))
|
||||
#+END_SRC
|
||||
|
||||
*** no-goal-alert
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: no-goal-alert
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-goal-no-goal-alert (task goal _spent)
|
||||
"If TASK has no GOAL, regularly remind the user of the time spent on it.
|
||||
TASK is the name of the current task (as a string).
|
||||
GOAL is the goal time for that task (minutes as an integer).
|
||||
SPENT is the time spent on that task (minutes as an integer)."
|
||||
(unless goal
|
||||
(chronometrist-goal-run-at-time (* 15 60) ;; first run after 15 minutes from now
|
||||
(* 15 60) ;; repeat every 15 minutes
|
||||
(lambda (task)
|
||||
;; We cannot use SPENT here, because that will
|
||||
;; remain the value it had when we clocked in
|
||||
;; (when `chronometrist-goal-run-alert-timers'
|
||||
;; is run), and we need show the time spent at
|
||||
;; the time of notification.
|
||||
(alert (format "You have spent %s on %s"
|
||||
(chronometrist-goal-seconds->alert-string
|
||||
(chronometrist-task-time-one-day task))
|
||||
task)))
|
||||
task)))
|
||||
#+END_SRC
|
||||
|
||||
*** alert-functions
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: alert-functions
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defcustom chronometrist-goal-alert-functions
|
||||
'(chronometrist-goal-approach-alert
|
||||
chronometrist-goal-complete-alert
|
||||
chronometrist-goal-exceed-alert
|
||||
chronometrist-goal-no-goal-alert)
|
||||
"List to describe timed alerts.
|
||||
Each element should be a function, which will be called with
|
||||
three arguments - the name of the current task (as a string) and
|
||||
the goal time for that task (minutes as an integer), and the time
|
||||
spent on that task (minutes as an integer).
|
||||
|
||||
Typically, each function in this list should call `run-at-time'
|
||||
to run another function, which in turn should call `alert' to
|
||||
notify the user.
|
||||
|
||||
The timer returned by `run-at-time' should also be appended to
|
||||
`chronometrist-goal--timers-list', so that it can later be stopped by
|
||||
`chronometrist-goal-stop-alert-timers'. `chronometrist-goal-run-at-time'
|
||||
will do that for you.
|
||||
|
||||
Note - the time spent passed to these functions is calculated
|
||||
when `chronometrist-goal-run-alert-timers' is run, i.e. when the
|
||||
user clocks in. To obtain the time spent at the time of
|
||||
notification, use `chronometrist-task-time-one-day' within the
|
||||
function passed to `run-at-time'."
|
||||
:group 'chronometrist
|
||||
:type 'hook)
|
||||
#+END_SRC
|
||||
|
||||
*** run-alert-timers
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: run-alert-timers
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-goal-run-alert-timers (task)
|
||||
"Run timers to alert the user of the time spent on TASK.
|
||||
To use, add this to `chronometrist-after-in-functions', and
|
||||
`chronometrist-goal-stop-alert-timers' to
|
||||
`chronometrist-after-out-functions'."
|
||||
(let ((goal (chronometrist-goal-get task))
|
||||
(spent (/ (chronometrist-task-time-one-day task) 60)))
|
||||
(add-hook 'chronometrist-file-change-hook #'chronometrist-goal-on-file-change)
|
||||
(mapc (lambda (f)
|
||||
(funcall f task goal spent))
|
||||
chronometrist-goal-alert-functions)))
|
||||
#+END_SRC
|
||||
|
||||
*** stop-alert-timers
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: stop-alert-timers
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-goal-stop-alert-timers (&optional _task)
|
||||
"Stop timers to alert the user of the time spent on TASK.
|
||||
To use, add this to `chronometrist-after-out-functions', and
|
||||
`chronometrist-goal-run-alert-timers' to
|
||||
`chronometrist-after-in-functions'."
|
||||
(and chronometrist-goal--timers-list ;; in case of start task -> exit Emacs without stopping -> start Emacs -> stop task
|
||||
(mapc #'cancel-timer chronometrist-goal--timers-list)
|
||||
(setq chronometrist-goal--timers-list nil)))
|
||||
#+END_SRC
|
||||
|
||||
** Minor mode
|
||||
*** on-file-change
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: on-file-change
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-goal-on-file-change ()
|
||||
"Manage timed alerts when `chronometrist-file' changes."
|
||||
(let ((last (chronometrist-latest-record (chronometrist-active-backend))))
|
||||
(chronometrist-goal-stop-alert-timers)
|
||||
;; if there's a task running, start timed alerts for it
|
||||
(unless (plist-get last :stop)
|
||||
(chronometrist-goal-run-alert-timers (plist-get last :name)))))
|
||||
#+END_SRC
|
||||
|
||||
*** row-transformers
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: row-transformers
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-goal-row-transformer (row)
|
||||
"Add a goal cell to ROW.
|
||||
Used to add a goal column to `chronometrist-rows'.
|
||||
|
||||
ROW must be a valid element of the list specified by
|
||||
`tabulated-list-entries'."
|
||||
(-let* (((task vector) row)
|
||||
(goal-minutes (chronometrist-goal-get task))
|
||||
(goal-string (if goal-minutes (format "% 4d" goal-minutes) "")))
|
||||
(list task (vconcat vector `[,goal-string]))))
|
||||
#+END_SRC
|
||||
|
||||
*** schema-transformer
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: schema-transformer
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-goal-schema-transformer (schema)
|
||||
"Add a goal column to SCHEMA.
|
||||
Used to add a goal column to `chronometrist-schema-transformers'.
|
||||
SCHEMA should be a vector as specified by `tabulated-list-format'."
|
||||
(vconcat schema `[("Target" 5 t :pad-right 3)]))
|
||||
#+END_SRC
|
||||
|
||||
*** setup
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: setup
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-goal-setup ()
|
||||
"Add `chronometrist-goal' functions to `chronometrist' hooks."
|
||||
(add-to-list 'chronometrist-row-transformers #'chronometrist-goal-row-transformer)
|
||||
(add-to-list 'chronometrist-schema-transformers #'chronometrist-goal-schema-transformer)
|
||||
(add-hook 'chronometrist-after-in-functions #'chronometrist-goal-run-alert-timers)
|
||||
(add-hook 'chronometrist-after-out-functions #'chronometrist-goal-stop-alert-timers))
|
||||
#+END_SRC
|
||||
|
||||
*** teardown
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: teardown
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-goal-teardown ()
|
||||
"Remove `chronometrist-goal' functions from `chronometrist' hooks."
|
||||
(setq chronometrist-row-transformers
|
||||
(remove #'chronometrist-goal-row-transformer chronometrist-row-transformers)
|
||||
chronometrist-schema-transformers
|
||||
(remove #'chronometrist-goal-schema-transformer chronometrist-schema-transformers))
|
||||
(remove-hook 'chronometrist-after-in-functions #'chronometrist-goal-run-alert-timers)
|
||||
(remove-hook 'chronometrist-after-out-functions #'chronometrist-goal-stop-alert-timers))
|
||||
#+END_SRC
|
||||
|
||||
*** goal-minor-mode
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: goal-minor-mode
|
||||
:END:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(define-minor-mode chronometrist-goal-minor-mode
|
||||
nil nil nil nil
|
||||
;; when being enabled/disabled, `chronometrist-goal-minor-mode' will already be t/nil here
|
||||
(if chronometrist-goal-minor-mode (chronometrist-goal-setup) (chronometrist-goal-teardown)))
|
||||
#+END_SRC
|
||||
|
||||
** Provide
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(provide 'chronometrist-goal)
|
||||
#+END_SRC
|
||||
|
||||
* Local Variables :NOEXPORT:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
;; Local Variables:
|
||||
;; nameless-current-name: "chronometrist-goal"
|
||||
;; End:
|
||||
|
||||
;;; chronometrist-goal.el ends here
|
||||
#+END_SRC
|
||||
|
||||
# Local Variables:
|
||||
# my-org-src-default-lang: "emacs-lisp"
|
||||
# eval: (when (package-installed-p 'literate-elisp) (require 'literate-elisp) (literate-elisp-load (buffer-file-name)))
|
||||
# End:
|
Reference in New Issue