Add optional timezone param to erc-echo-timestamp

* etc/ERC-NEWS: Move `erc-echo-timestamp' from misc section
to own entry, and mention option `erc-echo-timestamp-zone'.
* lisp/erc/erc-stamp.el (erc-echo-timestamps): Mention that some
finagling is required if enabling this option after activating the
module.
(erc-echo-timestamp-format): Add additional Custom choice constants
and make the existing default one of them.
(erc-echo-timestamp-zone): New option to specify timezone for option
`erc-echo-timestamps' and function `erc-echo-timestamp'.
(erc-stamp-mode, erc-stamp-enable, erc-stamp-disable): Call
`erc-stamp--setup' instead of `erc-munge-invisibility-spec'.
(erc-stamp--current-time): Use `current-time' instead of
`erc-current-time'.
(erc-add-timestamp): Improve readability slightly, and change
`fboundp' to `functionp' to avoid signaling an error when the
variable's value is not a symbol.
(erc-munge-invisibility-spec): Perform teardown when boolean flag
options, like `erc-timestamp-intangible' and `erc-echo-timestamps' are
nil.
(erc-stamp--setup): Call `erc-munge-invisibility-spec', possibly
binding timestamp options to nil to force a tear down).
(erc-stamp--last-stamp, erc-stamp--on-clear-message): New function and
helper state variable to tell Emacs not to clear the current timestamp
message when navigating within the same IRC message.
(erc-echo-timestamp): Add optional `zone' parameter, to be passed
directly to `format-time-string', when non-interactive, and massaged
sensibly otherwise.  Set the local variable `erc-stamp--last-stamp'.
* test/lisp/erc/erc-stamp-tests.el (erc-echo-timestamp): New test.
(Bug#60936)
This commit is contained in:
F. Jason Park 2023-08-30 23:15:22 -07:00
parent e1b8dbe9ea
commit 7c932fa307
3 changed files with 116 additions and 28 deletions

View file

@ -203,11 +203,18 @@ continued integration. With the existing design, merely loading the
library 'erc-log' caused 'truncate' to start writing logs, possibly
against a user's wishes.
** The function 'erc-echo-timestamp' is now a command.
The option 'erc-echo-timestamps' (plural) has always enabled the
contextual printing of timestamps to the echo area when moving between
messages in an ERC buffer. Similar functionality is now available on
demand by invoking the newly interactive function 'erc-echo-timestamp'
atop any message. The new companion option 'erc-echo-timestamp-zone'
determines the default timezone when not specified with a prefix
argument.
** Miscellaneous UX changes.
Some minor quality-of-life niceties have finally made their way to
ERC. For example, the function 'erc-echo-timestamp' is now
interactive and can be invoked on any message to view its timestamp in
the echo area. Fool visibility has become togglable with the new
ERC. For example, fool visibility has become togglable with the new
command 'erc-match-toggle-hidden-fools'. The 'button' module's
'erc-button-previous' now moves to the beginning instead of the end of
buttons. A new command, 'erc-news', can be invoked to visit this very

View file

@ -136,14 +136,27 @@ hidden, they will still be present in the logs."
"If non-nil, print timestamp in the minibuffer when point is moved.
Using this variable, you can turn off normal timestamping,
and simply move point to an irc message to see its timestamp
printed in the minibuffer."
printed in the minibuffer. When attempting to enable this option
after `erc-stamp-mode' is already active, you may need to run the
command `erc-show-timestamps' (or `erc-hide-timestamps') in the
appropriate ERC buffer before the change will take effect."
:type 'boolean)
(defcustom erc-echo-timestamp-format "Timestamped %A, %H:%M:%S"
"Format string to be used when `erc-echo-timestamps' is non-nil.
This string specifies the format of the timestamp being echoed in
the minibuffer."
:type 'string)
:type '(choice (const "Timestamped %A, %H:%M:%S")
(const "%Y-%m-%d %H:%M:%S %Z")
string))
(defcustom erc-echo-timestamp-zone nil
"Default timezone for the option `erc-echo-timestamps'.
Also affects the command `erc-echo-timestamp' (singular). See
the ZONE parameter of `format-time-string' for a description of
acceptable value types."
:type '(choice boolean number (const wall) (list number string))
:package-version '(ERC . "5.6")) ; FIXME sync on release
(defcustom erc-timestamp-intangible nil
"Whether the timestamps should be intangible, i.e. prevent the point
@ -167,14 +180,15 @@ from entering them and instead jump over them."
(add-hook 'erc-send-modify-hook #'erc-add-timestamp 60)
(add-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect)
(add-hook 'erc--pre-clear-functions #'erc-stamp--reset-on-clear)
(unless erc--updating-modules-p
(erc-buffer-do #'erc-munge-invisibility-spec)))
(unless erc--updating-modules-p (erc-buffer-do #'erc-stamp--setup)))
((remove-hook 'erc-mode-hook #'erc-munge-invisibility-spec)
(remove-hook 'erc-insert-modify-hook #'erc-add-timestamp)
(remove-hook 'erc-send-modify-hook #'erc-add-timestamp)
(remove-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect)
(remove-hook 'erc--pre-clear-functions #'erc-stamp--reset-on-clear)
(erc-with-all-buffers-of-server nil nil
(erc-stamp--setup)
(kill-local-variable 'erc-stamp--last-stamp)
(kill-local-variable 'erc-timestamp-last-inserted)
(kill-local-variable 'erc-timestamp-last-inserted-left)
(kill-local-variable 'erc-timestamp-last-inserted-right))))
@ -200,9 +214,8 @@ the stamp passed to `erc-insert-timestamp-function'.")
(cl-defgeneric erc-stamp--current-time ()
"Return a lisp time object to associate with an IRC message.
This becomes the message's `erc-timestamp' text property, which
may not be unique, `equal'-wise."
(erc-current-time))
This becomes the message's `erc-timestamp' text property."
(let (current-time-list) (current-time)))
(cl-defmethod erc-stamp--current-time :around ()
(or erc-stamp--current-time (cl-call-next-method)))
@ -218,15 +231,17 @@ or `erc-send-modify-hook'."
(erc-stamp--invisible-property
;; FIXME on major version bump, make this `erc-' prefixed.
(if invisible `(timestamp ,@(ensure-list invisible)) 'timestamp))
(skipp (and erc-stamp--skip-when-invisible invisible))
(erc-stamp--current-time ct))
(unless (setq invisible (and erc-stamp--skip-when-invisible invisible))
(unless skipp
(funcall erc-insert-timestamp-function
(erc-format-timestamp ct erc-timestamp-format)))
;; FIXME this will error when advice has been applied.
(when (and (not invisible) (fboundp erc-insert-away-timestamp-function)
erc-away-timestamp-format
(erc-away-time)
(not erc-timestamp-format))
;; Check `erc-insert-away-timestamp-function' for historical
;; reasons even though its Custom :type only allows functions.
(when (and (not (or skipp erc-timestamp-format))
erc-away-timestamp-format
(functionp erc-insert-away-timestamp-function)
(erc-away-time))
(funcall erc-insert-away-timestamp-function
(erc-format-timestamp ct erc-away-timestamp-format)))
(add-text-properties (point-min) (1- (point-max))
@ -640,14 +655,31 @@ Return the empty string if FORMAT is nil."
;; please modify this function and move it to a more appropriate
;; location.
(defun erc-munge-invisibility-spec ()
(and erc-timestamp-intangible (not (bound-and-true-p cursor-intangible-mode))
(cursor-intangible-mode 1))
(and erc-echo-timestamps (not (bound-and-true-p cursor-sensor-mode))
(cursor-sensor-mode 1))
(if erc-timestamp-intangible
(cursor-intangible-mode +1) ; idempotent
(when (bound-and-true-p cursor-intangible-mode)
(cursor-intangible-mode -1)))
(if erc-echo-timestamps
(progn
(cursor-sensor-mode +1) ; idempotent
(when (>= emacs-major-version 29)
(add-function :before-until (local 'clear-message-function)
#'erc-stamp--on-clear-message)))
(when (bound-and-true-p cursor-sensor-mode)
(cursor-sensor-mode -1))
(remove-function (local 'clear-message-function)
#'erc-stamp--on-clear-message))
(if erc-hide-timestamps
(add-to-invisibility-spec 'timestamp)
(remove-from-invisibility-spec 'timestamp)))
(defun erc-stamp--setup ()
"Enable or disable buffer-local `erc-stamp-mode' modifications."
(if erc-stamp-mode
(erc-munge-invisibility-spec)
(let (erc-echo-timestamps erc-hide-timestamps erc-timestamp-intangible)
(erc-munge-invisibility-spec))))
(defun erc-hide-timestamps ()
"Hide timestamp information from display."
(interactive)
@ -677,14 +709,33 @@ enabled when the message was inserted."
(erc-munge-invisibility-spec)))
(erc-buffer-list)))
(defun erc-echo-timestamp (dir stamp)
"Print timestamp text-property of an IRC message."
;; Could also pass an &optional `zone' arg to `format-time-string'.
(interactive (list 'entered (get-text-property (point) 'erc-timestamp)))
(when (eq 'entered dir)
(when stamp
(message "%s" (format-time-string erc-echo-timestamp-format
stamp)))))
(defvar-local erc-stamp--last-stamp nil)
(defun erc-stamp--on-clear-message (&rest _)
"Return `dont-clear-message' when operating inside the same stamp."
(and erc-stamp--last-stamp erc-echo-timestamps
(eq (get-text-property (point) 'erc-timestamp) erc-stamp--last-stamp)
'dont-clear-message))
(defun erc-echo-timestamp (dir stamp &optional zone)
"Display timestamp of message at point in echo area.
Interactively, interpret a numeric prefix as a ZONE offset in
hours (or seconds, if its abs value is larger than 14), and
interpret a \"raw\" prefix as UTC. To specify a zone for use
with the option `erc-echo-timestamps', see the companion option
`erc-echo-timestamp-zone'."
(interactive (list nil (get-text-property (point) 'erc-timestamp)
(pcase current-prefix-arg
((and (pred numberp) v)
(if (<= (abs v) 14) (* v 3600) v))
(`(,_) t))))
(if (and stamp (or (null dir) (and erc-echo-timestamps (eq 'entered dir))))
(progn
(setq erc-stamp--last-stamp stamp)
(message (format-time-string erc-echo-timestamp-format
stamp (or zone erc-echo-timestamp-zone))))
(when (and erc-echo-timestamps (eq 'left dir))
(setq erc-stamp--last-stamp nil))))
(defun erc--echo-ts-csf (_window _before dir)
(erc-echo-timestamp dir (get-text-property (point) 'erc-timestamp)))

View file

@ -274,4 +274,34 @@
(when noninteractive
(kill-buffer)))))
(ert-deftest erc-echo-timestamp ()
(should-not erc-echo-timestamps)
(should-not erc-stamp--last-stamp)
(insert (propertize "abc" 'erc-timestamp 433483200))
(goto-char (point-min))
(let ((inhibit-message t)
(erc-echo-timestamp-format "%Y-%m-%d %H:%M:%S %Z")
(erc-echo-timestamp-zone (list (* 60 60 -4) "EDT")))
;; No-op when non-interactive and option is nil
(should-not (erc--echo-ts-csf nil nil 'entered))
(should-not erc-stamp--last-stamp)
;; Non-interactive (cursor sensor function)
(let ((erc-echo-timestamps t))
(should (equal (erc--echo-ts-csf nil nil 'entered)
"1983-09-27 00:00:00 EDT")))
(should (= 433483200 erc-stamp--last-stamp))
;; Interactive
(should (equal (call-interactively #'erc-echo-timestamp)
"1983-09-27 00:00:00 EDT"))
;; Interactive with zone
(let ((current-prefix-arg '(4)))
(should (equal (call-interactively #'erc-echo-timestamp)
"1983-09-27 04:00:00 GMT")))
(let ((current-prefix-arg -7))
(should (equal (call-interactively #'erc-echo-timestamp)
"1983-09-26 21:00:00 -07")))))
;;; erc-stamp-tests.el ends here