X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=lisp%2Fgnus-util.el;h=65707dd3f4122d7507de01159b3077d399f748cb;hb=e2696774a2e225ea60d46cc665d4232c80412731;hp=00331200a7a389485ce1cac1bbf0ee75af2bedbb;hpb=49d38b41c190eaab2cb34294fac7302a9c9ea353;p=elisp%2Fgnus.git- diff --git a/lisp/gnus-util.el b/lisp/gnus-util.el index 0033120..65707dd 100644 --- a/lisp/gnus-util.el +++ b/lisp/gnus-util.el @@ -30,18 +30,25 @@ ;; used by Gnus and may be used by any other package without loading ;; Gnus first. +;; [Unfortunately, it does depend on other parts of Gnus, e.g. the +;; autoloads and defvars below...] + ;;; Code: (eval-when-compile (require 'cl) ;; Fixme: this should be a gnus variable, not nnmail-. - (defvar nnmail-pathname-coding-system)) -(eval-when-compile (require 'static)) + (defvar nnmail-pathname-coding-system) + + ;; Inappropriate references to other parts of Gnus. + (defvar gnus-emphasize-whitespace-regexp) + ) -(require 'custom) (require 'time-date) (require 'netrc) +(eval-when-compile (require 'static)) + (eval-and-compile (autoload 'message-fetch-field "message") (autoload 'gnus-get-buffer-window "gnus-win") @@ -57,20 +64,7 @@ (defalias 'gnus-replace-in-string 'replace-in-string)) ((fboundp 'replace-regexp-in-string) (defun gnus-replace-in-string (string regexp newtext &optional literal) - (replace-regexp-in-string regexp newtext string nil literal))) - (t - (defun gnus-replace-in-string (string regexp newtext &optional literal) - (let ((start 0) tail) - (while (string-match regexp string start) - (setq tail (- (length string) (match-end 0))) - (setq string (replace-match newtext nil literal string)) - (setq start (- (length string) tail)))) - string)))) - -;;; bring in the netrc functions as aliases -(defalias 'gnus-netrc-get 'netrc-get) -(defalias 'gnus-netrc-machine 'netrc-machine) -(defalias 'gnus-parse-netrc 'netrc-parse) + (replace-regexp-in-string regexp newtext string nil literal))))) (defun gnus-boundp (variable) "Return non-nil if VARIABLE is bound and non-nil." @@ -127,41 +121,12 @@ (funcall (if (stringp buffer) 'get-buffer 'buffer-name) buffer)))) -(static-cond - ((fboundp 'point-at-bol) - (defalias 'gnus-point-at-bol 'point-at-bol)) - ((fboundp 'line-beginning-position) - (defalias 'gnus-point-at-bol 'line-beginning-position)) - (t - (defun gnus-point-at-bol () - "Return point at the beginning of the line." - (let ((p (point))) - (beginning-of-line) - (prog1 - (point) - (goto-char p)))) - )) -(static-cond - ((fboundp 'point-at-eol) - (defalias 'gnus-point-at-eol 'point-at-eol)) - ((fboundp 'line-end-position) - (defalias 'gnus-point-at-eol 'line-end-position)) - (t - (defun gnus-point-at-eol () - "Return point at the end of the line." - (let ((p (point))) - (end-of-line) - (prog1 - (point) - (goto-char p)))) - )) - ;; The LOCAL arg to `add-hook' is interpreted differently in Emacs and ;; XEmacs. In Emacs we don't need to call `make-local-hook' first. ;; It's harmless, though, so the main purpose of this alias is to shut ;; up the byte compiler. (defalias 'gnus-make-local-hook - (if (eq (get 'make-local-hook 'byte-compile) + (if (eq (get 'make-local-hook 'byte-compile) 'byte-compile-obsolete) 'ignore ; Emacs 'make-local-hook)) ; XEmacs @@ -180,7 +145,7 @@ ;; Delete the current line (and the next N lines). (defmacro gnus-delete-line (&optional n) - `(delete-region (gnus-point-at-bol) + `(delete-region (point-at-bol) (progn (forward-line ,(or n 1)) (point)))) (defun gnus-byte-code (func) @@ -193,6 +158,11 @@ (cons 'progn (cddr fval))))) (defun gnus-extract-address-components (from) + "Extract address components from a From header. +Given an RFC-822 address FROM, extract full name and canonical address. +Returns a list of the form (FULL-NAME CANONICAL-ADDRESS). Much more simple +solution than `mail-extract-address-components', which works much better, but +is slower." (let (name address) ;; First find the address - the thing with the @ in it. This may ;; not be accurate in mail addresses, but does the trick most of @@ -225,8 +195,7 @@ "Return the value of the header FIELD of current article." (save-excursion (save-restriction - (let ((case-fold-search t) - (inhibit-point-motion-hooks t)) + (let ((inhibit-point-motion-hooks t)) (nnheader-narrow-to-headers) (message-fetch-field field))))) @@ -238,7 +207,7 @@ (defun gnus-goto-colon () (beginning-of-line) - (let ((eol (gnus-point-at-eol))) + (let ((eol (point-at-eol))) (goto-char (or (text-property-any (point) eol 'gnus-position t) (search-forward ":" eol t) (point))))) @@ -253,12 +222,15 @@ (defun gnus-remove-text-with-property (prop) "Delete all text in the current buffer with text property PROP." - (save-excursion - (goto-char (point-min)) - (while (not (eobp)) - (while (get-text-property (point) prop) - (delete-char 1)) - (goto-char (next-single-property-change (point) prop nil (point-max)))))) + (let ((start (point-min)) + end) + (unless (get-text-property start prop) + (setq start (next-single-property-change start prop))) + (while start + (setq end (text-property-any start (point-max) prop nil)) + (delete-region start (or end (point-max))) + (setq start (when end + (next-single-property-change start prop)))))) (defun gnus-newsgroup-directory-form (newsgroup) "Make hierarchical directory name from NEWSGROUP name." @@ -358,19 +330,20 @@ ;; age-depending date representations. (e.g. just the time if it's ;; from today, the day of the week if it's within the last 7 days and ;; the full date if it's older) + (defun gnus-seconds-today () - "Returns the number of seconds passed today" + "Return the number of seconds passed today." (let ((now (decode-time (current-time)))) (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600)))) (defun gnus-seconds-month () - "Returns the number of seconds passed this month" + "Return the number of seconds passed this month." (let ((now (decode-time (current-time)))) (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600) (* (- (car (nthcdr 3 now)) 1) 3600 24)))) (defun gnus-seconds-year () - "Returns the number of seconds passed this year" + "Return the number of seconds passed this year." (let ((now (decode-time (current-time))) (days (format-time-string "%j" (current-time)))) (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600) @@ -401,30 +374,25 @@ seconds passed since the start of today, of this month, of this year, respectively.") (defun gnus-user-date (messy-date) - "Format the messy-date acording to gnus-user-date-format-alist. + "Format the messy-date according to gnus-user-date-format-alist. Returns \" ? \" if there's bad input or if an other error occurs. Input should look like this: \"Sun, 14 Oct 2001 13:34:39 +0200\"." (condition-case () - (let* ((messy-date (safe-date-to-time messy-date)) - (now (current-time)) + (let* ((messy-date (time-to-seconds (safe-date-to-time messy-date))) + (now (time-to-seconds (current-time))) ;;If we don't find something suitable we'll use this one - (my-format "%b %m '%y") - (high (lsh (- (car now) (car messy-date)) 16))) - (if (and (> high -1) (= (logand high 65535) 0)) - ;;overflow and bad input - (let* ((difference (+ high (- (car (cdr now)) - (car (cdr messy-date))))) - (templist gnus-user-date-format-alist) - (top (eval (caar templist)))) - (while (if (numberp top) (< top difference) (not top)) - (progn - (setq templist (cdr templist)) - (setq top (eval (caar templist))))) - (if (stringp (cdr (car templist))) - (setq my-format (cdr (car templist)))))) - (format-time-string (eval my-format) messy-date)) + (my-format "%b %d '%y")) + (let* ((difference (- now messy-date)) + (templist gnus-user-date-format-alist) + (top (eval (caar templist)))) + (while (if (numberp top) (< top difference) (not top)) + (progn + (setq templist (cdr templist)) + (setq top (eval (caar templist))))) + (if (stringp (cdr (car templist))) + (setq my-format (cdr (car templist))))) + (format-time-string (eval my-format) (seconds-to-time messy-date))) (error " ? "))) -;;end of Frank's code (defun gnus-dd-mmm (messy-date) "Return a string like DD-MMM from a big messy string." @@ -566,13 +534,7 @@ If N, return the Nth ancestor instead." (defun gnus-read-event-char (&optional prompt) "Get the next event." - (let ((event (condition-case nil - (read-event prompt) - ;; `read-event' doesn't allow arguments in Mule 2.3 - (wrong-number-of-arguments - (when prompt - (message "%s" prompt)) - (read-event))))) + (let ((event (read-event prompt))) ;; should be gnus-characterp, but this can't be called in XEmacs anyway (cons (and (numberp event) event) event))) @@ -601,7 +563,8 @@ If N, return the Nth ancestor instead." (set-buffer gnus-work-buffer) (erase-buffer)) (set-buffer (gnus-get-buffer-create gnus-work-buffer)) - (kill-all-local-variables))) + (kill-all-local-variables) + (set-buffer-multibyte t))) (defmacro gnus-group-real-name (group) "Find the real name of a foreign newsgroup." @@ -611,7 +574,7 @@ If N, return the Nth ancestor instead." gname))) (defun gnus-make-sort-function (funs) - "Return a composite sort condition based on the functions in FUNC." + "Return a composite sort condition based on the functions in FUNS." (cond ;; Just a simple function. ((functionp funs) funs) @@ -628,7 +591,7 @@ If N, return the Nth ancestor instead." (car funs)))) (defun gnus-make-sort-function-1 (funs) - "Return a composite sort condition based on the functions in FUNC." + "Return a composite sort condition based on the functions in FUNS." (let ((function (car funs)) (first 't1) (last 't2)) @@ -677,8 +640,7 @@ and `print-level' to nil." (defun gnus-make-directory (directory) "Make DIRECTORY (and all its parents) if it doesn't exist." (require 'nnmail) - (let ((file-name-coding-system nnmail-pathname-coding-system) - (pathname-coding-system nnmail-pathname-coding-system)) + (let ((file-name-coding-system nnmail-pathname-coding-system)) (when (and directory (not (file-exists-p directory))) (make-directory directory t))) @@ -688,8 +650,7 @@ and `print-level' to nil." "Write the current buffer's contents to FILE." ;; Make sure the directory exists. (gnus-make-directory (file-name-directory file)) - (let ((file-name-coding-system nnmail-pathname-coding-system) - (pathname-coding-system nnmail-pathname-coding-system)) + (let ((file-name-coding-system nnmail-pathname-coding-system)) ;; Write the buffer. (write-region (point-min) (point-max) file nil 'quietly))) @@ -846,10 +807,31 @@ with potentially long computations." ;;; Functions for saving to babyl/mail files. -(defvar rmail-default-rmail-file) +(eval-when-compile + (condition-case nil + (progn + (require 'rmail) + (autoload 'rmail-update-summary "rmailsum")) + (error + (define-compiler-macro rmail-select-summary (&rest body) + ;; Rmail of the XEmacs version is supplied by the package, and + ;; requires tm and apel packages. However, there may be those + ;; who haven't installed those packages. This macro helps such + ;; people even if they install those packages later. + `(eval '(rmail-select-summary ,@body))) + ;; If there's rmail but there's no tm (or there's apel of the + ;; mainstream, not the XEmacs version), loading rmail of the XEmacs + ;; version fails halfway, however it provides the rmail-select-summary + ;; macro which uses the following functions: + (autoload 'rmail-summary-displayed "rmail") + (autoload 'rmail-maybe-display-summary "rmail"))) + (defvar rmail-default-rmail-file) + (defvar mm-text-coding-system)) + (defun gnus-output-to-rmail (filename &optional ask) "Append the current article to an Rmail file named FILENAME." (require 'rmail) + (require 'mm-util) ;; Most of these codes are borrowed from rmailout.el. (setq filename (expand-file-name filename)) (setq rmail-default-rmail-file filename) @@ -877,8 +859,7 @@ with potentially long computations." ;; Decide whether to append to a file or to an Emacs buffer. (let ((outbuf (get-file-buffer filename))) (if (not outbuf) - (let ((file-name-coding-system nnmail-pathname-coding-system) - (pathname-coding-system nnmail-pathname-coding-system)) + (let ((file-name-coding-system nnmail-pathname-coding-system)) (write-region-as-binary (point-min) (point-max) filename 'append)) ;; File has been visited, in buffer OUTBUF. @@ -949,8 +930,7 @@ with potentially long computations." (insert "\n")) (insert "\n")) (goto-char (point-max)) - (let ((file-name-coding-system nnmail-pathname-coding-system) - (pathname-coding-system nnmail-pathname-coding-system)) + (let ((file-name-coding-system nnmail-pathname-coding-system)) (write-region-as-binary (point-min) (point-max) filename 'append)))) ;; File has been visited, in buffer OUTBUF. @@ -975,7 +955,7 @@ with potentially long computations." (insert "\^_"))) (defun gnus-map-function (funs arg) - "Applies the result of the first function in FUNS to the second, and so on. + "Apply the result of the first function in FUNS to the second, and so on. ARG is passed to the first function." (while funs (setq arg (funcall (pop funs) arg))) @@ -1032,7 +1012,7 @@ Return the modified alist." `(setq ,alist (delq (,fun ,key ,alist) ,alist)))) (defun gnus-globalify-regexp (re) - "Returns a regexp that matches a whole line, iff RE matches a part of it." + "Return a regexp that matches a whole line, iff RE matches a part of it." (concat (unless (string-match "^\\^" re) "^.*") re (unless (string-match "\\$$" re) ".*$"))) @@ -1064,8 +1044,7 @@ Return the modified alist." t)) (defun gnus-write-active-file (file hashtb &optional full-names) - (let ((output-coding-system nnmail-active-file-coding-system) - (coding-system-for-write nnmail-active-file-coding-system)) + (let ((coding-system-for-write nnmail-active-file-coding-system)) (with-temp-file file (mapatoms (lambda (sym) @@ -1232,7 +1211,6 @@ If you find some problem with the directory separator character, try If optional second argument ALLOW-NEWLINES is non-nil, then allow the decoding of carriage returns and line feeds in the string, which is normally forbidden in URL encoding." - (setq str (or (mm-subst-char-in-string ?+ ? str) "")) ; why `or'? (let ((tmp "") (case-fold-search t)) (while (string-match "%[0-9a-f][0-9a-f]" str) @@ -1267,32 +1245,12 @@ SPEC is a predicate specifier that contains stuff like `or', `and', `(,(car spec) ,@(mapcar 'gnus-make-predicate-1 (cdr spec))) (error "Invalid predicate specifier: %s" spec))))) -(defun gnus-local-map-property (map) - "Return a list suitable for a text property list specifying keymap MAP." - (cond - ((featurep 'xemacs) - (list 'keymap map)) - ((>= emacs-major-version 21) - (list 'keymap map)) - (t - (list 'local-map map)))) - -(defmacro gnus-completing-read-maybe-default (prompt table &optional predicate - require-match initial-contents - history default) - "Like `completing-read', allowing for non-existent 7th arg in older XEmacsen." - `(completing-read ,prompt ,table ,predicate ,require-match - ,initial-contents ,history - ,@(if (and (featurep 'xemacs) (< emacs-minor-version 2)) - () - (list default)))) - (defun gnus-completing-read (prompt table &optional predicate require-match history) (when (and history (not (boundp history))) (set history nil)) - (gnus-completing-read-maybe-default + (completing-read (if (symbol-value history) (concat prompt " (" (car (symbol-value history)) "): ") (concat prompt ": ")) @@ -1347,8 +1305,9 @@ CHOICE is a list of the choice char and help message at IDX." (while (not tchar) (message "%s (%s): " prompt - (mapconcat (lambda (s) (char-to-string (car s))) - choice ", ")) + (concat + (mapconcat (lambda (s) (char-to-string (car s))) + choice ", ") ", ?")) (setq tchar (read-char)) (when (not (assq tchar choice)) (setq tchar nil) @@ -1409,17 +1368,9 @@ CHOICE is a list of the choice char and help message at IDX." (x-focus-frame frame)) ((eq window-system 'w32) (w32-focus-frame frame))) - (when (or (not (boundp 'focus-follows-mouse)) - (symbol-value 'focus-follows-mouse)) + (when focus-follows-mouse (set-mouse-position frame (1- (frame-width frame)) 0))))) -(unless (fboundp 'frame-parameter) - (defalias 'frame-parameter - (lambda (frame parameter) - "Return FRAME's value for parameter PARAMETER. -If FRAME is nil, describe the currently selected frame." - (cdr (assq parameter (frame-parameters frame)))))) - (defun gnus-frame-or-window-display-name (object) "Given a frame or window, return the associated display name. Return nil otherwise." @@ -1485,6 +1436,70 @@ predicate on the elements." (push (pop list1) res))) (nconc (nreverse res) list1 list2)))) +(eval-when-compile + (defvar xemacs-codename)) + +(defun gnus-emacs-version () + "Stringified Emacs version." + (let ((system-v + (cond + ((eq gnus-user-agent 'emacs-gnus-config) + system-configuration) + ((eq gnus-user-agent 'emacs-gnus-type) + (symbol-name system-type)) + (t nil)))) + (cond + ((eq gnus-user-agent 'gnus) + nil) + ((string-match "^\\(\\([.0-9]+\\)*\\)\\.[0-9]+$" emacs-version) + (concat "Emacs/" (match-string 1 emacs-version) + (if system-v + (concat " (" system-v ")") + ""))) + ((string-match + "\\([A-Z]*[Mm][Aa][Cc][Ss]\\)[^(]*\\(\\((beta.*)\\|'\\)\\)?" + emacs-version) + (concat + (match-string 1 emacs-version) + (format "/%d.%d" emacs-major-version emacs-minor-version) + (if (match-beginning 3) + (match-string 3 emacs-version) + "") + (if (boundp 'xemacs-codename) + (concat + " (" xemacs-codename + (if system-v + (concat ", " system-v ")") + ")")) + ""))) + (t emacs-version)))) + +(defun gnus-rename-file (old-path new-path &optional trim) + "Rename OLD-PATH as NEW-PATH. If TRIM, recursively delete +empty directories from OLD-PATH." + (when (file-exists-p old-path) + (let* ((old-dir (file-name-directory old-path)) + (old-name (file-name-nondirectory old-path)) + (new-dir (file-name-directory new-path)) + (new-name (file-name-nondirectory new-path)) + temp) + (gnus-make-directory new-dir) + (rename-file old-path new-path t) + (when trim + (while (progn (setq temp (directory-files old-dir)) + (while (member (car temp) '("." "..")) + (setq temp (cdr temp))) + (= (length temp) 0)) + (delete-directory old-dir) + (setq old-dir (file-name-as-directory + (file-truename + (concat old-dir ".."))))))))) + +(defun gnus-set-file-modes (filename mode) + "Wrapper for set-file-modes." + (ignore-errors + (set-file-modes filename mode))) + (provide 'gnus-util) ;;; gnus-util.el ends here