mirror of
https://github.com/vale981/pomm.el
synced 2025-03-05 09:41:42 -05:00
docs: more docs & screenshot
This commit is contained in:
parent
c81204984c
commit
e290e28d99
3 changed files with 68 additions and 36 deletions
23
README.org
23
README.org
|
@ -1,16 +1,16 @@
|
||||||
#+TITLE: pomm.el
|
|
||||||
|
|
||||||
Yet another implementation of a [[https://en.wikipedia.org/wiki/Pomodoro_Technique][pomodoro timer]] for Emacs.
|
Yet another implementation of a [[https://en.wikipedia.org/wiki/Pomodoro_Technique][pomodoro timer]] for Emacs.
|
||||||
|
|
||||||
|
[[./img/screenshot.png]]
|
||||||
|
|
||||||
This particular package features:
|
This particular package features:
|
||||||
- Managing the timer with the excellent [[https://github.com/magit/transient/blob/master/lisp/transient.el][transient.el]].
|
- Managing the timer with the excellent [[https://github.com/magit/transient/blob/master/lisp/transient.el][transient.el]].
|
||||||
- A persistent state between Emacs sessions.
|
- Persistent state between Emacs sessions.
|
||||||
The timer state isn't reset if you close Emacs. Also, the state file can be syncronized between machines.
|
The timer state isn't reset if you close Emacs. Also, the state file can be synchronized between machines.
|
||||||
|
|
||||||
None of the available [[*Alternatives][alternatives]] were doing quite what I wanted, and the idea of the timer is quite simple, so I figured I'd implement one myself.
|
None of the available [[*Alternatives][alternatives]] were doing quite what I wanted, and the idea of the timer is quite simple, so I figured I'd implement one myself.
|
||||||
|
|
||||||
* Setup
|
* Setup
|
||||||
While the package is available only this this repository, one way to install is to clone the repository, add the package to the =load-path= and load it with =require=:
|
While the package is available only in this repository, one way to install is to clone the repository, add the package to the =load-path= and load it with =require=:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(require 'pomm)
|
(require 'pomm)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
@ -22,7 +22,7 @@ My preferred way is =use-package= with =straight.el=:
|
||||||
:commands (pomm))
|
:commands (pomm))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
The package requires Emacs 27.1, because the time API of the previous versions is kinda crazy and 27.1 has =time-convert=.
|
The package requires Emacs 27.1 because the time API of the previous versions is kinda crazy and 27.1 has =time-convert=.
|
||||||
|
|
||||||
** Alerts
|
** Alerts
|
||||||
The package sends alerts via =alert.el=. The default style of alert is a plain =message=, but if you want an actual notification, set =alert-default-style= accordingly:
|
The package sends alerts via =alert.el=. The default style of alert is a plain =message=, but if you want an actual notification, set =alert-default-style= accordingly:
|
||||||
|
@ -40,10 +40,10 @@ If you want the timer to display in the modeline, add the following code to your
|
||||||
(add-hook 'pomm-on-status-changed-hook 'force-mode-line-update)
|
(add-hook 'pomm-on-status-changed-hook 'force-mode-line-update)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
This is quite verbose, but as I don't use this feature, I want to avoid adding an unnecesary load to my Emacs.
|
This is quite verbose, but as I don't use this feature, I want to avoid adding an unnecessary load to my Emacs.
|
||||||
|
|
||||||
** Polybar module
|
** Polybar module
|
||||||
If you want to display the pomodoro status in something like polybar, you can add the following lines to your config:
|
If you want to display the Pomodoro status in something like polybar, you can add the following lines to your config:
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(add-hook 'pomm-on-tick-hook 'pomm-update-mode-line-string)
|
(add-hook 'pomm-on-tick-hook 'pomm-update-mode-line-string)
|
||||||
(add-hook 'pomm-on-status-changed-hook 'pomm-update-mode-line-string)
|
(add-hook 'pomm-on-status-changed-hook 'pomm-update-mode-line-string)
|
||||||
|
@ -64,14 +64,15 @@ exec = /home/pavel/bin/polybar/pomm.sh
|
||||||
interval = 1
|
interval = 1
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
** State file location
|
||||||
|
The package stores the current state to a file by the path =pomm-state-file-location=, which is =emacs.d/pomm= by default. Set it to wherever you like.
|
||||||
* Usage
|
* Usage
|
||||||
Run =M-x pomm= to open the transient buffer.
|
Run =M-x pomm= to open the transient buffer.
|
||||||
|
|
||||||
The listed commands are rather self-descriptive and match the pomodoro ideology.
|
The listed commands are rather self-descriptive and match the Pomodoro ideology.
|
||||||
|
|
||||||
The timer can have 3 states:
|
The timer can have 3 states:
|
||||||
- *Stopped*.
|
- *Stopped*. Can be started with "s" or =M-x pomm-start=. A new iteration of the timer will be started.
|
||||||
Can be started with "s" or =M-x pomm-start=. A new iteration of the timer will be started.
|
|
||||||
- *Paused*. Can be continuted with "s" / =M-x pomm-start= or stopped competely with "S" / =M-x pomm-stop=.
|
- *Paused*. Can be continuted with "s" / =M-x pomm-start= or stopped competely with "S" / =M-x pomm-stop=.
|
||||||
- *Running*. Can be paused with "p" / =M-x pomm-pause= or stopped with "S" / =M-x pomm-stop=.
|
- *Running*. Can be paused with "p" / =M-x pomm-pause= or stopped with "S" / =M-x pomm-stop=.
|
||||||
|
|
||||||
|
|
BIN
img/screenshot.png
Normal file
BIN
img/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 287 KiB |
81
pomm.el
81
pomm.el
|
@ -25,7 +25,16 @@
|
||||||
|
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
|
|
||||||
;; TODO
|
;; An implementation of a Pomodoro timer for Emacs. Distintive features
|
||||||
|
;; of this particular implementation:
|
||||||
|
;; - Managing the timer with transient.el (`pomm' command)
|
||||||
|
;; - Persistent state between Emacs sessions.
|
||||||
|
;; So one could close & reopen Emacs without interruption the timer.
|
||||||
|
;;
|
||||||
|
;; Take a look at `pomm-update-mode-line-string' on how to setup this
|
||||||
|
;; package with a modeline.
|
||||||
|
;; Also take a look at README at
|
||||||
|
;; <https://github.com/SqrtMinusOne/pomm.el> for more information.
|
||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
(require 'alert)
|
(require 'alert)
|
||||||
|
@ -86,7 +95,7 @@
|
||||||
(defcustom pomm-history-reset-hour 0
|
(defcustom pomm-history-reset-hour 0
|
||||||
"An hour on which the history will be reset.
|
"An hour on which the history will be reset.
|
||||||
|
|
||||||
Whenever the pomodoro timer is intializing, it will try to read the
|
Whenever the Pomodoro timer is initializing, it will try to read the
|
||||||
state file from `pomm-state-file-location'. If there are records that
|
state file from `pomm-state-file-location'. If there are records that
|
||||||
were made before this hour, they will be cleared, so that the history
|
were made before this hour, they will be cleared, so that the history
|
||||||
contains records only from the current day."
|
contains records only from the current day."
|
||||||
|
@ -94,7 +103,7 @@ contains records only from the current day."
|
||||||
:type 'integer)
|
:type 'integer)
|
||||||
|
|
||||||
(defcustom pomm-remaining-time-format "%m:%.2s"
|
(defcustom pomm-remaining-time-format "%m:%.2s"
|
||||||
"Format the time, remaining in the period.
|
"Format the time remaining in the period.
|
||||||
|
|
||||||
The format is the same as in `format-seconds'"
|
The format is the same as in `format-seconds'"
|
||||||
:group 'pomm
|
:group 'pomm
|
||||||
|
@ -106,31 +115,36 @@ The format is the same as in `format-seconds'"
|
||||||
:type 'hook)
|
:type 'hook)
|
||||||
|
|
||||||
(defcustom pomm-on-status-changed-hook nil
|
(defcustom pomm-on-status-changed-hook nil
|
||||||
"A hook to run on status change."
|
"A hook to run on a status change."
|
||||||
|
:group 'pomm
|
||||||
|
:type 'hook)
|
||||||
|
|
||||||
|
(defcustom pomm-on-period-changed-hook nil
|
||||||
|
"A hook to run on a period status change."
|
||||||
:group 'pomm
|
:group 'pomm
|
||||||
:type 'hook)
|
:type 'hook)
|
||||||
|
|
||||||
(defvar pomm--state nil
|
(defvar pomm--state nil
|
||||||
"Current state of pomm.el.
|
"The current state of pomm.el.
|
||||||
|
|
||||||
This is an alist of with the following keys:
|
This is an alist of with the following keys:
|
||||||
- status: either 'stopped, 'paused or 'running
|
- status: either 'stopped, 'paused or 'running
|
||||||
- current: an alist with a current period
|
- current: an alist with a current period
|
||||||
- history: a list with today's history
|
- history: a list with today's history
|
||||||
- last-changed-time: a timestamp of a last change in status
|
- last-changed-time: a timestamp of the last change in status
|
||||||
|
|
||||||
Current period is also an alist with the following keys:
|
'current is also an alist with the following keys:
|
||||||
- kind: either 'short-break, 'long-break or 'work
|
- kind: either 'short-break, 'long-break or 'work
|
||||||
- start-time: start timestamp
|
- start-time: start timestamp
|
||||||
- effective-start-time: start timestamp, corrected for pauses
|
- effective-start-time: start timestamp, corrected for pauses
|
||||||
- iteration: number the current pomodoro iteration
|
- iteration: number the current Pomodoro iteration
|
||||||
|
|
||||||
History is a list of alists with the following keys:
|
History is a list of alists 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
|
||||||
- paused-time: time spent it a paused state")
|
- paused-time: time spent in a paused state")
|
||||||
|
|
||||||
(defvar pomm--timer nil
|
(defvar pomm--timer nil
|
||||||
"A variable for the pomm timer.")
|
"A variable for the pomm timer.")
|
||||||
|
@ -155,9 +169,9 @@ Updated by `pomm-update-mode-line-string'.")
|
||||||
(setf (alist-get 'status pomm--state) 'stopped))
|
(setf (alist-get 'status pomm--state) 'stopped))
|
||||||
|
|
||||||
(defun pomm--init-state ()
|
(defun pomm--init-state ()
|
||||||
"Initialize the pomodoro timer state.
|
"Initialize the Pomodoro timer state.
|
||||||
|
|
||||||
This function has to be run only once, at the first start of the timer."
|
This function is meant to be ran only once, at the first start of the timer."
|
||||||
(add-hook 'pomm-on-status-changed-hook #'pomm--save-state)
|
(add-hook 'pomm-on-status-changed-hook #'pomm--save-state)
|
||||||
(if (or (not (file-exists-p pomm-state-file-location))
|
(if (or (not (file-exists-p pomm-state-file-location))
|
||||||
(not pomm-state-file-location))
|
(not pomm-state-file-location))
|
||||||
|
@ -171,13 +185,13 @@ This function has to be run only once, at the first start of the timer."
|
||||||
(pomm--cleanup-old-history))
|
(pomm--cleanup-old-history))
|
||||||
|
|
||||||
(defun pomm--save-state ()
|
(defun pomm--save-state ()
|
||||||
"Save the current pomodoro timer state."
|
"Save the current Pomodoro timer state."
|
||||||
(when pomm-state-file-location
|
(when pomm-state-file-location
|
||||||
(with-temp-file pomm-state-file-location
|
(with-temp-file pomm-state-file-location
|
||||||
(insert (prin1-to-string pomm--state)))))
|
(insert (prin1-to-string pomm--state)))))
|
||||||
|
|
||||||
(defun pomm--cleanup-old-history ()
|
(defun pomm--cleanup-old-history ()
|
||||||
"Clear history of previous days from the pomodoro timer."
|
"Clear history of previous days from the Pomodoro timer."
|
||||||
(let ((cleanup-time (decode-time)))
|
(let ((cleanup-time (decode-time)))
|
||||||
(setf (decoded-time-second cleanup-time) 0
|
(setf (decoded-time-second cleanup-time) 0
|
||||||
(decoded-time-minute cleanup-time) 0
|
(decoded-time-minute cleanup-time) 0
|
||||||
|
@ -191,7 +205,7 @@ This function has to be run only once, at the first start of the timer."
|
||||||
(alist-get 'history pomm--state))))))
|
(alist-get 'history pomm--state))))))
|
||||||
|
|
||||||
(defun pomm-reset ()
|
(defun pomm-reset ()
|
||||||
"Reset the pomodoro timer."
|
"Reset the Pomodoro timer."
|
||||||
(interactive)
|
(interactive)
|
||||||
(when (y-or-n-p "Are you sure you want to reset the Pomodoro timer? ")
|
(when (y-or-n-p "Are you sure you want to reset the Pomodoro timer? ")
|
||||||
(pomm--do-reset)))
|
(pomm--do-reset)))
|
||||||
|
@ -208,7 +222,7 @@ KIND is the same as in `pomm--state'"
|
||||||
:title "Pomodoro"))
|
:title "Pomodoro"))
|
||||||
|
|
||||||
(defun pomm--new-iteration ()
|
(defun pomm--new-iteration ()
|
||||||
"Start a new iteration of the pomodoro timer."
|
"Start a new iteration of the Pomodoro timer."
|
||||||
(setf (alist-get 'current pomm--state)
|
(setf (alist-get 'current pomm--state)
|
||||||
`((kind . work)
|
`((kind . work)
|
||||||
(start-time . ,(time-convert nil 'integer))
|
(start-time . ,(time-convert nil 'integer))
|
||||||
|
@ -224,7 +238,7 @@ KIND is the same as in `pomm--state'"
|
||||||
(pomm--dispatch-notification 'work))
|
(pomm--dispatch-notification 'work))
|
||||||
|
|
||||||
(defun pomm--get-kind-length (kind)
|
(defun pomm--get-kind-length (kind)
|
||||||
"Get a length of period KIND in seconds."
|
"Get the length of a period of type KIND in seconds."
|
||||||
(* 60
|
(* 60
|
||||||
(pcase kind
|
(pcase kind
|
||||||
('short-break pomm-short-break-period)
|
('short-break pomm-short-break-period)
|
||||||
|
@ -242,7 +256,7 @@ The condition is: (effective-start-time + length) < now."
|
||||||
(time-convert nil 'integer)))
|
(time-convert nil 'integer)))
|
||||||
|
|
||||||
(defun pomm--store-current-to-history ()
|
(defun pomm--store-current-to-history ()
|
||||||
"Store the current pomodoro state to the history."
|
"Store the current pomodoro period to the history list."
|
||||||
(let* ((current-kind (alist-get 'kind (alist-get 'current pomm--state)))
|
(let* ((current-kind (alist-get 'kind (alist-get 'current pomm--state)))
|
||||||
(current-iteration (alist-get 'iteration (alist-get 'current pomm--state)))
|
(current-iteration (alist-get 'iteration (alist-get 'current pomm--state)))
|
||||||
(start-time (alist-get 'start-time (alist-get 'current pomm--state)))
|
(start-time (alist-get 'start-time (alist-get 'current pomm--state)))
|
||||||
|
@ -292,7 +306,8 @@ The condition is: (effective-start-time + length) < now."
|
||||||
(pomm--dispatch-notification next-kind))
|
(pomm--dispatch-notification next-kind))
|
||||||
(setf (alist-get 'current pomm--state) nil)
|
(setf (alist-get 'current pomm--state) nil)
|
||||||
(setf (alist-get 'status pomm--state) 'stopped))
|
(setf (alist-get 'status pomm--state) 'stopped))
|
||||||
(pomm--save-state)))
|
(pomm--save-state)
|
||||||
|
(run-hooks 'pomm-on-status-changed-hook)))
|
||||||
|
|
||||||
(defun pomm--on-tick ()
|
(defun pomm--on-tick ()
|
||||||
"A function to be ran on a timer tick."
|
"A function to be ran on a timer tick."
|
||||||
|
@ -345,7 +360,7 @@ paused-time := now - last-changed-time"
|
||||||
|
|
||||||
This sets the variable `pomm-current-mode-line-string' with a value
|
This sets the variable `pomm-current-mode-line-string' with a value
|
||||||
from `pomm-format-mode-line'. This is made so to minimize the load on
|
from `pomm-format-mode-line'. This is made so to minimize the load on
|
||||||
the modeline, because otherwise updates may be quite frequent.
|
the modeline, because otherwise the updates may be quite frequent.
|
||||||
|
|
||||||
To add this to the modeline, add the following code to your config:
|
To add this to the modeline, add the following code to your config:
|
||||||
\(add-to-list 'mode-line-misc-info '\(:eval pomm-current-mode-line-string\)')
|
\(add-to-list 'mode-line-misc-info '\(:eval pomm-current-mode-line-string\)')
|
||||||
|
@ -499,7 +514,7 @@ The class doesn't actually have any value, but this is necessary for transient."
|
||||||
"Format the history list for the transient buffer."
|
"Format the history list for the transient buffer."
|
||||||
(if (not (alist-get 'history pomm--state))
|
(if (not (alist-get 'history pomm--state))
|
||||||
"No history yet"
|
"No history yet"
|
||||||
(let ((previous-iteration -1))
|
(let ((previous-iteration 1000))
|
||||||
(mapconcat
|
(mapconcat
|
||||||
(lambda (item)
|
(lambda (item)
|
||||||
(let ((kind (alist-get 'kind item))
|
(let ((kind (alist-get 'kind item))
|
||||||
|
@ -508,8 +523,13 @@ The class doesn't actually have any value, but this is necessary for transient."
|
||||||
(end-time (alist-get 'end-time item))
|
(end-time (alist-get 'end-time item))
|
||||||
(paused-time (alist-get 'paused-time item)))
|
(paused-time (alist-get 'paused-time item)))
|
||||||
(concat
|
(concat
|
||||||
(if (> iteration previous-iteration)
|
(if (< iteration previous-iteration)
|
||||||
(progn (setq previous-iteration iteration) "\n") "")
|
(let ((is-first (= previous-iteration 1000)))
|
||||||
|
(setq previous-iteration iteration)
|
||||||
|
(if is-first
|
||||||
|
""
|
||||||
|
"\n"))
|
||||||
|
"")
|
||||||
(format "[%02d] " iteration)
|
(format "[%02d] " iteration)
|
||||||
(propertize
|
(propertize
|
||||||
(format "%12s " (upcase (symbol-name kind)))
|
(format "%12s " (upcase (symbol-name kind)))
|
||||||
|
@ -523,7 +543,7 @@ The class doesn't actually have any value, but this is necessary for transient."
|
||||||
(transient-define-infix pomm--transient-history-suffix ()
|
(transient-define-infix pomm--transient-history-suffix ()
|
||||||
:class 'pomm--transient-history
|
:class 'pomm--transient-history
|
||||||
;; A dummy key. Seems to be necessary for transient.
|
;; A dummy key. Seems to be necessary for transient.
|
||||||
;; Just don't press ~ while in buffer.
|
;; Just don't press ~ while in the buffer.
|
||||||
:key "~~1")
|
:key "~~1")
|
||||||
|
|
||||||
(transient-define-infix pomm--transient-current-suffix ()
|
(transient-define-infix pomm--transient-current-suffix ()
|
||||||
|
@ -557,9 +577,20 @@ The class doesn't actually have any value, but this is necessary for transient."
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun pomm ()
|
(defun pomm ()
|
||||||
"A Pomodoro timer.
|
"A Pomodoro technique timer.
|
||||||
|
|
||||||
This command initialized the state of timer and triggers the transient buffer."
|
This command initializes the timer and triggers the transient buffer.
|
||||||
|
|
||||||
|
The timer can have 3 states:
|
||||||
|
- Stopped.
|
||||||
|
Can be started with 's' or `pomm-start'. A new iteration of the
|
||||||
|
timer will be started.
|
||||||
|
- Paused.
|
||||||
|
Can be continuted with 's' / `pomm-start' or stopped competely with
|
||||||
|
'S' / `pomm-stop'.
|
||||||
|
- Running.
|
||||||
|
Can be paused with 'p' / `pomm-pause' or stopped with 'S' /
|
||||||
|
`pomm-stop'."
|
||||||
(interactive)
|
(interactive)
|
||||||
(unless pomm--state
|
(unless pomm--state
|
||||||
(pomm--init-state))
|
(pomm--init-state))
|
||||||
|
|
Loading…
Add table
Reference in a new issue