From 9a5b2bd7e9ce32bafbb3f204cc1b4a7d5069e9e5 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Wed, 30 Aug 2023 23:15:22 -0700 Subject: [PATCH 2/2] [5.6] Add optional timezone param to erc-echo-timestamp * etc/ERC-NEWS: 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. (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-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). (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) --- etc/ERC-NEWS | 13 +++-- lisp/erc/erc-stamp.el | 83 ++++++++++++++++++++++++++------ test/lisp/erc/erc-stamp-tests.el | 30 ++++++++++++ 3 files changed, 107 insertions(+), 19 deletions(-) diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 7ee55982b17..69088732c0d 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -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) enables the contextual +echoing of timestamps to the echo area when moving between messages in +an ERC buffer. This functionality is now available on demand by +invoking the newly interactive function 'erc-echo-timestamp' atop any +message. And 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 diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index a021cd26607..be12d6080d2 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -136,14 +136,27 @@ erc-echo-timestamps "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', `erc-hide-timestamps', or similar +in the appropriate ERC buffer." :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,16 @@ stamp (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 + (let (erc-echo-timestamps erc-hide-timestamps erc-timestamp-intangible) + (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)))) @@ -640,14 +655,31 @@ erc-format-timestamp ;; 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 (<= 29 emacs-major-version) + (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 @@ erc-toggle-timestamps (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))) diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index c448416cd69..b00aa6dcabf 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -274,4 +274,34 @@ erc-timestamp-intangible--left (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 -- 2.41.0