X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=elmo%2Felmo-util.el;h=56ac49f44136da8df69c6d0f6747fa6d57d677a5;hb=c2738fdc4e616fb55973a7e285432f60af6c1c57;hp=11a1813c4bc7c368e1f2cac0dd06c6812449347c;hpb=c55809158bb4e70149ae2bc448aed4c93428127c;p=elisp%2Fwanderlust.git diff --git a/elmo/elmo-util.el b/elmo/elmo-util.el index 11a1813..56ac49f 100644 --- a/elmo/elmo-util.el +++ b/elmo/elmo-util.el @@ -75,8 +75,6 @@ (filename newname &optional ok-if-already-exists) (copy-file filename newname ok-if-already-exists t))) -(defalias 'elmo-read 'read) - (defmacro elmo-set-work-buf (&rest body) "Execute BODY on work buffer. Work buffer remains." (` (save-excursion @@ -132,7 +130,8 @@ File content is encoded with MIME-CHARSET." Directory of the file is created if it doesn't exist. File content is encoded with MIME-CHARSET." (elmo-set-work-buf - (prin1 object (current-buffer)) + (let (print-length print-level) + (prin1 object (current-buffer))) ;;;(princ "\n" (current-buffer)) (elmo-save-buffer filename mime-charset))) @@ -150,7 +149,7 @@ File content is encoded with MIME-CHARSET." (format "%s (%s): " prompt default) (mapcar 'list (append '("AND" "OR" - "Last" "First" + "Last" "First" "Flag" "From" "Subject" "To" "Cc" "Body" "Since" "Before" "ToCc" "!From" "!Subject" "!To" "!Cc" "!Body" @@ -170,7 +169,7 @@ File content is encoded with MIME-CHARSET." (concat field "(2) Search by") default) ")")) ((string-match "Since\\|Before" field) - (let ((default (format-time-string "%Y-%m-%d" (current-time)))) + (let ((default (format-time-string "%Y-%m-%d"))) (setq value (completing-read (format "Value for '%s' [%s]: " field default) (mapcar (function @@ -179,6 +178,15 @@ File content is encoded with MIME-CHARSET." elmo-date-descriptions))) (concat (downcase field) ":" (if (equal value "") default value)))) + ((string= field "Flag") + (setq value (completing-read + (format "Value for '%s': " field) + (mapcar 'list + '("unread" "important" "answered" "digest" "any")))) + (unless (string-match (concat "^" elmo-condition-atom-regexp "$") + value) + (setq value (prin1-to-string value))) + (concat (downcase field) ":" value)) (t (setq value (read-from-minibuffer (format "Value for '%s': " field))) (unless (string-match (concat "^" elmo-condition-atom-regexp "$") @@ -234,7 +242,7 @@ Return value is a cons cell of (STRUCTURE . REST)" (goto-char (match-end 0)))) ;; search-key ::= [A-Za-z-]+ ;; ;; "since" / "before" / "last" / "first" / -;; ;; "body" / field-name +;; ;; "body" / "mark" / field-name ((looking-at "\\(!\\)? *\\([A-Za-z-]+\\) *: *") (goto-char (match-end 0)) (let ((search-key (vector @@ -269,7 +277,7 @@ Return value is a cons cell of (STRUCTURE . REST)" (defun elmo-condition-parse-search-value () (cond ((looking-at "\"") - (elmo-read (current-buffer))) + (read (current-buffer))) ((or (looking-at "yesterday") (looking-at "lastweek") (looking-at "lastmonth") (looking-at "lastyear") (looking-at "[0-9]+ *daysago") @@ -335,17 +343,12 @@ Return value is a cons cell of (STRUCTURE . REST)" lst) (defun elmo-list-insert (list element after) - "Insert an ELEMENT to the LIST, just after AFTER." - (let ((li list) - (curn 0) - p pn) - (while li - (if (eq (car li) after) - (setq p li pn curn li nil) - (incf curn)) - (setq li (cdr li))) - (if pn - (setcdr (nthcdr pn list) (cons element (cdr p))) + (let* ((match (memq after list)) + (rest (and match (cdr (memq after list))))) + (if match + (progn + (setcdr match (list element)) + (nconc list rest)) (nconc list (list element))))) (defun elmo-string-partial-p (string) @@ -422,7 +425,8 @@ Return value is a cons cell of (STRUCTURE . REST)" (save-excursion (let ((filename (expand-file-name elmo-passwd-alist-file-name elmo-msgdb-directory)) - (tmp-buffer (get-buffer-create " *elmo-passwd-alist-tmp*"))) + (tmp-buffer (get-buffer-create " *elmo-passwd-alist-tmp*")) + print-length print-level) (set-buffer tmp-buffer) (erase-buffer) (prin1 elmo-passwd-alist tmp-buffer) @@ -688,7 +692,8 @@ Return value is a cons cell of (STRUCTURE . REST)" (setq result (+ result (or (elmo-disk-usage (car files)) 0))) (setq files (cdr files))) result) - (float (nth 7 file-attr)))))) + (float (nth 7 file-attr))) + 0))) (defun elmo-get-last-accessed-time (path &optional dir) "Return the last accessed time of PATH." @@ -710,14 +715,14 @@ Return value is a cons cell of (STRUCTURE . REST)" (setq last-modified (+ (* (nth 0 last-modified) (float 65536)) (nth 1 last-modified))))) -(defun elmo-make-directory (path) +(defun elmo-make-directory (path &optional mode) "Create directory recursively." (let ((parent (directory-file-name (file-name-directory path)))) (if (null (file-directory-p parent)) (elmo-make-directory parent)) (make-directory path) - (if (string= path (expand-file-name elmo-msgdb-directory)) - (set-file-modes path (+ (* 64 7) (* 8 0) 0))))) ; chmod 0700 + (set-file-modes path (or mode + (+ (* 64 7) (* 8 0) 0))))) ; chmod 0700 (defun elmo-delete-directory (path &optional no-hierarchy) "Delete directory recursively." @@ -737,15 +742,21 @@ Return value is a cons cell of (STRUCTURE . REST)" (unless hierarchy (delete-directory path))))) +(defun elmo-delete-match-files (path regexp &optional remove-if-empty) + "Delete directory files specified by PATH. +If optional REMOVE-IF-EMPTY is non-nil, delete directory itself if +the directory becomes empty after deletion." + (when (stringp path) ; nil is not permitted. + (dolist (file (directory-files path t regexp)) + (delete-file file)) + (if remove-if-empty + (ignore-errors + (delete-directory path) ; should be removed if empty. + )))) + (defun elmo-list-filter (l1 l2) - "L1 is filter." - (if (eq l1 t) - ;; t means filter all. - nil - (if l1 - (elmo-delete-if (lambda (x) (not (memq x l1))) l2) - ;; filter is nil - l2))) + "Rerurn a list from L2 in which each element is a member of L1." + (elmo-delete-if (lambda (x) (not (memq x l1))) l2)) (defsubst elmo-list-delete-if-smaller (list number) (let ((ret-val (copy-sequence list))) @@ -757,7 +768,7 @@ Return value is a cons cell of (STRUCTURE . REST)" (defun elmo-list-diff (list1 list2 &optional mes) (if mes - (message mes)) + (message "%s" mes)) (let ((clist1 (copy-sequence list1)) (clist2 (copy-sequence list2))) (while list2 @@ -767,7 +778,7 @@ Return value is a cons cell of (STRUCTURE . REST)" (setq clist2 (delq (car list1) clist2)) (setq list1 (cdr list1))) (if mes - (message (concat mes "done."))) + (message "%sdone" mes)) (list clist1 clist2))) (defun elmo-list-bigger-diff (list1 list2 &optional mes) @@ -939,9 +950,11 @@ Return value is a cons cell of (STRUCTURE . REST)" file (nth 2 condition) number number-list))))) (defmacro elmo-get-hash-val (string hashtable) - (let ((sym (list 'intern-soft string hashtable))) - (list 'if (list 'boundp sym) - (list 'symbol-value sym)))) + `(and (stringp ,string) + ,hashtable + (let ((sym (intern-soft ,string ,hashtable))) + (if (boundp sym) + (symbol-value sym))))) (defmacro elmo-set-hash-val (string value hashtable) (list 'set (list 'intern string hashtable) value)) @@ -977,15 +990,16 @@ Emacs 19.28 or earlier does not have `unintern'." (defsubst elmo-mime-string (string) "Normalize MIME encoded STRING." - (and string - (let (str) - (elmo-set-work-buf - (elmo-set-buffer-multibyte default-enable-multibyte-characters) - (setq str (eword-decode-string - (decode-mime-charset-string string elmo-mime-charset))) - (setq str (encode-mime-charset-string str elmo-mime-charset)) - (elmo-set-buffer-multibyte nil) - str)))) + (and string + (elmo-set-work-buf + (elmo-set-buffer-multibyte default-enable-multibyte-characters) + (setq string + (encode-mime-charset-string + (eword-decode-and-unfold-unstructured-field-body + string) + elmo-mime-charset)) + (elmo-set-buffer-multibyte nil) + string))) (defsubst elmo-collect-field (beg end downcase-field-name) (save-excursion @@ -1090,13 +1104,15 @@ Emacs 19.28 or earlier does not have `unintern'." (setq lst (cdr lst))) result)) -(defun elmo-list-delete (list1 list2) +(defun elmo-list-delete (list1 list2 &optional delete-function) "Delete by side effect any occurrences equal to elements of LIST1 from LIST2. Return the modified LIST2. Deletion is done with `delete'. Write `(setq foo (elmo-list-delete bar foo))' to be sure of changing -the value of `foo'." +the value of `foo'. +If optional DELETE-FUNCTION is speficied, it is used as delete procedure." + (setq delete-function (or delete-function 'delete)) (while list1 - (setq list2 (delete (car list1) list2)) + (setq list2 (funcall delete-function (car list1) list2)) (setq list1 (cdr list1))) list2) @@ -1206,6 +1222,23 @@ the value of `foo'." (when (>= new-rate 100) (elmo-progress-clear label)))))) +(put 'elmo-with-progress-display 'lisp-indent-function '2) +(def-edebug-spec elmo-with-progress-display + (form (symbolp form &optional form) &rest form)) + +(defmacro elmo-with-progress-display (condition spec &rest body) + "Evaluate BODY with progress gauge if CONDITION is non-nil. +SPEC is a list as followed (LABEL MAX-VALUE [FORMAT])." + (let ((label (car spec)) + (max-value (cadr spec)) + (fmt (caddr spec))) + `(unwind-protect + (progn + (when ,condition + (elmo-progress-set (quote ,label) ,max-value ,fmt)) + ,@body) + (elmo-progress-clear (quote ,label))))) + (defun elmo-time-expire (before-time diff-time) (let* ((current (current-time)) (rest (when (< (nth 1 current) (nth 1 before-time)) @@ -1252,7 +1285,6 @@ But if optional argument AUTO is non-nil, DEFAULT is returned." (y-or-n-p prompt))) (defun elmo-string-member (string slist) - "Return t if STRING is a member of the SLIST." (catch 'found (while slist (if (and (stringp (car slist)) @@ -1260,6 +1292,25 @@ But if optional argument AUTO is non-nil, DEFAULT is returned." (throw 'found t)) (setq slist (cdr slist))))) +(cond ((fboundp 'member-ignore-case) + (defalias 'elmo-string-member-ignore-case 'member-ignore-case)) + ((fboundp 'compare-strings) + (defun elmo-string-member-ignore-case (elt list) + "Like `member', but ignores differences in case and text representation. +ELT must be a string. Upper-case and lower-case letters are treated as equal. +Unibyte strings are converted to multibyte for comparison." + (while (and list (not (eq t (compare-strings elt 0 nil (car list) 0 nil t)))) + (setq list (cdr list))) + list)) + (t + (defun elmo-string-member-ignore-case (elt list) + "Like `member', but ignores differences in case and text representation. +ELT must be a string. Upper-case and lower-case letters are treated as equal." + (let ((str (downcase elt))) + (while (and list (not (string= str (downcase (car list))))) + (setq list (cdr list))) + list)))) + (defun elmo-string-match-member (str list &optional case-ignore) (let ((case-fold-search case-ignore)) (catch 'member @@ -1349,6 +1400,39 @@ But if optional argument AUTO is non-nil, DEFAULT is returned." (setq alist (cdr alist))) matches)) +(defun elmo-expand-newtext (newtext original) + (let ((len (length newtext)) + (pos 0) + c expanded beg N did-expand) + (while (< pos len) + (setq beg pos) + (while (and (< pos len) + (not (= (aref newtext pos) ?\\))) + (setq pos (1+ pos))) + (unless (= beg pos) + (push (substring newtext beg pos) expanded)) + (when (< pos len) + ;; We hit a \; expand it. + (setq did-expand t + pos (1+ pos) + c (aref newtext pos)) + (if (not (or (= c ?\&) + (and (>= c ?1) + (<= c ?9)))) + ;; \ followed by some character we don't expand. + (push (char-to-string c) expanded) + ;; \& or \N + (if (= c ?\&) + (setq N 0) + (setq N (- c ?0))) + (when (match-beginning N) + (push (substring original (match-beginning N) (match-end N)) + expanded)))) + (setq pos (1+ pos))) + (if did-expand + (apply (function concat) (nreverse expanded)) + newtext))) + ;;; Folder parser utils. (defun elmo-parse-token (string &optional seps) "Parse atom from STRING using SEPS as a string of separator char list." @@ -1550,6 +1634,7 @@ If the cache is partial file-cache, TYPE is 'partial." (nth (% (/ sum 16) 2) chars) (nth (% sum 16) chars)))) +;;; (defun elmo-file-cache-get-path (msgid &optional section) "Get cache path for MSGID. If optional argument SECTION is specified, partial cache path is returned." @@ -1833,15 +1918,18 @@ If KBYTES is kilo bytes (This value must be float)." ;;; ;; Warnings. -(defconst elmo-warning-buffer-name "*elmo warning*") - -(defun elmo-warning (&rest args) - "Display a warning, making warning message by passing all args to `insert'." - (with-current-buffer (get-buffer-create elmo-warning-buffer-name) - (goto-char (point-max)) - (apply 'insert (append args '("\n"))) - (recenter 1)) - (display-buffer elmo-warning-buffer-name)) +(static-if (fboundp 'display-warning) + (defmacro elmo-warning (&rest args) + "Display a warning with `elmo' group." + `(display-warning 'elmo (format ,@args))) + (defconst elmo-warning-buffer-name "*elmo warning*") + (defun elmo-warning (&rest args) + "Display a warning. ARGS are passed to `format'." + (with-current-buffer (get-buffer-create elmo-warning-buffer-name) + (goto-char (point-max)) + (funcall 'insert (apply 'format (append args '("\n")))) + (ignore-errors (recenter 1)) + (display-buffer elmo-warning-buffer-name)))) (defvar elmo-obsolete-variable-alist nil) @@ -1871,9 +1959,9 @@ If `elmo-obsolete-variable-show-warnings' is non-nil, show warning message." (defvaralias var obsolete) (set var (symbol-value obsolete))) (if elmo-obsolete-variable-show-warnings - (elmo-warning (format "%s is obsolete. Use %s instead." - (symbol-name obsolete) - (symbol-name var)))))) + (elmo-warning "%s is obsolete. Use %s instead." + (symbol-name obsolete) + (symbol-name var))))) (defun elmo-resque-obsolete-variables (&optional alist) "Resque obsolete variables in ALIST. @@ -1900,6 +1988,18 @@ If ALIST is nil, `elmo-obsolete-variable-alist' is used." elmo-msgdb-directory) elmo-dop-queue)) +(if (and (fboundp 'regexp-opt) + (not (featurep 'xemacs))) + (defalias 'elmo-regexp-opt 'regexp-opt) + (defun elmo-regexp-opt (strings &optional paren) + "Return a regexp to match a string in STRINGS. +Each string should be unique in STRINGS and should not contain any regexps, +quoted or not. If optional PAREN is non-nil, ensure that the returned regexp +is enclosed by at least one regexp grouping construct." + (let ((open-paren (if paren "\\(" "")) (close-paren (if paren "\\)" ""))) + (concat open-paren (mapconcat 'regexp-quote strings "\\|") + close-paren)))) + (require 'product) (product-provide (provide 'elmo-util) (require 'elmo-version))