emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 7c932fa3078 3/4: Add optional timezone param to erc-echo-timestam


From: F. Jason Park
Subject: master 7c932fa3078 3/4: Add optional timezone param to erc-echo-timestamp
Date: Sun, 10 Sep 2023 21:02:11 -0400 (EDT)

branch: master
commit 7c932fa307851ccef1cf17a1d7eec689af82a0ef
Author: F. Jason Park <jp@neverwas.me>
Commit: F. Jason Park <jp@neverwas.me>

    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)
---
 etc/ERC-NEWS                     |  13 +++--
 lisp/erc/erc-stamp.el            | 101 +++++++++++++++++++++++++++++----------
 test/lisp/erc/erc-stamp-tests.el |  30 ++++++++++++
 3 files changed, 116 insertions(+), 28 deletions(-)

diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index 7ee55982b17..8997bd3e97b 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) 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
diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el
index a021cd26607..f159b6d226f 100644
--- a/lisp/erc/erc-stamp.el
+++ b/lisp/erc/erc-stamp.el
@@ -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)))
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 @@
       (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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]