#+title: Change log of TMR
#+author: Protesilaos
#+email: info@protesilaos.com
#+options: ':nil toc:nil num:nil author:nil email:nil
#+startup: content

This document contains the release notes for each tagged commit on the
project's main git repository: <https://github.com/protesilaos/tmr>.

The newest release is at the top.  For further details, please consult
the manual: <https://protesilaos.com/emacs/tmr>.

#+toc: headlines 1 insert TOC here, with one headline level

* Version 1.4.0 on 2026-07-31
:PROPERTIES:
:CUSTOM_ID: h:66b13018-8365-4a7d-877e-bd7768265fe9
:END:

TMR is an efficient package that has been stable for years. This new
version introduces some nice new features as well as several smaller
internal refinements.

** Create a timer that repeats
:PROPERTIES:
:CUSTOM_ID: h:3b3d827a-eb83-4a84-a448-d4e46f884dff
:END:

The command ~tmr-repeat~ prompts for a duration, like the standard
~tmr~ command but also asks for a number of times to repeat the given
timer. When called with a prefix argument (=C-u= with default
keybindings), ~tmr-repeat~ will also ask for a description for the new
timer and whether it should be acknowledged or not after all
repetitions have elapsed.

Thanks to Óscar Fuentes for contributing the original implementation
of ~tmr-repeat~ (with many extra changes/features by me). This was
done in pull request 16: <https://github.com/protesilaos/tmr/pull/16>.
Óscar has assigned copyright to the Free Software Foundation.

** Modify the repeat count of an existing timer
:PROPERTIES:
:CUSTOM_ID: h:c866acef-4fd9-49da-893e-c3489d264b52
:END:

The command ~tmr-edit-repeat-count~ prompts for an existing timer and
updates its repeat count. If the repeat count is set to =0=, then the
timer is no longer considered repeatable.

As with all commands that operate on existing timers, ~tmr-edit-repeat-count~
automatically applies to the timer at point when called from inside
the tabulated list of timers (per ~tmr-tabulated-view~).

Modifying a timer's repeat count does not start a new timer. It simply
updates the relevant data. Use the command ~tmr-clone~ to start a new
timer using the data of an existing timer.

** The tabulated view has more columns and all of them can be adjusted
:PROPERTIES:
:CUSTOM_ID: h:0cdf33c6-2669-4b35-a8c3-89a7bf9f979c
:END:

The tabulated list of timers, which is typically produced by the
command ~tmr-tabulated-view~, now has extra columns for the data that
pertains to repeatable timers.

Users who want to control which columns are displayed, and in what
order, can modify the user option ~tmr-tabulated-columns~. Its
documentation covers the technicalities. The default value is to
display all columns.

** Completion metadata for the prompt that selects a timer
:PROPERTIES:
:CUSTOM_ID: h:0d465855-5f3c-4828-b4a9-9b55a174f143
:END:

Advanced users can now modify all the ~completion-metadata~ associated
with the prompt that reads/selects one among the existing timer
objects (the function is ~tmr-read-timer~). The relevant variable is
~tmr-completion-metadata~. I am not providing this as a user option,
because regular users will anyway not be able to do much with it as it
involves custom functions.

** Timers in the completion prompt are sorted by end time
:PROPERTIES:
:CUSTOM_ID: h:6002d40b-c6b8-47f7-89cd-ad5724a41a0f
:END:

The prompt for selecting a timer now sorts candidates by their end
time. The closest end time appears at the top.

This affects all commands that operate on a timer, such as
~tmr-edit-repeat-count~, ~tmr-cancel~, and more.

In the past, there was no sorting whatsoever. Users who prefer that
style can add the following to their configuration:

#+begin_src emacs-lisp
(setq tmr-completion-metadata
      (list
       (cons 'category 'tmr-timer)
       (cons 'display-sort-function #'identity) ; THIS IS THE RELEVANT PART
       (cons 'annotation-function #'tmr-completion-annotate)))
#+end_src

** Miscellaneous
:PROPERTIES:
:CUSTOM_ID: h:14a7d873-3069-478f-9136-f603eefb75ee
:END:

- The manual is easier to read. I have rewritten it to group commands
  and user options under appropriate headings.

- Lots of internal refinements to the code. I tweaks things to make
  the code easier to maintain and contribute to.

- Thanks to Pavlo Lysov for adding a small example to the manual about
  using TMR hooks to send a custom notification on the macOS. This was
  done in pull request 25: <https://github.com/protesilaos/tmr/pull/25>.
  Pavlo does not need to assign copyright to the Free Software
  Foundation.

- Thanks to Carlos Pajuelo Rojo for refining an earlier version of the
  function that produces a message about the repeat count of a given
  timer (I have since made lots of changes on this and other fronts).
  Carlos' contribution is in pull request 20: <https://github.com/protesilaos/tmr/pull/20>.
  The change is small, meaning that Carlos does not need to assign
  copyright to the Free Software Foundation.

- Thanks to f6p for use the appropriate face for the paused indicator
  in the tabulated view. This was done in pull request 17:
  <https://github.com/protesilaos/tmr/pull/17>. The change is small,
  meaning that the author does not need to assign copyright to the
  Free Software Foundation.

* Version 1.3.0 on 2026-01-25
:PROPERTIES:
:CUSTOM_ID: h:705987e4-60e9-4d06-bdc0-4f08347348a0
:END:

This version adds some user options and new features to an already
stable package.

** Timers can be paused
:PROPERTIES:
:CUSTOM_ID: h:4e740a08-0e29-4d5e-84ec-e5507df3845c
:END:

The command ~tmr-toggle-pause~ will prompt for a running timer and
pause it.

Users who have something like the following in their configuration,
have access to ~tmr-toggle-pause~ under the =P= key:

#+begin_src emacs-lisp
;; All TMR commands are behind this prefix key.  So `tmr-toggle-pause' is C-c t P.
(define-key global-map (kbd "C-c t") #'tmr-prefix-map)
#+end_src

In the buffer produced by the command ~tmr-tabulated-view~ the pause
functionality applies to the timer at point. The ~tmr-toggle-pause~ is
invoked with the =P= key.

An extra column in the tabulated view shows whether a timer is paused
or not. Here is an example:

#+begin_example
Start      End        Duration   Remaining  Paused?  Acknowledge?   Description

08:49:41   09:19:46   30m        29m 17s    Yes                     Work on TMR for 30 minutes
08:49:31   08:54:31   5m         3m 53s                             Prepare tea
08:49:21   08:59:21   10m        8m 42s              Yes            Edit the description with this one instead
#+end_example

** Configure the confirmation text for acknowledgements
:PROPERTIES:
:CUSTOM_ID: h:b08bda30-2991-4d36-83d8-39d619abb20f
:END:

When a timer is set to be acknowledged (i.e. the user must confirm
that they saw it elapse) it prompts for confirmation. The default
input text that confirms the acknowledgement is =ack=. This is now
subject to configuration via the user option ~tmr-acknowledge-timer-text~.

** Change how frequently the tabulated list is refreshed
:PROPERTIES:
:CUSTOM_ID: h:758d2691-14c5-4f3e-9044-a394101f9cff
:END:

The buffer produced by ~tmr-tabulated-view~ is set to automatically
refresh every 5 seconds by default. In previous versions this was every
1 second. The new user option ~tmr-tabulated-refresh-interval~ can be
set to a number of seconds or ~nil~. In the latter case, the automatic
refresh is disabled.

** Removed the long-obsolete =tmr-tabulated.el=
:PROPERTIES:
:CUSTOM_ID: h:5bd873e9-15fa-4660-947f-b4f104d4e577
:END:

Its code was merged into =tmr.el= on 2024-10-30 and all it was doing
thenceforth is issue a warning to those who would ~require~ the
~tmr-tabulated~ feature. Now ~(require 'tmr-tabulated)~ produces an
error.

* Version 1.2.0 on 2025-10-06
:PROPERTIES:
:CUSTOM_ID: h:87d321d7-e88e-4303-a7fc-fa4264e62a92
:END:

This release introduces several quality-of-life refinements to an
already stable and featureful package.

** Timers can now appear on the modeline
:PROPERTIES:
:CUSTOM_ID: h:4a695649-c356-4410-ab3e-27edcf5852e7
:END:

The new minor mode ~tmr-mode-line-mode~ controls whether running
timers are displayed on the mode line. More specifically, they are
displayed in the ~global-mode-string~, which can also be set in the
~tab-bar-mode~ (this way the information appears in one place instead
of all the mode lines, assuming default settings).

The exact format of a timer on display is controlled by the user
option ~tmr-mode-line-format~. The number of timers is set with the
option ~tmr-mode-line-max-timers~. The separator between multiple
timers is ~tmr-mode-line-separator~. The length of each timer's
optional description is subject to ~tmr-mode-line-max-desc-length~.
While the entire indicator can have a prefix, per ~tmr-mode-line-prefix~.

Thanks to Steven Allen for contributing the original version of this
feature in pull request 2: <https://github.com/protesilaos/tmr/pull/2>.
Steven has assigned copyright to the Free Software Foundation. Further
changes by me, such as to make the timers on the mode line clickable
(which produces a tabulated view, per ~tmr-tabulated-view~).

** Notifications for more operating systems
:PROPERTIES:
:CUSTOM_ID: h:5bc7646d-b785-461a-9d85-331afb958002
:END:

Timers can optionally trigger a system notification, via the abnormal
hook ~tmr-timer-finished-functions~. The relevant function is
~tmr-notification-notify~. It used to only support Linux. Now it is
extended to handle Android, Windows, and Haiku.

Thanks to Lucas Quintana for the contribution in pull request 10:
<https://github.com/protesilaos/tmr/pull/10>. Lucas has assigned
copyright to the Free Software Foundation.

** The tabulated timers have a "duration" column
:PROPERTIES:
:CUSTOM_ID: h:78bf9f7d-549c-46e5-bde2-efab21f1fba4
:END:

The ~tmr-tabulated-view~ command (alias ~tmr-list-timers~) now
includes a "duration" column, in addition to all the other informative
data on display.

[ Remember that the tabulated view can be used to create, duplicate,
  edit, etc. the timers. ]

Thanks to jpg for suggesting this in issue 11:
<https://github.com/protesilaos/tmr/issues/11>.

** Miscellaneous
:PROPERTIES:
:CUSTOM_ID: h:5309ee0b-edd0-4d75-849c-df008b4014ae
:END:

- System notifications specify the =:app-icon= of Emacs. It will be
  displayed, if the underlying software supports it (I see it on
  Linux, anyway).

- The option to play the ~tmr-sound-file~ via the abnormal hook
  ~tmr-timer-finished-functions~ is redone to not rely on the system
  shell (implicitly ~bash~). This way, users who use exotic shell
  alternatives will not run into any trouble. This is done in response
  to a relevant problem that g-gundam was facing with the ~nushell~:
  <https://github.com/protesilaos/tmr/pull/7>.

- The function ~tmr-notification-notify~ is better at informing the
  user that it has produced the warning about the lack of DBUS
  support. Before, the notification did not identity itself as
  belonging to the ~tmr~ package.

- The function ~tmr-running-timers-p~ is now available as a standalone
  function to do what was done before inside other functions. This is
  useful for anyone writing custom code on top of ~tmr~. Thanks to
  Eugene Mikhaylov for suggesting the idea in issue 9:
  <https://github.com/protesilaos/tmr/issues/9>.

- The manual is updated to include whatever necessary from the
  aforementioned.

* Version 1.1.0 on 2025-04-18
:PROPERTIES:
:CUSTOM_ID: h:41248cbf-d399-411d-91ff-5359a00a1577
:END:

This version makes small refinements to an already stable package.

** All of =tmr-tabulated.el=  is part of =tmr.el=
:PROPERTIES:
:CUSTOM_ID: h:cd10fa6b-60ed-4045-ae32-780e62b50f21
:END:

The command ~tmr-tabulated-view~, which produces a grid with
timers+descriptions, used to be in a separate file. It now is part of
the singular =tmr.el= to keep things simple. Users who were using
=(require 'tmr-tabulated)= or similar will now get a warning. Simply
load ~tmr~ instead.

** Refined the behaviour of the ~tmr-tabulated-view~ command
:PROPERTIES:
:CUSTOM_ID: h:bd56a213-7714-4bd7-bd1a-f3ac108f27d2
:END:

When the command ~tmr-tabulated-view~ (alias ~tmr-list-timers~) is
called interactively, it uses the =*tmr-tabulated-view*= buffer just
as it did before. Though it also evaluates the new user option
~tmr-list-timers-action-alist~: it is a variable that controls where
the buffer is displayed. The default value displays the buffer at the
bottom of the Emacs frame and makes some other tweaks for usability.

Watch my video on the ~display-buffer-alist~ for further details on
how to control the display of buffers: <https://protesilaos.com/codelog/2024-02-08-emacs-window-rules-display-buffer-alist/>.

The ~tmr-tabulated-view~ command is further revised to make it
callable from a program. One scenario where we do this is to interrupt
the termination of Emacs if there are running timers (more below).

** TMR interrupts the termination of Emacs if it must
:PROPERTIES:
:CUSTOM_ID: h:5a4bf956-b1c2-446b-848c-eb64ffa50109
:END:

In the past, we did not have anything to prevent the termination of
Emacs if timers were running: Emacs would simply shut down. Now we
define the ~tmr-kill-emacs-query-function~, which is added to the
standard ~kill-emacs-query-functions~: if there are running timers, it
asks for confirmation before closing Emacs. To make it easier for
users to decide how to proceed, it also pops up the list with all the
timers (i.e. it uses ~tmr-tabulated-view~ from Lisp, as noted above).

** The list view is easier to follow
:PROPERTIES:
:CUSTOM_ID: h:c432f1ab-dcaf-4a01-8004-cf268a24b228
:END:

The buffer produced by ~tmr-tabulated-view~ now uses more colours to
make it easier to track the data it presents. These are all the faces
it applies:

- ~tmr-tabulated-start-time~ :: The time when the timer was started.

- ~tmr-tabulated-end-time~ :: The time when the timer is set to end.

- ~tmr-tabulated-remaining-time~ :: The remaining time.

- ~tmr-tabulated-acknowledgement~ :: Whether the timer needs to be
  "acknowledged" after it ends (if it is marked as "acknowledged",
  then it will not go away until the user confirms they have seen it).

- ~tmr-tabulated-description~ :: The text describing what the timer is
  about.

* Version 1.0.0 on 2024-08-30
:PROPERTIES:
:CUSTOM_ID: h:88595352-0263-425c-baab-6042f63ae28a
:END:

This version adds quality-of-life improvements to an already stable
base.

** The ~tmr-with-details~ supersedes the ~tmr-with-description~
:PROPERTIES:
:CUSTOM_ID: h:ac3d5ea6-2e89-477b-a5eb-9b408ef30b4e
:END:

The ~tmr-with-description~ would always prompt for a time input and
then a description of the resulting timer object. We now provide a
more general command, ~tmr-with-details~, which does this in addition
to an extra prompt for an acknowledgement. What an "acknowledgement"
is, is documented in the following section.

** Timers can now be "acknowledged"
:PROPERTIES:
:CUSTOM_ID: h:1a971ba1-09a6-4df6-bbe5-73685430417c
:END:

Normally, when a timer elapses it does not stick around to notify the
user again and again. This means that the user may miss the one
notification if, say, they were away from the computer. As such, we
now provide an opt-in mechanism where a timer persists until it is
explicitly acknowledged as finished. The acknowledgement is either an
additional duration for the timer to produce another notification in
the future, or an explicit consent from the timer to count as
finished. The goal is to help the user never miss a timer.

Setting up an acknowledgement can be done in the following ways:

- Call the standard ~tmr~ command with a prefix argument (=C-u= by
  default). This will make it prompt for a description and an
  acknowledgement.

- Use the new command ~tmr-with-details~, which asks for a timer
  input, a description, and whether to include an acknowledgement
  prompt.

- Use the new command ~tmr-toggle-acknowledge~, which will prompt for
  a timer and then toggle the acknowledgement status on/off. In this
  scenario, the timer already exists (e.g. it was created with ~tmr~
  without a prefix argument).

All timers are listed in a nice list with the command
~tmr-tabulated-view~. An extra column will indicate their
acknowledgement status.

Thanks to Daniel Mendler for contributing this feature. This was done
in the form of patches, sent via email. Daniel has assigned copyright
to the Free Software Foundation.

** The ~tmr-list-timers~ is an alias for ~tmr-tabulated-view~
:PROPERTIES:
:CUSTOM_ID: h:f1d80033-45f5-47cc-b76b-c8aee05dd789
:END:

Perhaps the "list timers" is a more meaningful description of what the
command does, as opposed to "tabulated view".

** Use the ~tmr-prefix-map~
:PROPERTIES:
:CUSTOM_ID: h:20dcbc95-a376-4130-8ae8-7be6c7aa149a
:END:

We now define a prefix keymap that users can bind directly to a key
and get all the TMR commands in one go. For example, this adds all TMR
commands behind the =C-c t= prefix:

#+begin_src emacs-lisp
(define-key global-map (kbd "C-c t") 'tmr-prefix-map)
#+end_src

Thanks to Daniel Mendler for this patch.

** TMR uses its own faces
:PROPERTIES:
:CUSTOM_ID: h:1d6ddc5a-8856-40d4-8328-f6413cb37f30
:END:

Theme developers or users can now modify how the various TMR
indicators look by tweaking the faces we provide:

- ~tmr-duration~
- ~tmr-description~
- ~tmr-start-time~
- ~tmr-end-time~
- ~tmr-is-acknowledged~
- ~tmr-must-be-acknowledged~
- ~tmr-finished~

The default values inherit from basic faces that should be supported
everywhere.

Existing users will not notice any visual difference, other things
being equal.

** Fixed some typos in the manual
:PROPERTIES:
:CUSTOM_ID: h:2b0e0105-d142-45de-807d-b2ef60c25dc8
:END:

Thanks to Ed Tavinor for the contribution. The change pertains to
typos and is within the limit of edits that do not require copyright
assignment to the Free Software Foundation.

* Version 0.4.0 on 2022-07-07
:PROPERTIES:
:CUSTOM_ID: h:52e3b3ac-70ef-47c5-895c-92adbd5c92b0
:END:

The general theme of this release is that TMR became simpler, better,
and more robust.  Daniel Mendler provided lots of patches and is now
recognised as co-author of the package together with Damien Cassou and
me (Protesilaos).  With the exception of documentation changes and other
accompanying tweaks, all of the following are courtesy of Daniel
Mendler.  Consult the git log for the minutia.

+ Timers can also be set using an absolute time input.  For example,
  =21:45= will set a timer from now until the specified time.  The
  familiar ways of starting timers with relative values, work as they
  did before.  This is part of a wider internal revision to make the
  parsing of input more strict.

+ TMR no longer maintains distinct feature sets between its minibuffer
  and tabulated interfaces.  What works in one context, works equally in
  the other.  All commands that were formerly available only in the
  ~tmr-tabulated-mode~ (accessed via ~tmr-tabulated-view~) are now
  implemented anew to provide the requisite minibuffer capabilities.
  When called from inside the ~tmr-tabulated-mode~, the commands operate
  on the timer at point.  Otherwise they prompt for completion among the
  available timers (where relevant).  This covers all operations for
  creating, cloning, [re-]describing, rescheduling, and removing timers.
  The ~tmr-tabulated-mode-map~ is updated thus:

  #+begin_src emacs-lisp
  (defvar tmr-tabulated-mode-map
    (let ((map (make-sparse-keymap)))
      (define-key map "k" #'tmr-remove)
      (define-key map "r" #'tmr-remove)
      (define-key map "R" #'tmr-remove-finished)
      (define-key map "+" #'tmr)
      (define-key map "t" #'tmr)
      (define-key map "*" #'tmr-with-description)
      (define-key map "T" #'tmr-with-description)
      (define-key map "c" #'tmr-clone)
      (define-key map "e" #'tmr-edit-description)
      (define-key map "s" #'tmr-reschedule)
      map)
    "Keybindings for `tmr-tabulated-mode-map'.")
  #+end_src

  Similarly, our sample key bindings are these:

  #+begin_src emacs-lisp
  ;; OPTIONALLY set your own global key bindings:
  (let ((map global-map))
    (define-key map (kbd "C-c t t") #'tmr)
    (define-key map (kbd "C-c t T") #'tmr-with-description)
    (define-key map (kbd "C-c t l") #'tmr-tabulated-view) ; "list timers" mnemonic
    (define-key map (kbd "C-c t c") #'tmr-clone)
    (define-key map (kbd "C-c t k") #'tmr-cancel)
    (define-key map (kbd "C-c t s") #'tmr-reschedule)
    (define-key map (kbd "C-c t e") #'tmr-edit-description)
    (define-key map (kbd "C-c t r") #'tmr-remove)
    (define-key map (kbd "C-c t R") #'tmr-remove-finished))
  #+end_src

+ The tabulated view now shows the remaining time for all timer objects.
  This is how the =*tmr-tabulated-view*= buffer is formatted:

  #+begin_example
  Start      End        Remaining  Description
  10:11:49   10:11:54   ✔
  10:11:36   10:31:36   19m 35s
  10:11:32   10:26:32   14m 31s    Yet another test
  10:11:16   10:21:16   9m 14s     Testing how it works
  #+end_example

+ All timer objects are refactored to expose a properly formatted
  completion table.  The completion category is ~tmr-timer~.  In
  practical terms, =embark= (and other standards-compliant packages) can
  operate on them.  The manual provides sample glue code for Embark:

  #+begin_src emacs-lisp
  (defvar tmr-action-map
    (let ((map (make-sparse-keymap)))
      (define-key map "k" #'tmr-remove)
      (define-key map "r" #'tmr-remove)
      (define-key map "R" #'tmr-remove-finished)
      (define-key map "c" #'tmr-clone)
      (define-key map "e" #'tmr-edit-description)
      (define-key map "s" #'tmr-reschedule)
      map))

  (with-eval-after-load 'embark
    (add-to-list 'embark-keymap-alist '(tmr-timer . tmr-action-map))
    (cl-loop
     for cmd the key-bindings of tmr-action-map
     if (commandp cmd) do
     (add-to-list 'embark-post-action-hooks (list cmd 'embark--restart))))
  #+end_src

  The [[https://github.com/oantolin/embark/wiki/Additional-Actions#actions-for-prots-tmr-tmr-may-ring][Embark Wiki]] is updated accordingly.

+ The new user option ~tmr-confirm-single-timer~ governs how TMR should
  behave while operating on the sole timer.  If non-nil (the default),
  TMR will always use the minibuffer to select a timer object to operate
  on, even when there is only one candidate available.  If set to nil,
  TMR will not ask for confirmation when there is one timer available:
  the operation will be carried out outright.  The default value is
  optimal for use with Embark.

+ The existing user option ~tmr-description-list~ is revised to accept
  either a list of strings (the old approach) or a symbol of a variable
  that holds a list of strings.  In the latter case, this can be the
  ~tmr-description-history~, which is a variable that stores the user's
  input at the relevant minibuffer prompt.  We have made this the new
  default value, as it grows naturally to reflect one's usage of TMR.
  Minibuffer histories can persist between sessions if the user enables
  the built-in =savehist= library.  Sample configuration:

  #+begin_src emacs-lisp
  (require 'savehist)
  (setq savehist-file (locate-user-emacs-file "savehist"))
  (setq history-length 10000)
  (setq history-delete-duplicates t)
  (setq savehist-save-minibuffer-history t)
  (add-hook 'after-init-hook #'savehist-mode)
  #+end_src

+ Fixed an edge case where a ~when-let*~ form did not return the
  expected value.  Thanks to Nathan R. DeGruchy for the patch.  The
  patch is below the ~15 line threshold and thus does not require
  copyright assignment to the Free Software Foundation.

+ Named the mailing list address as the =Maintainer:= of Denote.
  Together with the other package headers, they help the user find our
  primary sources and/or communication channels.  This change conforms
  with work being done upstream in package.el by Philip Kaludercic.  I
  was informed about it here:
  <https://lists.sr.ht/~protesilaos/general-issues/%3C875ykl84yi.fsf%40posteo.net%3E>.

+ Updated the manual to reflect the aforementioned.

* Version 0.3.0 on 2022-05-17
:PROPERTIES:
:CUSTOM_ID: h:0a2d4909-0079-47e9-97f4-220e85a811f9
:END:

The gist of TMR's May Release is that TMR is Maintained Rigorously---but
enough with The Mostly Recursive acronyms!

+ This is the first version for which we produce a change log.  The
  short story of previous releases: I (Protesilaos) was using and
  developing TMR (pronounced as "timer" or "T-M-R") as part of my
  personal setup for more than a year until I eventually contributed it
  to GNU ELPA.

+ What was once =tmr.el= is now split up into purpose-specific files:
  =tmr.el= (core functionality), =tmr-tabulated.el= (grid view),
  =tmr-sound.el= (audible notifications), and =tmr-notification.el=
  (desktop notifications).

+ The ~tmr-with-description~ command creates a new timer while always
  asking for a description.  Whereas the standard ~tmr~ command prompts
  for a description only when invoked with a prefix argument.

+ The ~tmr-clone~ command copies the duration and optional description
  of an existing timer object into a new one.  The operation is
  performed without further questions, except if a prefix argument is
  supplied: in that case the command will prompt for a duration and, if
  the original timer had a description, for one as well.  The default
  values of these prompts are those of the original timer.

+ The ~tmr-remove-finished~ deletes all elapsed timers.  This means that
  they are removed from the list of available timers and, thus, cannot
  be cloned.

+ The ~tmr-timer-created-functions~, ~tmr-timer-completed-functions~,
  and ~tmr-timer-cancelled-functions~ are hooks which can be used to
  control what happens once a timer is (i) created, (ii) elapses, or
  (iii) is cancelled.

+ Elapsed and running timers are displayed in a grid view with the
  command ~tmr-tabulated-view~.  The buffer looks like this:

  #+begin_example
  Start      End        Finished?  Description
  09:22:43   09:32:43   ✔         Prepare tea
  09:17:14   09:37:14              Boil water
  09:07:03   09:57:03              Bake bread
  #+end_example

+ In that grid view, it is possible to create a new timer, or operate on
  the one at point to cancel, clone, redescribe, and reschedule it.

+ Thanks to Christian Tietze for implementing changes to how desktop
  notifications are handled.  The overall effect should still be the
  same for existing users, though the implementation has been redesigned.

+ Thanks to Damien Cassou who is now is my co-author due to multiple
  contributions for =tmr.el=, the addition of the grid view, and the
  splitting of TMR into numerous files.  Please consult the Git commit
  log for the details.  (I still am the maintainer.)

+ Christian and Damien have assigned copyright to the Free Software
  Foundation.  It is required for all packages distributed via GNU ELPA.

The manual documents the technicalities and provides a sample
configuration.  Either evaluate the form =(info "(tmr) Top")= if you
have the package installed or visit https://protesilaos.com/emacs/tmr.

* Version 0.2.0 on 2022-04-21
:PROPERTIES:
:CUSTOM_ID: h:054285c2-3d90-4adc-ada4-61222b31fb85
:END:

This entry is retroactively introduced on 2022-07-07.

+ Changed the ~tmr~ and ~tmr-cancel~ commands to handle a list of timers
  instead of only interfacing with the last timer.

+ Improved the documentation.

+ Made various internal tweaks and refinements.

+ Added TMR to the official GNU ELPA archive as =tmr=.

* Version 0.1.0 on 2021-10-02
:PROPERTIES:
:CUSTOM_ID: h:1fce2c20-a16c-4ea9-9006-cf565f78f812
:END:

This entry is retroactively introduced on 2022-07-07.

TMR was originally [[https://protesilaos.com/codelog/2021-10-02-introducing-tmr-el/][announced on my website]].  The code was developed as
part of [[https://protesilaos.com/emacs/dotemacs][my dotemacs]] for several months before it was placed in its own
Git repo.  Even before the Elisp implementation, the core idea existed
as a standalone shell script, which is still part of [[https://git.sr.ht/~protesilaos/dotfiles][my dotfiles]].
