tvl-depot/tools/emacs-pkgs/dottime/dottime.el
2019-12-27 13:04:49 +01:00

101 lines
3.7 KiB
EmacsLisp

;;; dottime.el --- use dottime in the modeline
;;
;; Copyright (C) 2019 Google Inc.
;;
;; Author: Vincent Ambo <tazjin@google.com>
;; Version: 1.0
;; Package-Requires: (cl-lib)
;;
;;; Commentary:
;;
;; This package changes the display of time in the modeline to use
;; dottime (see https://dotti.me/) instead of the standard time
;; display.
;;
;; Modeline dottime display is enabled by calling
;; `dottime-display-mode' and dottime can be used in Lisp code via
;; `dottime-format'.
(require 'cl-lib)
(require 'time)
(defun dottime--format-string (&optional offset prefix)
"Creates the dottime format string for `format-time-string'
based on the local timezone."
(let* ((offset-sec (or offset (car (current-time-zone))))
(offset-hours (/ offset-sec 60 60))
(base (concat prefix "%m-%dT%H·%M")))
(if (/= offset-hours 0)
(concat base (format "%0+3d" offset-hours))
base)))
(defun dottime--display-time-update-advice (orig)
"Function used as advice to `display-time-update' with a
rebound definition of `format-time-string' that renders all
timestamps as dottime."
(cl-letf* ((format-orig (symbol-function 'format-time-string))
((symbol-function 'format-time-string)
(lambda (&rest _)
(funcall format-orig (dottime--format-string) nil t))))
(funcall orig)))
(defun dottime-format (&optional time offset prefix)
"Format the given TIME in dottime at OFFSET. If TIME is nil,
the current time will be used. PREFIX is prefixed to the format
string verbatim.
OFFSET can be an integer representing an offset in seconds, or
the argument can be elided in which case the system time zone
is used."
(format-time-string (dottime--format-string offset prefix) time t))
(defun dottime-display-mode (arg)
"Enable time display as dottime. Disables dottime if called
with prefix 0 or nil."
(interactive "p")
(if (or (eq arg 0) (eq arg nil))
(advice-remove 'display-time-update #'dottime--display-time-update-advice)
(advice-add 'display-time-update :around #'dottime--display-time-update-advice))
(display-time-update)
;; Amend the time display in telega.el to use dottime.
;;
;; This will never display offsets in the chat window, as those are
;; always visible in the modeline anyways.
(when (featurep 'telega)
(require 'telega)
(defun telega-ins--dottime-advice (orig timestamp)
(let* ((dtime (decode-time timestamp t))
(current-ts (time-to-seconds (current-time)))
(ctime (decode-time current-ts))
(today00 (telega--time-at00 current-ts ctime)))
(if (> timestamp today00)
(telega-ins-fmt "%02d·%02d" (nth 2 dtime) (nth 1 dtime))
(funcall orig timestamp))))
(advice-add 'telega-ins--date :around #'telega-ins--dottime-advice))
;; Amend the time display in notmuch to use dottime.
(when (featurep 'notmuch)
(require 'notmuch)
(defun notmuch-show--dottime-date-advice (orig header header-value)
(if (equal "Date" header)
;; Unfortunately the header insertion functions do not have access
;; to the message object, which means that the only information we
;; have about the timestamp is its string rendering.
(-let* (((sec min hour day mon year dow dst tz)
(parse-time-string header-value)))
(insert header ": "
(dottime-format (encode-time sec min hour day mon year tz)
tz "%a, %Y-")
"\n"))
(funcall orig header header-value)))
(advice-add 'notmuch-show-insert-header :around #'notmuch-show--dottime-date-advice)))
(provide 'dottime)