~swflint/time-block-command

Block running Emacs commands using time.
Update Bug Report email
Define a "relaxed mode"
Drop debugging message

clone

read-only
https://git.sr.ht/~swflint/time-block-command
read/write
git@git.sr.ht:~swflint/time-block-command

You can also use your local clone with git send-email.

#time-block

MELPA REUSE status

A method for blocking access to emacs commands based on time.

#Installation

This package requires ts.el to handle time parsing.

Download time-block.el to somewhere on your load-path and load with (require 'time-block). It is also available on MELPA.

#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))

#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.

#Automatically 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?")

#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.

#Errors and Bugs

If you find an error or a bug, send an email to ~swflint/emacs-utilities@lists.sr.ht.