Commit 0fe719e6 authored by Glenn Morris's avatar Glenn Morris
Browse files

copyright.el updates.

* lisp/emacs-lisp/copyright.el (copyright-at-end-flag)
(copyright-names-regexp): Add safety properties.
(copyright-year-ranges): New option.
(copyright-find-end): New function, split from copyright-update-year.
(copyright-update-year): Use copyright-find-end.
(copyright-fix-years): Optionally, convert years to ranges.
Handle years continued over comment lines.
Do not mess with the fill-prefix.
Do not call copyright-update.
(copyright-update-directory): Optionally, fix years rather than update.
Skip directories.  Find files literally, with only safe local vars.

* etc/NEWS: Mention copyright-fix-years and ranges.
parent d0cb8662
...@@ -607,6 +607,11 @@ means to prompt the user for command specifics, e.g. a merge location. ...@@ -607,6 +607,11 @@ means to prompt the user for command specifics, e.g. a merge location.
**** Currently supported by Bzr. **** Currently supported by Bzr.
** Miscellaneous
---
*** `copyright-fix-years' can optionally convert consecutive years to ranges.
* New Modes and Packages in Emacs 24.1 * New Modes and Packages in Emacs 24.1
......
2011-01-25 Glenn Morris <rgm@gnu.org>
* emacs-lisp/copyright.el (copyright-at-end-flag)
(copyright-names-regexp): Add safety properties.
(copyright-year-ranges): New option.
(copyright-find-end): New function, split from copyright-update-year.
(copyright-update-year): Use copyright-find-end.
(copyright-fix-years): Optionally, convert years to ranges.
Handle years continued over comment lines.
Do not mess with the fill-prefix.
Do not call copyright-update.
(copyright-update-directory): Optionally, fix years rather than update.
Skip directories. Find files literally, with only safe local vars.
2011-01-25 Stefan Monnier <monnier@iro.umontreal.ca> 2011-01-25 Stefan Monnier <monnier@iro.umontreal.ca>
   
* files.el (file-name-non-special): Only change buffer-file-name after * files.el (file-name-non-special): Only change buffer-file-name after
......
;;; copyright.el --- update the copyright notice in current buffer ;;; copyright.el --- update the copyright notice in current buffer
;; Copyright (C) 1991-1995, 1998, 2001-2011 ;; Copyright (C) 1991-1995, 1998, 2001-2011 Free Software Foundation, Inc.
;; Free Software Foundation, Inc.
;; Author: Daniel Pfeiffer <occitan@esperanto.org> ;; Author: Daniel Pfeiffer <occitan@esperanto.org>
;; Keywords: maint, tools ;; Keywords: maint, tools
...@@ -47,6 +46,7 @@ This is useful for ChangeLogs." ...@@ -47,6 +46,7 @@ This is useful for ChangeLogs."
:group 'copyright :group 'copyright
:type 'boolean :type 'boolean
:version "23.1") :version "23.1")
;;;###autoload(put 'copyright-at-end-flag 'safe-local-variable 'booleanp)
(defcustom copyright-regexp (defcustom copyright-regexp
"\\(©\\|@copyright{}\\|[Cc]opyright\\s *:?\\s *\\(?:(C)\\)?\ "\\(©\\|@copyright{}\\|[Cc]opyright\\s *:?\\s *\\(?:(C)\\)?\
...@@ -66,6 +66,11 @@ someone else or to a group for which you do not work." ...@@ -66,6 +66,11 @@ someone else or to a group for which you do not work."
:group 'copyright :group 'copyright
:type 'regexp) :type 'regexp)
;; The worst that can happen is a malicious regexp that overflows in
;; the regexp matcher, a minor nuisance. It's a pain to be always
;; prompted if you want to put this in a dir-locals.el.
;;;###autoload(put 'copyright-names-regexp 'safe-local-variable 'stringp)
(defcustom copyright-years-regexp (defcustom copyright-years-regexp
"\\(\\s *\\)\\([1-9]\\([-0-9, ';/*%#\n\t]\\|\\s<\\|\\s>\\)*[0-9]+\\)" "\\(\\s *\\)\\([1-9]\\([-0-9, ';/*%#\n\t]\\|\\s<\\|\\s>\\)*[0-9]+\\)"
"Match additional copyright notice years. "Match additional copyright notice years.
...@@ -73,6 +78,19 @@ The second \\( \\) construct must match the years." ...@@ -73,6 +78,19 @@ The second \\( \\) construct must match the years."
:group 'copyright :group 'copyright
:type 'regexp) :type 'regexp)
;; See "Copyright Notices" in maintain.info.
;; TODO? 'end only for ranges at the end, other for all ranges.
;; Minimum limit on the size of a range?
(defcustom copyright-year-ranges nil
"Non-nil if individual consecutive years should be replaced with a range.
For example: 2005, 2006, 2007, 2008 might be replaced with 2005-2008.
If you use ranges, you should add an explanatory note in a README file.
The function `copyright-fix-year' respects this variable."
:group 'copyright
:type 'boolean
:version "24.1")
;;;###autoload(put 'copyright-year-ranges 'safe-local-variable 'booleanp)
(defcustom copyright-query 'function (defcustom copyright-query 'function
"If non-nil, ask user before changing copyright. "If non-nil, ask user before changing copyright.
...@@ -139,11 +157,10 @@ This function sets the match-data that `copyright-update-year' uses." ...@@ -139,11 +157,10 @@ This function sets the match-data that `copyright-update-year' uses."
;; such an error is very inconvenient for the user. ;; such an error is very inconvenient for the user.
(error (message "Can't update copyright: %s" err) nil))) (error (message "Can't update copyright: %s" err) nil)))
(defun copyright-update-year (replace noquery) (defun copyright-find-end ()
;; This uses the match-data from copyright-find-copyright. "Possibly adjust the search performed by `copyright-find-copyright'.
(goto-char (match-end 1)) If the years continue onto multiple lines that are marked as comments,
;; If the years are continued onto multiple lines skips to the end of all the years."
;; that are marked as comments, skip to the end of the years anyway.
(while (save-excursion (while (save-excursion
(and (eq (following-char) ?,) (and (eq (following-char) ?,)
(progn (forward-char 1) t) (progn (forward-char 1) t)
...@@ -158,8 +175,12 @@ This function sets the match-data that `copyright-update-year' uses." ...@@ -158,8 +175,12 @@ This function sets the match-data that `copyright-update-year' uses."
(re-search-forward comment-start-skip) (re-search-forward comment-start-skip)
;; (2) Need the extra \\( \\) so that the years are subexp 3, as ;; (2) Need the extra \\( \\) so that the years are subexp 3, as
;; they are at note (1) above. ;; they are at note (1) above.
(re-search-forward (format "\\(%s\\)" copyright-years-regexp))) (re-search-forward (format "\\(%s\\)" copyright-years-regexp))))
(defun copyright-update-year (replace noquery)
;; This uses the match-data from copyright-find-copyright/end.
(goto-char (match-end 1))
(copyright-find-end)
;; Note that `current-time-string' isn't locale-sensitive. ;; Note that `current-time-string' isn't locale-sensitive.
(setq copyright-current-year (substring (current-time-string) -4)) (setq copyright-current-year (substring (current-time-string) -4))
(unless (string= (buffer-substring (- (match-end 3) 2) (match-end 3)) (unless (string= (buffer-substring (- (match-end 3) 2) (match-end 3))
...@@ -217,6 +238,7 @@ interactively." ...@@ -217,6 +238,7 @@ interactively."
(save-restriction (save-restriction
;; If names-regexp doesn't match, we should not mess with ;; If names-regexp doesn't match, we should not mess with
;; the years _or_ the GPL version. ;; the years _or_ the GPL version.
;; TODO there may be multiple copyrights we should update.
(when (copyright-find-copyright) (when (copyright-find-copyright)
(copyright-update-year arg noquery) (copyright-update-year arg noquery)
(goto-char (copyright-start-point)) (goto-char (copyright-start-point))
...@@ -246,42 +268,78 @@ interactively." ...@@ -246,42 +268,78 @@ interactively."
nil)) nil))
;; FIXME should be within 50 years of present (cf calendar). ;; FIXME heuristic should be within 50 years of present (cf calendar).
;;;###autoload ;;;###autoload
(defun copyright-fix-years () (defun copyright-fix-years ()
"Convert 2 digit years to 4 digit years. "Convert 2 digit years to 4 digit years.
Uses heuristic: year >= 50 means 19xx, < 50 means 20xx." Uses heuristic: year >= 50 means 19xx, < 50 means 20xx.
If `copyright-year-ranges' (which see) is non-nil, also
independently replaces consecutive years with a range."
(interactive) (interactive)
;; TODO there may be multiple copyrights we should fix.
(if (copyright-find-copyright) (if (copyright-find-copyright)
(let ((s (match-beginning 2)) (let ((s (match-beginning 3))
(e (copy-marker (1+ (match-end 2))))
(p (make-marker)) (p (make-marker))
last) ;; Not line-beg-pos, so we don't mess up leading whitespace.
(copystart (match-beginning 0))
e last sep year prev-year first-year range-start range-end)
;; In case years are continued over multiple, commented lines.
(goto-char (match-end 1))
(copyright-find-end)
(setq e (copy-marker (1+ (match-end 3))))
(goto-char s) (goto-char s)
(while (re-search-forward "[0-9]+" e t) (while (re-search-forward "[0-9]+" e t)
(set-marker p (point)) (set-marker p (point))
(goto-char (match-beginning 0)) (goto-char (match-beginning 0))
(let ((sep (char-before)) (setq year (string-to-number (match-string 0)))
(year (string-to-number (match-string 0)))) (and (setq sep (char-before))
(when (and sep (/= (char-syntax sep) ?\s)
(/= (char-syntax sep) ?\s) (/= sep ?-)
(/= sep ?-)) (insert " "))
(insert " ")) (when (< year 100)
(when (< year 100) (insert (if (>= year 50) "19" "20"))
(insert (if (>= year 50) "19" "20")))) (setq year (+ year (if (>= year 50) 1900 2000))))
(goto-char p) (goto-char p)
(setq last p)) (when copyright-year-ranges
;; If the previous thing was a range, don't try to tack more on.
;; Ie not 2000-2005 -> 2000-2005-2007
;; TODO should merge into existing range if possible.
(if (eq sep ?-)
(setq prev-year nil
year nil)
(if (and prev-year (= year (1+ prev-year)))
(setq range-end (point))
(when (and first-year prev-year
(> prev-year first-year))
(goto-char range-end)
(delete-region range-start range-end)
(insert (format "-%d" prev-year))
(goto-char p))
(setq first-year year
range-start (point)))))
(setq prev-year year
last p))
(when last (when last
(when (and copyright-year-ranges
first-year prev-year
(> prev-year first-year))
(goto-char range-end)
(delete-region range-start range-end)
(insert (format "-%d" prev-year)))
(goto-char last) (goto-char last)
;; Don't mess up whitespace after the years. ;; Don't mess up whitespace after the years.
(skip-chars-backward " \t") (skip-chars-backward " \t")
(save-restriction (save-restriction
(narrow-to-region (copyright-start-point) (point)) (narrow-to-region copystart (point))
(let ((fill-prefix " ")) ;; This is clearly wrong, eg what about comment markers?
(fill-region s last)))) ;;; (let ((fill-prefix " "))
;; TODO do not break copyright owner over lines.
(fill-region (point-min) (point-max))))
(set-marker e nil) (set-marker e nil)
(set-marker p nil) (set-marker p nil))
(copyright-update nil t)) ;; Simply reformatting the years is not copyrightable, so it does
;; not seem right to call this. Also it messes with ranges.
;;; (copyright-update nil t))
(message "No copyright message"))) (message "No copyright message")))
;;;###autoload ;;;###autoload
...@@ -296,17 +354,24 @@ Uses heuristic: year >= 50 means 19xx, < 50 means 20xx." ...@@ -296,17 +354,24 @@ Uses heuristic: year >= 50 means 19xx, < 50 means 20xx."
(message "Copyright extends beyond `copyright-limit' and won't be updated automatically.")) (message "Copyright extends beyond `copyright-limit' and won't be updated automatically."))
comment-end \n) comment-end \n)
;; TODO: recurse, exclude COPYING etc.
;;;###autoload ;;;###autoload
(defun copyright-update-directory (directory match) (defun copyright-update-directory (directory match &optional fix)
"Update copyright notice for all files in DIRECTORY matching MATCH." "Update copyright notice for all files in DIRECTORY matching MATCH.
If FIX is non-nil, run `copyright-fix-years' instead."
(interactive "DDirectory: \nMFilenames matching (regexp): ") (interactive "DDirectory: \nMFilenames matching (regexp): ")
(dolist (file (directory-files directory t match nil)) (dolist (file (directory-files directory t match nil))
(message "Updating file `%s'" file) (unless (file-directory-p file)
(find-file file) (message "Updating file `%s'" file)
(let ((copyright-query nil)) (find-file-literally file)
(copyright-update)) (let ((inhibit-read-only t)
(save-buffer) (enable-local-variables :safe)
(kill-buffer (current-buffer)))) copyright-query)
(if fix
(copyright-fix-years)
(copyright-update)))
(save-buffer)
(kill-buffer (current-buffer)))))
(provide 'copyright) (provide 'copyright)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment