From 09688d8b12019b820a03634b39eb2c44ba41550c Mon Sep 17 00:00:00 2001 From: Stephen Gildea Date: Fri, 7 Feb 2025 09:17:26 -0800 Subject: [PATCH] time-stamp: Better handling of some edge cases * lisp/time-stamp.el (time-stamp-count): Require confirmation if large. (time-stamp-once): Correctly handle a start regexp matching 0 chars. * test/lisp/time-stamp-tests.el (time-stamp-custom-start): New test. (cherry picked from commit 280b25e0096bb97fb473a8da9b4635fb2d6e5385) --- lisp/time-stamp.el | 20 +++++++++++-------- test/lisp/time-stamp-tests.el | 36 ++++++++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/lisp/time-stamp.el b/lisp/time-stamp.el index 7904b92184a..2e7bc0078e3 100644 --- a/lisp/time-stamp.el +++ b/lisp/time-stamp.el @@ -114,7 +114,7 @@ limit yourself to the formats recommended by that older version." (defcustom time-stamp-active t - "Non-nil to enable time-stamping of buffers by \\[time-stamp]. + "Non-nil enables time-stamping of buffers by \\[time-stamp]. Can be toggled by \\[time-stamp-toggle-active]. This option does not affect when `time-stamp' is run, only what it @@ -257,7 +257,7 @@ then instead of changing this variable, include a newline (written as `time-stamp-count' is best changed with a file-local variable. If you were to change it in your init file, you would be incompatible with other people's files.") -;;;###autoload(put 'time-stamp-count 'safe-local-variable 'integerp) +;;;###autoload(put 'time-stamp-count 'safe-local-variable (lambda (c) (and (integerp c) (< c 100)))) (defvar time-stamp-pattern nil ;Do not change! @@ -342,12 +342,11 @@ To enable automatic time-stamping for only a specific file, add this line to a local variables list near the end of the file: eval: (add-hook \\='before-save-hook \\='time-stamp nil t) -If the file has no time stamp template, this function does nothing. +If the file has no time stamp template or if `time-stamp-active' is nil, +this function does nothing. You can set `time-stamp-pattern' in a file's local variables list -to customize the information in the time stamp and where it is written. - -The time stamp is updated only if `time-stamp-active' is non-nil." +to customize the information in the time stamp and where it is written." (interactive) (let ((line-limit time-stamp-line-limit) (ts-start time-stamp-start) @@ -421,6 +420,7 @@ The time stamp is updated only if `time-stamp-active' is non-nil." Returns the end point, which is where `time-stamp' begins the next search." (let ((case-fold-search nil) (end nil) + (advance-nudge 0) end-search-start (end-length nil)) (save-excursion @@ -430,6 +430,9 @@ Returns the end point, which is where `time-stamp' begins the next search." (while (and (< (goto-char start) search-limit) (not end) (re-search-forward ts-start search-limit 'move)) + ;; Whether or not we find a template, we must + ;; advance through the buffer. + (setq advance-nudge (if (> (point) start) 0 1)) (setq start (point)) (if (not time-stamp-inserts-lines) (forward-line format-lines)) @@ -444,7 +447,8 @@ Returns the end point, which is where `time-stamp' begins the next search." (if (re-search-forward ts-end line-end t) (progn (setq end (match-beginning 0)) - (setq end-length (- (match-end 0) end)))))))))))) + (setq end-length (- (match-end 0) end))) + (setq start (+ start advance-nudge))))))))))) (if end (progn ;; do all warnings outside save-excursion @@ -478,7 +482,7 @@ Returns the end point, which is where `time-stamp' begins the next search." (setq end (point)))))))))))) ;; return the location after this time stamp, if there was one (and end end-length - (+ end end-length)))) + (+ end (max advance-nudge end-length))))) ;;;###autoload diff --git a/test/lisp/time-stamp-tests.el b/test/lisp/time-stamp-tests.el index 4794051efd0..c479806639c 100644 --- a/test/lisp/time-stamp-tests.el +++ b/test/lisp/time-stamp-tests.el @@ -138,6 +138,31 @@ (iter-yield-from (time-stamp-test-pattern-sequential)) (iter-yield-from (time-stamp-test-pattern-multiply))) +(ert-deftest time-stamp-custom-start () + "Test that `time-stamp' isn't stuck by a start matching 0 characters." + (with-time-stamp-test-env + (with-time-stamp-test-time ref-time1 + (let ((time-stamp-pattern "^%Y-%m-%d<-TS")) ;start matches 0 chars + (with-temp-buffer + (insert "\n<-TS\n") + ;; we should advance to line 2 and find the template + (time-stamp) + (should (equal (buffer-string) "\n2006-01-02<-TS\n")))) + (let ((time-stamp-pattern "\\b%Y-%m-%d\\b") ;start and end match 0 chars + (time-stamp-count 2)) + (with-temp-buffer + (insert "..") + ;; the two time stamps should be in different places + (time-stamp) + (should (equal (buffer-string) "2006-01-02..2006-01-02")))) + (let ((time-stamp-pattern "::%S\\_>") ;end matches 0 chars + (time-stamp-count 2)) + (with-temp-buffer + (insert "::0::0") + ;; the second template should be found immediately after the first + (time-stamp) + (should (equal (buffer-string) "::05::05"))))))) + (ert-deftest time-stamp-custom-pattern () "Test that `time-stamp-pattern' is parsed correctly." (iter-do (pattern-parts (time-stamp-test-pattern-all)) @@ -246,17 +271,17 @@ (let ((time-stamp-start "TS: <") (time-stamp-format "%Y-%m-%d") (time-stamp-count 0) ;changed later in the test - (buffer-expected-once "TS: <2006-01-02>\nTS: <>") - (buffer-expected-twice "TS: <2006-01-02>\nTS: <2006-01-02>")) + (buffer-expected-once "TS: <2006-01-02>TS: <>") + (buffer-expected-twice "TS: <2006-01-02>TS: <2006-01-02>")) (with-time-stamp-test-time ref-time1 (with-temp-buffer - (insert "TS: <>\nTS: <>") + (insert "TS: <>TS: <>") (time-stamp) ;; even with count = 0, expect one time stamp (should (equal (buffer-string) buffer-expected-once))) (with-temp-buffer (setq time-stamp-count 1) - (insert "TS: <>\nTS: <>") + (insert "TS: <>TS: <>") (time-stamp) (should (equal (buffer-string) buffer-expected-once)) @@ -680,7 +705,7 @@ (should (equal (time-stamp-string "%5z" ref-time1) "+0000")) (let ((time-stamp-time-zone "PST8")) (should (equal (time-stamp-string "%5z" ref-time1) "-0800"))) - (let ((time-stamp-time-zone "HST10")) + (let ((time-stamp-time-zone '(-36000 "HST"))) (should (equal (time-stamp-string "%5z" ref-time1) "-1000"))) (let ((time-stamp-time-zone "CET-1")) (should (equal (time-stamp-string "%5z" ref-time1) "+0100"))) @@ -868,6 +893,7 @@ (should (safe-local-variable-p 'time-stamp-inserts-lines t)) (should-not (safe-local-variable-p 'time-stamp-inserts-lines 17)) (should (safe-local-variable-p 'time-stamp-count 2)) + (should-not (safe-local-variable-p 'time-stamp-count 100)) (should-not (safe-local-variable-p 'time-stamp-count t)) (should (safe-local-variable-p 'time-stamp-pattern "a string")) (should-not (safe-local-variable-p 'time-stamp-pattern 17))) -- 2.39.5