mirror of
https://github.com/SqrtMinusOne/pomm.el.git
synced 2025-12-10 14:43:03 +03:00
feat: first version of third time transient
This commit is contained in:
parent
2f95a2a1c5
commit
1691d36473
1 changed files with 231 additions and 7 deletions
|
|
@ -31,6 +31,8 @@
|
||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
(require 'pomm)
|
(require 'pomm)
|
||||||
|
(require 'alert)
|
||||||
|
(require 'transient)
|
||||||
(require 'calc)
|
(require 'calc)
|
||||||
|
|
||||||
(defgroup pomm-third-time nil
|
(defgroup pomm-third-time nil
|
||||||
|
|
@ -88,7 +90,8 @@ This is an alist with the following keys:
|
||||||
- kind: same as in 'current
|
- kind: same as in 'current
|
||||||
- iteration
|
- iteration
|
||||||
- start-time: start timestamp
|
- start-time: start timestamp
|
||||||
- end-time: end timestamp")
|
- end-time: end timestamp
|
||||||
|
- context: context")
|
||||||
|
|
||||||
(defvar pomm-third-time--timer nil
|
(defvar pomm-third-time--timer nil
|
||||||
"A variable for the Third Time timer.")
|
"A variable for the Third Time timer.")
|
||||||
|
|
@ -162,11 +165,30 @@ This is an alist with the following keys:
|
||||||
(pomm--maybe-play-sound
|
(pomm--maybe-play-sound
|
||||||
(alist-get 'kind (alist-get 'current pomm-third-time--state))))))
|
(alist-get 'kind (alist-get 'current pomm-third-time--state))))))
|
||||||
|
|
||||||
|
(defun pomm-third-time--calc-eval (value)
|
||||||
|
"Convert VALUE to number.
|
||||||
|
|
||||||
|
If VALUE is not a string, return it.
|
||||||
|
|
||||||
|
Otherwise, try to evaluate with `calc-eval'. If unsuccessful, return
|
||||||
|
calc error. If the result is numeric, convert it to number and return
|
||||||
|
it, otherwise, return a list with an error."
|
||||||
|
(if (stringp value)
|
||||||
|
(let ((res (calc-eval value)))
|
||||||
|
(if (listp res)
|
||||||
|
res
|
||||||
|
(if (string-match-p (rx (+ num) (? (: "." (* num)))) value)
|
||||||
|
(string-to-number res)
|
||||||
|
(list nil (format "Can't parse number: %s" res)))))
|
||||||
|
value))
|
||||||
|
|
||||||
(defun pomm-third-time--fraction ()
|
(defun pomm-third-time--fraction ()
|
||||||
"Get fraction of break time to work time."
|
"Get fraction of break time to work time."
|
||||||
(if (stringp pomm-third-time-fraction)
|
(let ((parsed (pomm-third-time--calc-eval
|
||||||
(string-to-number (calc-eval pomm-third-time-fraction))
|
pomm-third-time-fraction)))
|
||||||
pomm-third-time-fraction))
|
(if (listp parsed)
|
||||||
|
(user-error "Error in `pomm-third-time-fraction': %s" (card parsed))
|
||||||
|
parsed)))
|
||||||
|
|
||||||
(defun pomm-third-time--current-period-time ()
|
(defun pomm-third-time--current-period-time ()
|
||||||
"Get the time spent in the current period."
|
"Get the time spent in the current period."
|
||||||
|
|
@ -200,11 +222,14 @@ This is an alist with the following keys:
|
||||||
(current-start-time (alist-get 'start-time
|
(current-start-time (alist-get 'start-time
|
||||||
(alist-get 'current pomm-third-time--state)))
|
(alist-get 'current pomm-third-time--state)))
|
||||||
(current-iteration (alist-get 'iteration
|
(current-iteration (alist-get 'iteration
|
||||||
(alist-get 'current pomm-third-time--state))) )
|
(alist-get 'current pomm-third-time--state)))
|
||||||
|
(current-context (alist-get 'context pomm-third-time--state)))
|
||||||
(when current-kind
|
(when current-kind
|
||||||
(push `((kind . ,current-kind)
|
(push `((kind . ,current-kind)
|
||||||
(start-time . ,current-start-time)
|
(start-time . ,current-start-time)
|
||||||
(end-time . ,(time-convert nil 'integer)))
|
(end-time . ,(time-convert nil 'integer))
|
||||||
|
(iteration . ,current-iteration)
|
||||||
|
(context . ,current-context))
|
||||||
(alist-get 'history pomm-third-time--state)))))
|
(alist-get 'history pomm-third-time--state)))))
|
||||||
|
|
||||||
(defun pomm-third-time--format-period (seconds)
|
(defun pomm-third-time--format-period (seconds)
|
||||||
|
|
@ -239,12 +264,12 @@ KIND is the same as in `pomm--state'"
|
||||||
(next-kind (pcase current-kind
|
(next-kind (pcase current-kind
|
||||||
('work 'break)
|
('work 'break)
|
||||||
('break 'work))))
|
('break 'work))))
|
||||||
|
(pomm-third-time--store-current-to-history)
|
||||||
(setf (alist-get 'current pomm-third-time--state)
|
(setf (alist-get 'current pomm-third-time--state)
|
||||||
`((kind . ,next-kind)
|
`((kind . ,next-kind)
|
||||||
(start-time . ,(time-convert nil 'integer))
|
(start-time . ,(time-convert nil 'integer))
|
||||||
(break-time-bank . ,break-time)
|
(break-time-bank . ,break-time)
|
||||||
(iteration . ,iteration)))
|
(iteration . ,iteration)))
|
||||||
(pomm-third-time--store-current-to-history)
|
|
||||||
(pomm-third-time--dispatch-notification next-kind)
|
(pomm-third-time--dispatch-notification next-kind)
|
||||||
(pomm-third-time--save-state)
|
(pomm-third-time--save-state)
|
||||||
(run-hooks 'pomm-third-time-on-status-changed-hook)))
|
(run-hooks 'pomm-third-time-on-status-changed-hook)))
|
||||||
|
|
@ -345,5 +370,204 @@ Take a look at the `pomm-third-time' function for more details."
|
||||||
(remove-hook 'pomm-third-time-on-status-changed-hook #'pomm-third-time-update-mode-string)
|
(remove-hook 'pomm-third-time-on-status-changed-hook #'pomm-third-time-update-mode-string)
|
||||||
(remove-hook 'pomm-third-time-on-status-changed-hook #'force-mode-line-update)))
|
(remove-hook 'pomm-third-time-on-status-changed-hook #'force-mode-line-update)))
|
||||||
|
|
||||||
|
(defun pomm-third-time-set-context ()
|
||||||
|
"Set the current context for the Third Time timer."
|
||||||
|
(interactive)
|
||||||
|
(setf (alist-get 'context pomm-third-time--state)
|
||||||
|
(prin1-to-string (read-minibuffer "Context: " (current-word)))))
|
||||||
|
|
||||||
|
(defun pomm-third-time-start-with-context ()
|
||||||
|
"Prompt for context call call `pomm-third-time-start'."
|
||||||
|
(interactive)
|
||||||
|
(pomm-third-time-set-context)
|
||||||
|
(pomm-third-time-start))
|
||||||
|
|
||||||
|
;;;; Transient
|
||||||
|
(defun pomm-third-time--completing-read-calc ()
|
||||||
|
(let ((res (completing-read
|
||||||
|
"Time: "
|
||||||
|
(lambda (string fun flag)
|
||||||
|
(when (eq flag 'metadata)
|
||||||
|
(let ((res (pomm-third-time--calc-eval string)))
|
||||||
|
(if (listp res)
|
||||||
|
(message (nth 1 res))
|
||||||
|
(message "%f" res))))))))
|
||||||
|
(let ((eval-res (pomm-third-time--calc-eval res)))
|
||||||
|
(if (listp eval-res)
|
||||||
|
(user-error "Bad value: %s" (nth 1 eval-res))
|
||||||
|
res))))
|
||||||
|
|
||||||
|
(transient-define-infix pomm-third-time--set-fraction ()
|
||||||
|
:class 'transient-lisp-variable
|
||||||
|
:variable 'pomm-third-time-fraction
|
||||||
|
:key "-f"
|
||||||
|
:description "Fraction of break time to work time:"
|
||||||
|
:reader (lambda (&rest _)
|
||||||
|
(let ((current-value pomm-third-time-fraction))
|
||||||
|
(condition-case error
|
||||||
|
(pomm-third-time--completing-read-calc)
|
||||||
|
(error (progn
|
||||||
|
(message "%s" error)
|
||||||
|
current-value))))))
|
||||||
|
|
||||||
|
(transient-define-infix pomm-third-time-set-reset-context-on-iteration-end ()
|
||||||
|
:class 'pomm--transient-lisp-variable-switch
|
||||||
|
:variable 'pomm-reset-context-on-iteration-end
|
||||||
|
:argument "--context-reset"
|
||||||
|
:key "-r"
|
||||||
|
:description "Reset the context on the interation end")
|
||||||
|
|
||||||
|
(defclass pomm-third-time--set-context-infix (transient-variable)
|
||||||
|
((transient :initform 'transient--do-call)
|
||||||
|
(always-read :initform t)))
|
||||||
|
|
||||||
|
(cl-defmethod transient-init-value ((_ pomm-third-time--set-context-infix))
|
||||||
|
(alist-get 'context pomm-third-time--state))
|
||||||
|
|
||||||
|
(cl-defmethod transient-infix-set ((_ pomm-third-time--set-context-infix) value)
|
||||||
|
(setf (alist-get 'context pomm-third-time--state) value))
|
||||||
|
|
||||||
|
(cl-defmethod transient-prompt ((_ pomm-third-time--set-context-infix))
|
||||||
|
"Set context: ")
|
||||||
|
|
||||||
|
(cl-defmethod transient-format-value ((_ pomm-third-time--set-context-infix))
|
||||||
|
(propertize (if-let (val (alist-get 'context pomm-third-time--state))
|
||||||
|
(prin1-to-string val)
|
||||||
|
"unset")
|
||||||
|
'face 'transient-value))
|
||||||
|
|
||||||
|
(transient-define-infix pomm-third-time--set-context ()
|
||||||
|
:class 'pomm-third-time--set-context-infix
|
||||||
|
:key "-c"
|
||||||
|
:description "Context:")
|
||||||
|
|
||||||
|
(defclass pomm-third-time--transient-current (transient-suffix)
|
||||||
|
((transient :initform t))
|
||||||
|
"A transient class to display the current state of the timer.")
|
||||||
|
|
||||||
|
(cl-defmethod transient-init-value ((_ pomm-third-time--transient-current))
|
||||||
|
"A dummy method for `pomm-third-time--transient-current'.
|
||||||
|
|
||||||
|
The class doesn't actually have any value, but this is necessary for transient."
|
||||||
|
nil)
|
||||||
|
|
||||||
|
(defun pomm-third-time--get-kind-face (kind)
|
||||||
|
"Get a face for a KIND of period.
|
||||||
|
|
||||||
|
KIND is the same as in `pomm-third-time--state'"
|
||||||
|
(pcase kind
|
||||||
|
('work 'success)
|
||||||
|
('break 'error)))
|
||||||
|
|
||||||
|
(cl-defmethod transient-format ((_ pomm-third-time--transient-current))
|
||||||
|
"Format the state of the Third Time timer."
|
||||||
|
(let ((status (alist-get 'status pomm-third-time--state)))
|
||||||
|
(if (or (eq 'stopped status) (not (alist-get 'current pomm-third-time--state)))
|
||||||
|
"The timer is not running"
|
||||||
|
(let ((kind (alist-get 'kind (alist-get 'current pomm-third-time--state)))
|
||||||
|
(start-time (alist-get 'start-time
|
||||||
|
(alist-get 'current pomm-third-time--state)))
|
||||||
|
(iteration (alist-get 'iteration
|
||||||
|
(alist-get 'current pomm-third-time--state)))
|
||||||
|
(break-time (pomm-third-time--break-time))
|
||||||
|
(period-time (pomm-third-time--current-period-time)))
|
||||||
|
(concat
|
||||||
|
(format "Iteration #%d. " iteration)
|
||||||
|
"State: "
|
||||||
|
(propertize
|
||||||
|
(upcase (symbol-name kind))
|
||||||
|
'face
|
||||||
|
(pomm-third-time--get-kind-face kind))
|
||||||
|
". Time: "
|
||||||
|
(propertize
|
||||||
|
(pomm-third-time--format-period period-time)
|
||||||
|
'face 'success)
|
||||||
|
" (started at "
|
||||||
|
(propertize
|
||||||
|
(format-time-string "%H:%M:%S" (seconds-to-time start-time))
|
||||||
|
'face 'success)
|
||||||
|
"). Available break time: "
|
||||||
|
(propertize
|
||||||
|
(pomm-third-time--format-period break-time)
|
||||||
|
'face 'success))))))
|
||||||
|
|
||||||
|
(defclass pomm-third-time--transient-history (transient-suffix)
|
||||||
|
((transient :initform t))
|
||||||
|
"A transient class to display the history of the pomodoro timer.")
|
||||||
|
|
||||||
|
(cl-defmethod transient-init-value ((_ pomm-third-time--transient-history))
|
||||||
|
"A dummy method for `pomm-third-time--transient-history'.
|
||||||
|
|
||||||
|
The class doesn't actually have any value, but this is necessary for transient."
|
||||||
|
nil)
|
||||||
|
|
||||||
|
(cl-defmethod transient-format ((_ pomm-third-time--transient-history))
|
||||||
|
"Format the history list for the transient buffer"
|
||||||
|
(if (not (alist-get 'history pomm-third-time--state))
|
||||||
|
"No history yet"
|
||||||
|
(let ((previous-iteration 1000))
|
||||||
|
(mapconcat
|
||||||
|
(lambda (item)
|
||||||
|
(let ((kind (alist-get 'kind item))
|
||||||
|
(iteration (alist-get 'iteration item))
|
||||||
|
(start-time (alist-get 'start-time item))
|
||||||
|
(end-time (alist-get 'end-time item))
|
||||||
|
(context (alist-get 'context item)))
|
||||||
|
(concat
|
||||||
|
(if (< iteration previous-iteration)
|
||||||
|
(let ((is-first (= previous-iteration 1000)))
|
||||||
|
(setq previous-iteration iteration)
|
||||||
|
(if is-first
|
||||||
|
""
|
||||||
|
"\n"))
|
||||||
|
"")
|
||||||
|
(format "[%02d] " iteration)
|
||||||
|
(propertize
|
||||||
|
(format "%12s " (upcase (symbol-name kind)))
|
||||||
|
'face (pomm-third-time--get-kind-face kind))
|
||||||
|
(format-time-string "%H:%M" (seconds-to-time start-time))
|
||||||
|
"-"
|
||||||
|
(format-time-string "%H:%M" (seconds-to-time end-time))
|
||||||
|
(if context
|
||||||
|
(format " : %s" (propertize context 'face 'transient-value))
|
||||||
|
""))))
|
||||||
|
(alist-get 'history pomm-third-time--state)
|
||||||
|
"\n"))))
|
||||||
|
|
||||||
|
(transient-define-infix pomm-third-time--transient-current-suffix ()
|
||||||
|
:class 'pomm-third-time--transient-current
|
||||||
|
:key "~~2")
|
||||||
|
|
||||||
|
(transient-define-infix pomm-third-time--transient-history-suffix ()
|
||||||
|
:class 'pomm-third-time--transient-history
|
||||||
|
:key "~~1")
|
||||||
|
|
||||||
|
(transient-define-prefix pomm-third-time-transient ()
|
||||||
|
["Timer settings"
|
||||||
|
(pomm-third-time--set-fraction)]
|
||||||
|
["Context settings"
|
||||||
|
(pomm-third-time--set-context)
|
||||||
|
(pomm-third-time-set-reset-context-on-iteration-end)]
|
||||||
|
["Commands"
|
||||||
|
:class transient-row
|
||||||
|
("s" "Start the timer" pomm-third-time-start :transient t)
|
||||||
|
("S" "Stop the timer" pomm-third-time-stop :transient t)
|
||||||
|
("b" "Switch work/break" pomm-third-time-switch :transient t)
|
||||||
|
("R" "Reset" pomm-third-time-reset :transient t)
|
||||||
|
("u" "Update" pomm--transient-update :transient t)
|
||||||
|
("q" "Quit" transient-quit-one)]
|
||||||
|
["Status"
|
||||||
|
(pomm-third-time--transient-current-suffix)]
|
||||||
|
["History"
|
||||||
|
(pomm-third-time--transient-history-suffix)])
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun pomm-third-time ()
|
||||||
|
"TODO"
|
||||||
|
(interactive)
|
||||||
|
(unless pomm-third-time--state
|
||||||
|
(pomm-third-time--init-state))
|
||||||
|
(call-interactively #'pomm-third-time-transient))
|
||||||
|
|
||||||
(provide 'pomm-third-time)
|
(provide 'pomm-third-time)
|
||||||
;;; pomm-third-time.el ends here
|
;;; pomm-third-time.el ends here
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue