time-block

Homepage: https://git.sr.ht/~swflint/time-block-command

Author: Samuel W. Flint

Updated:

Summary

Block running commands using time

Commentary

This package requires [`ts.el`](https://github.com/alphapapa/ts.el) to
handle time parsing.

Download `time-block.el` to somewhere on your `load-path' and
load with `(require 'time-block)`.

Usage

To use this package it's necessary to do two things: define time
blocking groups and define time blocked commands.

 Time Blocking Groups

Customize the variable `time-block-groups'.  An example of a groups
definition is below.

(setf time-block-groups '((workday . ((1 . (("09:00" . "17:00")))
                                      (2 . (("09:00" . "17:00")))
                                      (3 . (("09:00" . "17:00")))
                                      (4 . (("09:00" . "17:00")))
                                      (5 . (("09:00" . "17:00")))))))

This variable is an alist of names (keywords) to group definitions.  A
group definition is an alist from days of the week (as numbers, Sunday
= 0/7, etc.) to lists of start/stop pairs (times in "HH:MM" form).

It is also possible to ignore time blocking on holidays.  This is
globally set using the `time-block-skip-on-holidays-p' variable.
This defaults to nil, which does not ignore blocking on holidays.
If set to t, time blocking will be ignored on any holiday.  It may
also be set to a regular expression or a list.  Holidays which
match either representation will cause time blocking to be ignored.

Defining Time Blocked Commands

Commands are only time-blocked if they're defined.  This is done
using the `define-time-blocked-command` macro, which behaves
similarly to `defun`.  After the lambda list, it has a list
describing blocking and blocking messages.  This is composed of a
symbol (a key in `time-block-groups') a block message, and an
optional override prompt (if present, the command will ask if you'd
like to override the block using `time-block-confirm-override').
An example is shown below.

(define-time-blocked-command my/start-elfeed ()
                             (workday "You have decided not to check news currently."
                                      "You have decided not to check news currently.\nStill start elfeed?")
  "Start `elfeed'.

Time blocked according to `time-block-groups'."
  (interactive)
  (elfeed))

Advising commands to be time-blocked

Commands can also be advised to use timeblocking.  This works for
simpler commands, and as a bonus, can make it harder to access the
commands when blocked.  Overall, the arguments for `group`,
`block-message` and `override-prompt` are as above.  Consider the
following example.

(time-block-advise my/elfeed-block-advice 'elfeed workday "You have decided not to check news currently."
                   "You have decided not to check news currently.\nStill start elfeed?")

Focus Mode

A "focus mode" may be enabled using the `time-block-focus-mode'
command.  This global minor mode by default will block all
block-groups, but this behavior may be changed using
`time-block-block-checkers'.

Relaxed Mode

A "relaxed mode" (disabling all blocking) may be enabled with the
`time-block-relaxed-mode' command.  This global minor mode will
disable all block groups (and ignore `time-block-focus-mode').  At
present, this behavior is not configurable.

Checking if A Group Is Blocked

You may check if a group is currently blocked using the
`time-block-blocked-p' function, which uses the functions in
`time-block-block-checkers' to determine if a group is presently
blocked.  Functions in this hook must take one argument, a group
name, and return non-nil if the group is to be blocked.

Manually advising commands to be time-blocked

Commands can also be manually advised.  This can be done to prevent
only certain cases from happening.  For instance, I use the following
code to delay myself from editing my Emacs configuration during the
workday.

(defun my/buffer-sets-around-advice (orig name)
  "Check if NAME is 'emacs', if so, follow time blocking logic before calling ORIG (`buffer-sets-load-set')."
  (unless (and (string= name "emacs")
               (time-block-blocked-p :workday)
               (not (time-block-confirm-override "You have decided not to edit your emacs configuration at this time.\nContinue?")))
    (funcall orig name)))
(advice-add 'buffer-sets-load-set :around #'my/buffer-sets-around-advice)

Confirmation Functions

When an automatically-advised function or function defined with
`define-time-block-command' provides an override prompt, the
function `time-block-confirm-override' is used to confirm that the
block should be overriden.  This is done following the logic of
`time-block-override-confirmation-functions', an alist from block
groups (or default t) to prompting functions. The prompting
function should take one argument (a confirmation prompt) and
return non-nil if the block should be overridden.  The default is
`yes-or-no-p', but the functions
`time-block-override-math-question' and
`time-block-override-random-string' may be used as well.

Dependencies