mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-30 08:09:04 +00:00
dda00b2cb5
Remove circular dependencies. mh-e.el now includes few require statements and stands alone. Other files should need to require mh-e.el, which requires mh-loaddefs.el, plus variable-only files such as mh-scan.el. Remove unneeded require statements. Remove unneeded load statements, or replace them with non-fatal require statements. Break out components into their own files that were often spread between many files. As a result, many functions that are now only used within a single file no longer need to be autoloaded. Rearrange and provide consistent headings. Untabify. * mh-acros.el: Update commentary to reflect current usage. Add autoload cookies to all macros. (mh-require-cl): Merge docstring and comment. (mh-do-in-xemacs): Fix typo in docstring. (assoc-string): Move to new file mh-compat.el. (with-mh-folder-updating, mh-in-show-buffer) (mh-do-at-event-location, mh-seq-msgs): Move here from mh-utils.el. (mh-iterate-on-messages-in-region, mh-iterate-on-range): Move here from mh-seq.el. * mh-alias.el (mh-address-mail-regexp) (mh-goto-address-find-address-at-point): Move here from mh-utils.el. (mh-folder-line-matches-show-buffer-p): Move here from mh-e.el. * mh-buffers.el: Update descriptive text. * mh-comp.el (mh-note-repl, mh-note-forw, mh-note-dist): Move to new file mh-scan.el. (mh-yank-hooks, mh-to-field-choices, mh-position-on-field) (mh-letter-menu, mh-letter-mode-help-messages) (mh-letter-buttons-init-flag, mh-letter-mode) (mh-font-lock-field-data, mh-letter-header-end) (mh-auto-fill-for-letter, mh-to-field, mh-to-fcc) (mh-file-is-vcard-p, mh-insert-signature, mh-check-whom) (mh-insert-letter, mh-extract-from-attribution, mh-yank-cur-msg) (mh-filter-out-non-text, mh-insert-prefix-string) (mh-current-fill-prefix, mh-open-line, mh-complete-word) (mh-folder-expand-at-point, mh-letter-complete-function-alist) (mh-letter-complete, mh-letter-complete-or-space) (mh-letter-confirm-address, mh-letter-header-field-at-point) (mh-letter-next-header-field-or-indent) (mh-letter-next-header-field, mh-letter-previous-header-field) (mh-letter-skipped-header-field-p) (mh-letter-skip-leading-whitespace-in-header-field) (mh-hidden-header-keymap) (mh-letter-toggle-header-field-display-button) (mh-letter-toggle-header-field-display) (mh-letter-truncate-header-field, mh-letter-mode-map): Move to new file mh-letter.el. (mh-letter-mode-map, mh-sent-from-folder, mh-send-args) (mh-pgp-support-flag, mh-x-mailer-string) (mh-letter-header-field-regexp): Move to mh-e.el. (mh-goto-header-field, mh-goto-header-end) (mh-extract-from-header-value, mh-beginning-of-word): Move to mh-utils.el. (mh-insert-header-separator): Move to mh-comp.el. (mh-display-completion-list-compat): Move to new file mh-compat.el. * mh-compat.el: New file. (assoc-string): Move here from mh-acros.el. (mh-display-completion-list): Move here from mh-comp.el. * mh-customize.el: Move content into mh-e.el and remove. * mh-e.el (mh-folder-mode-map, mh-folder-seq-tool-bar-map) (mh-folder-tool-bar-map, mh-inc-spool-map, mh-letter-mode-map) (mh-letter-tool-bar-map, mh-search-mode-map, mh-show-mode-map) (mh-show-seq-tool-bar-map, mh-show-tool-bar-map): All maps now declared here so that they can be used in docstrings. (mh-sent-from-folder, mh-sent-from-msg) (mh-letter-header-field-regexp, mh-pgp-support-flag) (mh-x-mailer-string): Move here from mh-comp.el. (mh-folder-line-matches-show-buffer-p): Move to mh-alias.el. (mh-thread-scan-line-map, mh-thread-scan-line-map-stack): Move here from mh-seq.el. (mh-draft-folder, mh-inbox, mh-user-path, mh-current-folder) (mh-previous-window-config, mh-seen-list, mh-seq-list) (mh-show-buffer, mh-showing-mode, mh-globals-hash) (mh-show-folder-buffer, mh-mail-header-separator) (mh-unseen-seq, mh-previous-seq, mh-page-to-next-msg-flag) (mh-signature-separator, mh-signature-separator-regexp) (mh-list-to-string, mh-list-to-string-1): Move here from mh-utils.el. (mh-index-max-cmdline-args, mh-xargs, mh-quote-for-shell) (mh-exec-cmd, mh-exec-cmd-error, mh-exec-cmd-daemon) (mh-exec-cmd-env-daemon, mh-process-daemon, mh-exec-cmd-quiet) (mh-exec-cmd-output) (mh-exchange-point-and-mark-preserving-active-mark) (mh-exec-lib-cmd-output, mh-handle-process-error): Move here from deprecated file mh-exec.el. (mh-path): Move here from deprecated file mh-customize.el. (mh-sys-path, mh-variants, mh-variant-in-use, mh-progs, mh-lib) (mh-flists-present-flag, mh-variants, mh-variant-mh-info) (mh-variant-mu-mh-info, mh-variant-nmh-info, mh-file-command-p) (mh-variant-set-variant, mh-variant-p, mh-profile-component) (mh-profile-component-value, mh-defface-compat): Move here from deprecated file mh-init.el. (mh-goto-next-button, mh-folder-mime-action) (mh-folder-toggle-mime-part, mh-folder-inline-mime-part) (mh-folder-save-mime-part, mh-toggle-mime-buttons): Move to to mh-mime.el. (mh-scan-format-mh, mh-scan-format-nmh, mh-note-deleted) (mh-note-refiled, mh-note-cur, mh-scan-good-msg-regexp) (mh-scan-deleted-msg-regexp, mh-scan-refiled-msg-regexp) (mh-scan-valid-regexp, mh-scan-cur-msg-number-regexp) (mh-scan-date-regexp, mh-scan-rcpt-regexp, mh-scan-body-regexp) (mh-scan-subject-regexp, mh-scan-sent-to-me-sender-regexp) (mh-scan-cmd-note-width, mh-scan-destination-width) (mh-scan-date-width, mh-scan-date-flag-width) (mh-scan-from-mbox-width, mh-scan-from-mbox-sep-width) (mh-scan-field-destination-offset) (mh-scan-field-from-start-offset, mh-scan-field-from-end-offset) (mh-scan-field-subject-start-offset, mh-scan-format) (mh-msg-num-width-to-column, mh-set-cmd-note): Move to new file mh-scan.el. (mh-partial-folder-mode-line-annotation) (mh-folder-font-lock-keywords, mh-folder-font-lock-subject) (mh-generate-sequence-font-lock, mh-last-destination) (mh-last-destination-write, mh-first-msg-num, mh-last-msg-num) (mh-rmail, mh-nmail, mh-delete-msg, mh-delete-msg-no-motion) (mh-execute-commands, mh-first-msg, mh-header-display) (mh-inc-folder, mh-last-msg, mh-next-undeleted-msg) (mh-folder-from-address, mh-prompt-for-refile-folder) (mh-refile-msg, mh-refile-or-write-again, mh-quit, mh-page-msg) (mh-previous-page, mh-previous-undeleted-msg) (mh-previous-unread-msg, mh-next-button, mh-prev-button) (mh-reset-threads-and-narrowing, mh-rescan-folder) (mh-write-msg-to-file, mh-toggle-showing, mh-undo) (mh-visit-folder, mh-update-sequences, mh-delete-a-msg) (mh-refile-a-msg, mh-next-msg, mh-next-unread-msg) (mh-set-scan-mode, mh-undo-msg, mh-make-folder) (mh-folder-sequence-menu, mh-folder-message-menu) (mh-folder-folder-menu, mh-remove-xemacs-horizontal-scrollbar) (mh-write-file-functions-compat, mh-folder-mode) (mh-restore-desktop-buffer, mh-scan-folder) (mh-regenerate-headers, mh-generate-new-cmd-note) (mh-get-new-mail, mh-make-folder-mode-line, mh-goto-cur-msg) (mh-process-or-undo-commands, mh-process-commands) (mh-update-unseen, mh-delete-scan-msgs) (mh-outstanding-commands-p): Move to new file mh-folder.el. (mh-mapc, mh-colors-available-p, mh-colors-in-use-p) (mh-make-local-vars, mh-coalesce-msg-list, mh-greaterp) (mh-lessp): Move to mh-utils.el. (mh-parse-flist-output-line, mh-folder-size-folder) (mh-folder-size-flist, mh-folder-size, mh-add-sequence-notation) (mh-remove-sequence-notation, mh-remove-cur-notation) (mh-remove-all-notation, mh-delete-seq-locally) (mh-read-folder-sequences, mh-read-msg-list) (mh-notate-user-sequences, mh-internal-seqs, mh-internal-seq) (mh-valid-seq-p, mh-delete-msg-from-seq, mh-catchup) (mh-delete-a-msg-from-seq, mh-undefine-sequence) (mh-define-sequence, mh-seq-containing-msg): Move to mh-seq.el. (mh-xemacs-flag) (mh-customize, mh-e, mh-alias, mh-folder, mh-folder-selection) (mh-identity, mh-inc, mh-junk, mh-letter, mh-ranges) (mh-scan-line-formats, mh-search, mh-sending-mail, mh-sequences) (mh-show, mh-speedbar, mh-thread, mh-tool-bar, mh-hooks) (mh-faces, mh-alias-completion-ignore-case-flag) (mh-alias-expand-aliases-flag, mh-alias-flash-on-comma) (mh-alias-insert-file, mh-alias-insertion-location) (mh-alias-local-users, mh-alias-local-users-prefix) (mh-alias-passwd-gecos-comma-separator-flag) (mh-new-messages-folders, mh-ticked-messages-folders) (mh-large-folder, mh-recenter-summary-flag) (mh-recursive-folders-flag, mh-sortm-args) (mh-default-folder-for-message-function, mh-default-folder-list) (mh-default-folder-must-exist-flag, mh-default-folder-prefix) (mh-identity-list, mh-auto-fields-list) (mh-auto-fields-prompt-flag, mh-identity-default) (mh-identity-handlers, mh-inc-prog, mh-inc-spool-list) (mh-junk-choice, mh-junk-function-alist, mh-junk-choose) (mh-junk-background, mh-junk-disposition, mh-junk-program) (mh-compose-insertion, mh-compose-skipped-header-fields) (mh-compose-space-does-completion-flag) (mh-delete-yanked-msg-window-flag) (mh-extract-from-attribution-verb, mh-ins-buf-prefix) (mh-letter-complete-function, mh-letter-fill-column) (mh-mml-method-default, mh-signature-file-name) (mh-signature-separator-flag, mh-x-face-file, mh-yank-behavior) (mh-interpret-number-as-range-flag, mh-adaptive-cmd-note-flag) (mh-scan-format-file-check, mh-scan-format-file) (mh-adaptive-cmd-note-flag-check, mh-scan-prog) (mh-search-program, mh-compose-forward-as-mime-flag) (mh-compose-letter-function, mh-compose-prompt-flag) (mh-forward-subject-format, mh-insert-x-mailer-flag) (mh-redist-full-contents-flag, mh-reply-default-reply-to) (mh-reply-show-message-flag, mh-refile-preserves-sequences-flag) (mh-tick-seq, mh-update-sequences-after-mh-show-flag) (mh-bury-show-buffer-flag, mh-clean-message-header-flag) (mh-decode-mime-flag, mh-display-buttons-for-alternatives-flag) (mh-display-buttons-for-inline-parts-flag) (mh-do-not-confirm-flag, mh-fetch-x-image-url) (mh-graphical-smileys-flag, mh-graphical-emphasis-flag) (mh-highlight-citation-style) (mh-invisible-header-fields-internal) (mh-delay-invisible-header-generation-flag) (mh-invisible-header-fields, mh-invisible-header-fields-default) (mh-invisible-header-fields-compiled, mh-invisible-headers) (mh-lpr-command-format, mh-max-inline-image-height) (mh-max-inline-image-width, mh-mhl-format-file) (mh-mime-save-parts-default-directory, mh-print-background-flag) (mh-show-maximum-size, mh-show-use-goto-addr-flag) (mh-show-use-xface-flag, mh-store-default-directory) (mh-summary-height, mh-speed-update-interval) (mh-show-threads-flag, mh-tool-bar-search-function) (mh-after-commands-processed-hook, mh-alias-reloaded-hook) (mh-before-commands-processed-hook, mh-before-quit-hook) (mh-before-send-letter-hook, mh-delete-msg-hook) (mh-find-path-hook, mh-folder-mode-hook, mh-forward-hook) (mh-inc-folder-hook, mh-insert-signature-hook) (mh-kill-folder-suppress-prompt-hooks, mh-letter-mode-hook) (mh-mh-to-mime-hook, mh-search-mode-hook, mh-quit-hook) (mh-refile-msg-hook, mh-show-hook, mh-show-mode-hook) (mh-unseen-updated-hook, mh-min-colors-defined-flag) (mh-folder-address, mh-folder-body) (mh-folder-cur-msg-number, mh-folder-date, mh-folder-deleted) (mh-folder-followup, mh-folder-msg-number, mh-folder-refiled) (mh-folder-sent-to-me-hint, mh-folder-sent-to-me-sender) (mh-folder-subject, mh-folder-tick, mh-folder-to) (mh-search-folder, mh-letter-header-field, mh-show-cc) (mh-show-date, mh-show-from, mh-show-header, mh-show-pgg-bad) (mh-show-pgg-good, mh-show-pgg-unknown, mh-show-signature) (mh-show-subject, mh-show-to, mh-show-xface, mh-speedbar-folder) (mh-speedbar-folder-with-unseen-messages) (mh-speedbar-selected-folder) (mh-speedbar-selected-folder-with-unseen-messages): Move here from deprecated file mh-customize.el. * mh-exec.el: Move content into mh-e.el and remove. * mh-folder.el: New file. Contains mh-folder-mode from mh-e.el * mh-funcs.el (mh-note-copied, mh-note-printed): Move to new file mh-scan.el. (mh-ephem-message, mh-help, mh-prefix-help): Move to mh-utils.el. * mh-gnus.el (mm-uu-dissect-text-parts): Add. (mh-mail-abbrev-make-syntax-table): Move to mh-utils.el and rename to mail-abbrev-make-syntax-table. * mh-identity.el (mh-identity-menu): New variable for existing menu. (mh-identity-make-menu-no-autoload): New alias for mh-identity-make-menu which can be called from mh-e.el. (mh-identity-list-set): Move to mh-e.el. (mh-identity-add-menu): New function (mh-insert-identity): Add optional argument maybe-insert so that local variable mh-identity-local does not have to be visible. (mh-identity-handler-default): * mh-inc.el (mh-inc-spool-map): Move declaration to mh-e.el (with rest of keymaps). Update key binding for ? to call mh-help with help messages in new argument. (mh-inc-spool-make-no-autoload): New alias for mh-inc-spool-make which can be called from mh-e.el. (mh-inc-spool-list-set): Simplify update of mh-inc-spool-map-help. * mh-init.el: Move content into mh-e.el and remove. * mh-junk.el: Update requires, untabify, and add mh-autoload cookies. * mh-letter.el: New file. Contains mh-letter-mode from mh-comp.el. * mh-limit.el: New file. Contains display limit commands from mh-mime.el. * mh-mime.el: Rearrange for consistency with other files. (mh-buffer-data, mh-mm-inline-media-tests): Move here from mh-utils.el. (mh-folder-inline-mime-part, mh-folder-save-mime-part) (mh-folder-toggle-mime-part, mh-toggle-mime-buttons) (mh-goto-next-button): Move here from mh-e.el. * mh-print.el: Rearrange for consistency with other files. * mh-scan.el: New file. Contains scan line constants and utilities from XXX, mh-funcs, mh-utils.el. * mh-search.el: Rearrange for consistency with other files. (mh-search-mode-map): Drop C-c C-f {dr} bindings since these fields which don't exist in the saved header. Replace C-c C-f f with C-c C-f m per mail-mode consistency. (mh-search-mode): Use mh-set-help instead of setting mh-help-messages. * mh-seq.el (mh-thread-message, mh-thread-container) (mh-thread-id-hash, mh-thread-subject-hash, mh-thread-id-table) (mh-thread-id-index-map, mh-thread-index-id-map) (mh-thread-scan-line-map, mh-thread-scan-line-map-stack) (mh-thread-subject-container-hash, mh-thread-duplicates) (mh-thread-history, mh-thread-body-width) (mh-thread-find-msg-subject mh-thread-initialize-hash) (mh-thread-initialize, mh-thread-id-container) (mh-thread-remove-parent-link, mh-thread-add-link) (mh-thread-ancestor-p, mh-thread-get-message-container) (mh-thread-get-message, mh-thread-canonicalize-id) (mh-thread-prune-subject, mh-thread-container-subject) (mh-thread-rewind-pruning, mh-thread-prune-containers) (mh-thread-sort-containers, mh-thread-group-by-subject) (mh-thread-process-in-reply-to, mh-thread-set-tables) (mh-thread-update-id-index-maps, mh-thread-generate) (mh-thread-inc, mh-thread-generate-scan-lines) (mh-thread-parse-scan-line, mh-thread-update-scan-line-map) (mh-thread-add-spaces, mh-thread-print-scan-lines) (mh-thread-folder, mh-toggle-threads, mh-thread-forget-message) (mh-thread-current-indentation-level, mh-thread-next-sibling) (mh-thread-previous-sibling, mh-thread-immediate-ancestor) (mh-thread-ancestor, mh-thread-find-children) (mh-message-id-regexp, mh-thread-delete, mh-thread-refile): Move to new file mh-thread.el. (mh-subject-to-sequence, mh-subject-to-sequence-unthreaded) (mh-subject-to-sequence-threaded, mh-edit-pick-expr) (mh-pick-args-list, mh-narrow-to-subject, mh-narrow-to-from) (mh-narrow-to-cc, mh-narrow-to-to, mh-narrow-to-header-field) (mh-current-message-header-field, mh-narrow-to-range) (mh-delete-subject, mh-delete-subject-or-thread): Move to new file mh-limit.el. (mh-iterate-on-messages-in-region, mh-iterate-on-range): Move to mh-acros.el. (mh-internal-seqs, mh-catchup, mh-delete-msg-from-seq) (mh-internal-seq, mh-valid-seq-p, mh-seq-containing-msg) (mh-define-sequence, mh-undefine-sequence) (mh-delete-a-msg-from-seq, mh-delete-seq-locally) (mh-folder-size, mh-folder-size-flist, mh-folder-size-folder) (mh-parse-flist-output-line, mh-read-folder-sequences) (mh-read-msg-list, mh-notate-user-sequences) (mh-remove-cur-notation, mh-add-sequence-notation) (mh-remove-sequence-notation, mh-remove-all-notation): Move here from mh-e.el. (mh-make-seq, mh-seq-name, mh-find-seq, mh-seq-to-msgs) (mh-add-msgs-to-seq, mh-notate): Move here from mh-utils.el. * mh-show.el: New file. Contains mh-show-mode from mh-utils.el. * mh-speed.el: Rearrange for consistency with other files. * mh-thread.el: New file. Contains threading code from mh-seq.el. * mh-tool-bar.el: New file. Contains tool bar creation code from deprecated file mh-customize.el. * mh-utils.el (recursive-load-depth-limit): Remove setting. No longer needed. (mh-scan-msg-number-regexp, mh-scan-msg-overflow-regexp) (mh-scan-msg-format-regexp, mh-scan-msg-format-string) (mh-scan-msg-search-regexp, mh-cmd-note, mh-note-seq) (mh-update-scan-format, mh-msg-num-width): Move to new file mh-scan.el. (mh-show-buffer-mode-line-buffer-id, mh-letter-header-font-lock) (mh-header-field-font-lock, mh-header-to-font-lock) (mh-header-cc-font-lock, mh-header-subject-font-lock) (mh-show-font-lock-keywords) (mh-show-font-lock-keywords-with-cite) (mh-show-font-lock-fontify-region) (mh-gnus-article-highlight-citation, mh-showing-with-headers) (mh-start-of-uncleaned-message, mh-invalidate-show-buffer) (mh-unvisit-file, mh-defun-show-buffer, mh-show-mode-map) (mh-show-sequence-menu, mh-show-message-menu) (mh-show-folder-menu, mh-show-mode, mh-show-addr) (mh-maybe-show, mh-show, mh-show-msg, mh-show-unquote-From) (mh-msg-folder, mh-display-msg, mh-clean-msg-header): Move to new file mh-show.el. (mh-mail-header-separator, mh-signature-separator-regexp) (mh-signature-separator, mh-globals-hash, mh-user-path) (mh-draft-folder, mh-unseen-seq, mh-previous-seq, mh-inbox) (mh-previous-window-config, mh-current-folder mh-show-buffer) (mh-showing-mode, mh-show-mode-map, mh-show-folder-buffer) (mh-showing-mode, mh-seq-list, mh-seen-list, mh-summary-height) (mh-list-to-string, mh-list-to-string-1): Move to mh-e.el. (mh-buffer-data, mh-mm-inline-media-tests): Move to mh-mime.el. (mh-address-mail-regexp, mh-goto-address-find-address-at-point): Move to mh-alias.el. (mh-letter-font-lock-keywords): Move to new file mh-letter.el. (mh-folder-filename, mh-msg-count, mh-recenter, mh-msg-filename) (mh-show-mouse, mh-modify, mh-goto-msg, mh-set-folder-modified-p): Move to new file mh-folder.el. (with-mh-folder-updating, mh-in-show-buffer) (mh-do-at-event-location, mh-seq-msgs): Moved to mh-acros.el. (mh-make-seq, mh-seq-name, mh-notate, mh-find-seq) (mh-seq-to-msgs, mh-add-msgs-to-seq, mh-canonicalize-sequence): Moved to mh-seq.el. (mh-show-xface-function, mh-uncompface-executable, mh-face-to-png) (mh-uncompface, mh-icontopbm, mh-face-foreground-compat) (mh-face-background-compat, mh-face-display-function) (mh-show-xface, mh-picon-directory-list) (mh-picon-existing-directory-list) (mh-picon-cache, mh-picon-image-types) (mh-picon-set-directory-list, mh-picon-get-image) (mh-picon-file-contents, mh-picon-generate-path) (mh-x-image-cache-directory, mh-x-image-scaling-function) (mh-wget-executable, mh-wget-choice, mh-wget-option) (mh-x-image-temp-file, mh-x-image-url, mh-x-image-marker) (mh-x-image-url-cache-file, mh-x-image-scale-with-pnm) (mh-x-image-scale-with-convert) (url-unreserved-chars, url-hexify-string) (mh-x-image-url-cache-canonicalize) (mh-x-image-set-download-state, mh-x-image-get-download-state) (mh-x-image-url-fetch-image, mh-x-image-display) (mh-x-image-scale-and-display, mh-x-image-url-sane-p) (mh-x-image-url-display): Move to new file mh-xface.el. (mh-logo-display): Call mh-image-load-path. (mh-find-path-run, mh-find-path): Move here from deprecated file mh-init.el. (mh-help-messages): Now an alist of modes to an alist of messages. (mh-set-help): New function used to set mh-help-messages (mh-help): Adjust for new format of mh-help-messages. Add help-messages argument. (mh-prefix-help): Refactor to use mh-help. (mh-coalesce-msg-list, mh-greaterp, mh-lessp): Move here from mh-e.el. (mh-clear-sub-folders-cache): New function added to avoid exposing mh-sub-folders-cache variable. * mh-xface.el: New file. Contains X-Face and Face header field display routines from mh-utils.el.
880 lines
33 KiB
EmacsLisp
880 lines
33 KiB
EmacsLisp
;;; mh-utils.el --- MH-E general utilities
|
||
|
||
;; Copyright (C) 1993, 1995, 1997,
|
||
;; 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||
|
||
;; Author: Bill Wohler <wohler@newt.com>
|
||
;; Maintainer: Bill Wohler <wohler@newt.com>
|
||
;; Keywords: mail
|
||
;; See: mh-e.el
|
||
|
||
;; This file is part of GNU Emacs.
|
||
|
||
;; GNU Emacs is free software; you can redistribute it and/or modify
|
||
;; it under the terms of the GNU General Public License as published by
|
||
;; the Free Software Foundation; either version 2, or (at your option)
|
||
;; any later version.
|
||
|
||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
;; GNU General Public License for more details.
|
||
|
||
;; You should have received a copy of the GNU General Public License
|
||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||
;; Boston, MA 02110-1301, USA.
|
||
|
||
;;; Commentary:
|
||
|
||
;;; Change Log:
|
||
|
||
;;; Code:
|
||
|
||
(require 'mh-e)
|
||
(mh-require-cl)
|
||
|
||
(require 'font-lock)
|
||
|
||
;;; CL Replacements
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-search-from-end (char string)
|
||
"Return the position of last occurrence of CHAR in STRING.
|
||
If CHAR is not present in STRING then return nil. The function is
|
||
used in lieu of `search' in the CL package."
|
||
(loop for index from (1- (length string)) downto 0
|
||
when (equal (aref string index) char) return index
|
||
finally return nil))
|
||
|
||
|
||
|
||
;;; General Utilities
|
||
|
||
(require 'mailabbrev nil t)
|
||
(mh-defun-compat mail-abbrev-make-syntax-table ()
|
||
"Emacs 21 and XEmacs don't have this function."
|
||
nil)
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-beginning-of-word (&optional n)
|
||
"Return position of the N th word backwards."
|
||
(unless n (setq n 1))
|
||
(let ((syntax-table (syntax-table)))
|
||
(unwind-protect
|
||
(save-excursion
|
||
(mail-abbrev-make-syntax-table)
|
||
(set-syntax-table mail-abbrev-syntax-table)
|
||
(backward-word n)
|
||
(point))
|
||
(set-syntax-table syntax-table))))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-colors-available-p ()
|
||
"Check if colors are available in the Emacs being used."
|
||
(or mh-xemacs-flag
|
||
(let ((color-cells (display-color-cells)))
|
||
(and (numberp color-cells) (>= color-cells 8)))))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-colors-in-use-p ()
|
||
"Check if colors are being used in the folder buffer."
|
||
(and mh-colors-available-flag font-lock-mode))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-delete-line (lines)
|
||
"Delete the next LINES lines."
|
||
(delete-region (point) (progn (forward-line lines) (point))))
|
||
|
||
(defvar mh-image-load-path-called-flag nil)
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-image-load-path ()
|
||
"Ensure that the MH-E images are accessible by `find-image'.
|
||
Images for MH-E are found in ../../etc/images relative to the
|
||
files in \"lisp/mh-e\". If `image-load-path' exists (since Emacs
|
||
22), then the images directory is added to it if isn't already
|
||
there. Otherwise, the images directory is added to the
|
||
`load-path' if it isn't already there."
|
||
(unless mh-image-load-path-called-flag
|
||
(let (mh-library-name mh-image-load-path)
|
||
;; First, find mh-e in the load-path.
|
||
(setq mh-library-name (locate-library "mh-e"))
|
||
(if (not mh-library-name)
|
||
(error "Can not find MH-E in load-path"))
|
||
(setq mh-image-load-path
|
||
(expand-file-name (concat (file-name-directory mh-library-name)
|
||
"../../etc/images")))
|
||
(if (not (file-exists-p mh-image-load-path))
|
||
(error "Can not find image directory %s" mh-image-load-path))
|
||
(if (boundp 'image-load-path)
|
||
(add-to-list 'image-load-path mh-image-load-path)
|
||
(add-to-list 'load-path mh-image-load-path)))
|
||
(setq mh-image-load-path-called-flag t)))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-make-local-vars (&rest pairs)
|
||
"Initialize local variables according to the variable-value PAIRS."
|
||
(while pairs
|
||
(set (make-local-variable (car pairs)) (car (cdr pairs)))
|
||
(setq pairs (cdr (cdr pairs)))))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-mapc (function list)
|
||
"Apply FUNCTION to each element of LIST for side effects only."
|
||
(while list
|
||
(funcall function (car list))
|
||
(setq list (cdr list))))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-replace-string (old new)
|
||
"Replace all occurrences of OLD with NEW in the current buffer.
|
||
Ignores case when searching for OLD."
|
||
(goto-char (point-min))
|
||
(let ((case-fold-search t))
|
||
(while (search-forward old nil t)
|
||
(replace-match new t t))))
|
||
|
||
|
||
|
||
;;; Logo Display
|
||
|
||
(defvar mh-logo-cache nil)
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-logo-display ()
|
||
"Modify mode line to display MH-E logo."
|
||
(mh-image-load-path)
|
||
(mh-do-in-gnu-emacs
|
||
(add-text-properties
|
||
0 2
|
||
`(display ,(or mh-logo-cache
|
||
(setq mh-logo-cache
|
||
(mh-funcall-if-exists
|
||
find-image '((:type xpm :ascent center
|
||
:file "mh-logo.xpm"))))))
|
||
(car mode-line-buffer-identification)))
|
||
(mh-do-in-xemacs
|
||
(setq modeline-buffer-identification
|
||
(list
|
||
(if mh-modeline-glyph
|
||
(cons modeline-buffer-id-left-extent mh-modeline-glyph)
|
||
(cons modeline-buffer-id-left-extent "XEmacs%N:"))
|
||
(cons modeline-buffer-id-right-extent " %17b")))))
|
||
|
||
|
||
|
||
;;; Read MH Profile
|
||
|
||
(defvar mh-find-path-run nil
|
||
"Non-nil if `mh-find-path' has been run already.
|
||
Do not access this variable; `mh-find-path' already uses it to
|
||
avoid running more than once.")
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-find-path ()
|
||
"Set variables from user's MH profile.
|
||
|
||
This function sets `mh-user-path' from your \"Path:\" MH profile
|
||
component (but defaults to \"Mail\" if one isn't present),
|
||
`mh-draft-folder' from \"Draft-Folder:\", `mh-unseen-seq' from
|
||
\"Unseen-Sequence:\", `mh-previous-seq' from
|
||
\"Previous-Sequence:\", and `mh-inbox' from \"Inbox:\" (defaults
|
||
to \"+inbox\").
|
||
|
||
The hook `mh-find-path-hook' is run after these variables have
|
||
been set. This hook can be used the change the value of these
|
||
variables if you need to run with different values between MH and
|
||
MH-E."
|
||
(unless mh-find-path-run
|
||
;; Sanity checks.
|
||
(if (and (getenv "MH")
|
||
(not (file-readable-p (getenv "MH"))))
|
||
(error "MH environment variable contains unreadable file %s"
|
||
(getenv "MH")))
|
||
(if (null (mh-variants))
|
||
(error "Install MH and run install-mh before running MH-E"))
|
||
(let ((profile "~/.mh_profile"))
|
||
(if (not (file-readable-p profile))
|
||
(error "Run install-mh before running MH-E")))
|
||
;; Read MH profile.
|
||
(setq mh-user-path (mh-profile-component "Path"))
|
||
(if (not mh-user-path)
|
||
(setq mh-user-path "Mail"))
|
||
(setq mh-user-path
|
||
(file-name-as-directory
|
||
(expand-file-name mh-user-path (expand-file-name "~"))))
|
||
(mh-set-x-image-cache-directory (expand-file-name ".mhe-x-image-cache"
|
||
mh-user-path))
|
||
(setq mh-draft-folder (mh-profile-component "Draft-Folder"))
|
||
(if mh-draft-folder
|
||
(progn
|
||
(if (not (mh-folder-name-p mh-draft-folder))
|
||
(setq mh-draft-folder (format "+%s" mh-draft-folder)))
|
||
(if (not (file-exists-p (mh-expand-file-name mh-draft-folder)))
|
||
(error
|
||
"Draft folder \"%s\" not found; create it and try again"
|
||
(mh-expand-file-name mh-draft-folder)))))
|
||
(setq mh-inbox (mh-profile-component "Inbox"))
|
||
(cond ((not mh-inbox)
|
||
(setq mh-inbox "+inbox"))
|
||
((not (mh-folder-name-p mh-inbox))
|
||
(setq mh-inbox (format "+%s" mh-inbox))))
|
||
(setq mh-unseen-seq (mh-profile-component "Unseen-Sequence"))
|
||
(if mh-unseen-seq
|
||
(setq mh-unseen-seq (intern mh-unseen-seq))
|
||
(setq mh-unseen-seq 'unseen)) ;old MH default?
|
||
(setq mh-previous-seq (mh-profile-component "Previous-Sequence"))
|
||
(if mh-previous-seq
|
||
(setq mh-previous-seq (intern mh-previous-seq)))
|
||
(run-hooks 'mh-find-path-hook)
|
||
(mh-collect-folder-names)
|
||
(setq mh-find-path-run t)))
|
||
|
||
|
||
|
||
;;; Help Functions
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-ephem-message (string)
|
||
"Display STRING in the minibuffer momentarily."
|
||
(message "%s" string)
|
||
(sit-for 5)
|
||
(message ""))
|
||
|
||
(defvar mh-help-default nil
|
||
"Mode to use if messages are not present for the current mode.")
|
||
|
||
(defvar mh-help-messages nil
|
||
"Help messages for all modes.
|
||
This is an alist of alists. The primary key is a symbol
|
||
representing the mode; the value is described in `mh-set-help'.")
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-set-help (messages &optional default)
|
||
"Set help messages.
|
||
|
||
The MESSAGES are assumed to be an associative array. It is used
|
||
to show help for the most common commands in the current mode.
|
||
The key is a prefix char. The value is one or more strings which
|
||
are concatenated together and displayed in a help buffer if ? is
|
||
pressed after the prefix character. The special key nil is used
|
||
to display the non-prefixed commands.
|
||
|
||
The substitutions described in `substitute-command-keys' are performed as
|
||
well.
|
||
|
||
If optional argument DEFAULT is non-nil, then these messages will
|
||
be used if help is asked for an unknown mode."
|
||
(add-to-list 'mh-help-messages (cons major-mode messages))
|
||
(if default
|
||
(setq mh-help-default major-mode)))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-help (&optional help-messages)
|
||
"Display cheat sheet for the MH-E commands.
|
||
See `mh-set-help' for setting the help messages.
|
||
HELP-MESSAGES are used instead if given.
|
||
This is a list of one or more strings which are concatenated together
|
||
and displayed in a help buffer."
|
||
(interactive)
|
||
(let* ((help (or help-messages
|
||
(cdr (assoc nil (assoc major-mode mh-help-messages)))))
|
||
(text (substitute-command-keys (mapconcat 'identity help ""))))
|
||
(with-electric-help
|
||
(function
|
||
(lambda ()
|
||
(insert text)))
|
||
mh-help-buffer)))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-prefix-help ()
|
||
"Display cheat sheet for the commands of the current prefix in minibuffer."
|
||
(interactive)
|
||
;; We got here because the user pressed a "?", but he pressed a prefix key
|
||
;; before that. Since the the key vector starts at index 0, the index of the
|
||
;; last keystroke is length-1 and thus the second to last keystroke is at
|
||
;; length-2. We use that information to obtain a suitable prefix character
|
||
;; from the recent keys.
|
||
(let* ((keys (recent-keys))
|
||
(prefix-char (elt keys (- (length keys) 2)))
|
||
(help (cdr (assoc prefix-char (assoc major-mode mh-help-messages)))))
|
||
(mh-help help)))
|
||
|
||
|
||
|
||
;;; Message Number Utilities
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-coalesce-msg-list (messages)
|
||
"Given a list of MESSAGES, return a list of message number ranges.
|
||
This is the inverse of `mh-read-msg-list', which expands ranges.
|
||
Message lists passed to MH programs should be processed by this
|
||
function to avoid exceeding system command line argument limits."
|
||
(let ((msgs (sort (copy-sequence messages) 'mh-greaterp))
|
||
(range-high nil)
|
||
(prev -1)
|
||
(ranges nil))
|
||
(while prev
|
||
(if range-high
|
||
(if (or (not (numberp prev))
|
||
(not (equal (car msgs) (1- prev))))
|
||
(progn ;non-sequential, flush old range
|
||
(if (eq prev range-high)
|
||
(setq ranges (cons range-high ranges))
|
||
(setq ranges (cons (format "%s-%s" prev range-high) ranges)))
|
||
(setq range-high nil))))
|
||
(or range-high
|
||
(setq range-high (car msgs))) ;start new or first range
|
||
(setq prev (car msgs))
|
||
(setq msgs (cdr msgs)))
|
||
ranges))
|
||
|
||
(defun mh-greaterp (msg1 msg2)
|
||
"Return the greater of two message indicators MSG1 and MSG2.
|
||
Strings are \"smaller\" than numbers.
|
||
Valid values are things like \"cur\", \"last\", 1, and 1820."
|
||
(if (numberp msg1)
|
||
(if (numberp msg2)
|
||
(> msg1 msg2)
|
||
t)
|
||
(if (numberp msg2)
|
||
nil
|
||
(string-lessp msg2 msg1))))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-lessp (msg1 msg2)
|
||
"Return the lesser of two message indicators MSG1 and MSG2.
|
||
Strings are \"smaller\" than numbers.
|
||
Valid values are things like \"cur\", \"last\", 1, and 1820."
|
||
(not (mh-greaterp msg1 msg2)))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-get-msg-num (error-if-no-message)
|
||
"Return the message number of the displayed message.
|
||
If the argument ERROR-IF-NO-MESSAGE is non-nil, then complain if
|
||
the cursor is not pointing to a message."
|
||
(save-excursion
|
||
(beginning-of-line)
|
||
(cond ((looking-at (mh-scan-msg-number-regexp))
|
||
(string-to-number (buffer-substring (match-beginning 1)
|
||
(match-end 1))))
|
||
(error-if-no-message
|
||
(error "Cursor not pointing to message"))
|
||
(t nil))))
|
||
|
||
(add-to-list 'debug-ignored-errors "^Cursor not pointing to message$")
|
||
|
||
|
||
|
||
;;; Folder Cache and Access
|
||
|
||
(defvar mh-sub-folders-cache (make-hash-table :test #'equal))
|
||
(defvar mh-current-folder-name nil)
|
||
(defvar mh-flists-partial-line "")
|
||
(defvar mh-flists-process nil)
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-clear-sub-folders-cache ()
|
||
"Clear `mh-sub-folders-cache'."
|
||
(clrhash mh-sub-folders-cache))
|
||
|
||
;; Initialize mh-sub-folders-cache...
|
||
(defun mh-collect-folder-names ()
|
||
"Collect folder names by running \"folders\"."
|
||
(unless mh-flists-process
|
||
(setq mh-flists-process
|
||
(mh-exec-cmd-daemon "folders" 'mh-collect-folder-names-filter
|
||
"-recurse" "-fast"))))
|
||
|
||
(defun mh-collect-folder-names-filter (process output)
|
||
"Read folder names.
|
||
PROCESS is the flists process that was run to collect folder
|
||
names and the function is called when OUTPUT is available."
|
||
(let ((position 0)
|
||
(prevailing-match-data (match-data))
|
||
line-end folder)
|
||
(unwind-protect
|
||
(while (setq line-end (string-match "\n" output position))
|
||
(setq folder (format "+%s%s"
|
||
mh-flists-partial-line
|
||
(substring output position line-end)))
|
||
(setq mh-flists-partial-line "")
|
||
(unless (equal (aref folder 1) ?.)
|
||
(mh-populate-sub-folders-cache folder))
|
||
(setq position (1+ line-end)))
|
||
(set-match-data prevailing-match-data))
|
||
(setq mh-flists-partial-line (substring output position))))
|
||
|
||
(defun mh-populate-sub-folders-cache (folder)
|
||
"Tell `mh-sub-folders-cache' about FOLDER."
|
||
(let* ((last-slash (mh-search-from-end ?/ folder))
|
||
(child1 (substring folder (1+ (or last-slash 0))))
|
||
(parent (and last-slash (substring folder 0 last-slash)))
|
||
(parent-slash (and parent (mh-search-from-end ?/ parent)))
|
||
(child2 (and parent (substring parent (1+ (or parent-slash 0)))))
|
||
(grand-parent (and parent-slash (substring parent 0 parent-slash)))
|
||
(cache-entry (gethash parent mh-sub-folders-cache)))
|
||
(unless (loop for x in cache-entry when (equal (car x) child1) return t
|
||
finally return nil)
|
||
(push (list child1) cache-entry)
|
||
(setf (gethash parent mh-sub-folders-cache)
|
||
(sort cache-entry (lambda (x y) (string< (car x) (car y)))))
|
||
(when parent
|
||
(loop for x in (gethash grand-parent mh-sub-folders-cache)
|
||
when (equal (car x) child2)
|
||
do (progn (setf (cdr x) t) (return)))))))
|
||
|
||
(defun mh-normalize-folder-name (folder &optional empty-string-okay
|
||
dont-remove-trailing-slash)
|
||
"Normalizes FOLDER name.
|
||
|
||
Makes sure that two '/' characters never occur next to each
|
||
other. Also all occurrences of \"..\" and \".\" are suitably
|
||
processed. So \"+inbox/../news\" will be normalized to \"+news\".
|
||
|
||
If optional argument EMPTY-STRING-OKAY is nil then a '+' is added
|
||
at the front if FOLDER lacks one. If non-nil and FOLDER is the
|
||
empty string then nothing is added.
|
||
|
||
If optional argument DONT-REMOVE-TRAILING-SLASH is non-nil then a
|
||
trailing '/' if present is retained (if present), otherwise it is
|
||
removed."
|
||
(when (stringp folder)
|
||
;; Replace two or more consecutive '/' characters with a single '/'
|
||
(while (string-match "//" folder)
|
||
(setq folder (replace-match "/" nil t folder)))
|
||
(let* ((length (length folder))
|
||
(trailing-slash-present (and (> length 0)
|
||
(equal (aref folder (1- length)) ?/)))
|
||
(leading-slash-present (and (> length 0)
|
||
(equal (aref folder 0) ?/))))
|
||
(when (and (> length 0) (equal (aref folder 0) ?@)
|
||
(stringp mh-current-folder-name))
|
||
(setq folder (format "%s/%s/" mh-current-folder-name
|
||
(substring folder 1))))
|
||
;; XXX: Purge empty strings from the list that split-string returns. In
|
||
;; XEmacs, (split-string "+foo/" "/") returns ("+foo" "") while in GNU
|
||
;; Emacs it returns ("+foo"). In the code it is assumed that the
|
||
;; components list has no empty strings.
|
||
(let ((components (delete "" (split-string folder "/")))
|
||
(result ()))
|
||
;; Remove .. and . from the pathname.
|
||
(dolist (component components)
|
||
(cond ((and (equal component "..") result)
|
||
(pop result))
|
||
((equal component ".."))
|
||
((equal component "."))
|
||
(t (push component result))))
|
||
(setq folder "")
|
||
(dolist (component result)
|
||
(setq folder (concat component "/" folder)))
|
||
;; Remove trailing '/' if needed.
|
||
(unless (and trailing-slash-present dont-remove-trailing-slash)
|
||
(when (not (equal folder ""))
|
||
(setq folder (substring folder 0 (1- (length folder))))))
|
||
(when leading-slash-present
|
||
(setq folder (concat "/" folder)))))
|
||
(cond ((and empty-string-okay (equal folder "")))
|
||
((equal folder "") (setq folder "+"))
|
||
((not (equal (aref folder 0) ?+)) (setq folder (concat "+" folder)))))
|
||
folder)
|
||
|
||
(defmacro mh-children-p (folder)
|
||
"Return t if FOLDER from sub-folders cache has children.
|
||
The car of folder is the name, and the cdr is either t or some
|
||
sort of count that I do not understand. It's too small to be the
|
||
number of messages in the sub-folders and too large to be the
|
||
number of sub-folders. XXX"
|
||
`(if (cdr ,folder)
|
||
t
|
||
nil))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-folder-list (folder)
|
||
"Return FOLDER and its descendents.
|
||
Returns a list of strings. For example,
|
||
|
||
'(\"inbox\" \"lists\" \"lists/mh-e\").
|
||
|
||
If folder is nil, then all folders are considered. Respects the
|
||
value of `mh-recursive-folders-flag'. If this flag is nil, and
|
||
the sub-folders have not been explicitly viewed, then they will
|
||
not be returned."
|
||
(let ((folder-list))
|
||
;; Normalize folder. Strip leading +. Add trailing slash. If no
|
||
;; folder is specified, ensure it is nil to ensure we get the
|
||
;; top-level folders; otherwise mh-sub-folders returns all the
|
||
;; files in / if given an empty string or +.
|
||
(when folder
|
||
(setq folder (replace-regexp-in-string "^\+" "" folder))
|
||
(setq folder (replace-regexp-in-string "/*$" "/" folder))
|
||
(if (equal folder "")
|
||
(setq folder nil)))
|
||
(loop for f in (mh-sub-folders folder) do
|
||
(setq folder-list (append folder-list (list (concat folder (car f)))))
|
||
(if (mh-children-p f)
|
||
(setq folder-list
|
||
(append folder-list
|
||
(mh-folder-list (concat folder (car f)))))))
|
||
folder-list))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-sub-folders (folder &optional add-trailing-slash-flag)
|
||
"Find the subfolders of FOLDER.
|
||
The function avoids running folders unnecessarily by caching the
|
||
results of the actual folders call.
|
||
|
||
If optional argument ADD-TRAILING-SLASH-FLAG is non-nil then a
|
||
slash is added to each of the sub-folder names that may have
|
||
nested folders within them."
|
||
(let* ((folder (mh-normalize-folder-name folder))
|
||
(match (gethash folder mh-sub-folders-cache 'no-result))
|
||
(sub-folders (cond ((eq match 'no-result)
|
||
(setf (gethash folder mh-sub-folders-cache)
|
||
(mh-sub-folders-actual folder)))
|
||
(t match))))
|
||
(if add-trailing-slash-flag
|
||
(mapcar #'(lambda (x)
|
||
(if (cdr x) (cons (concat (car x) "/") (cdr x)) x))
|
||
sub-folders)
|
||
sub-folders)))
|
||
|
||
(defun mh-sub-folders-actual (folder)
|
||
"Execute the command folders to return the sub-folders of FOLDER.
|
||
Filters out the folder names that start with \".\" so that
|
||
directories that aren't usually mail folders are hidden."
|
||
(let ((arg-list `(,(expand-file-name "folders" mh-progs)
|
||
nil (t nil) nil "-noheader" "-norecurse" "-nototal"
|
||
,@(if (stringp folder) (list folder) ())))
|
||
(results ())
|
||
(current-folder (concat
|
||
(with-temp-buffer
|
||
(call-process (expand-file-name "folder" mh-progs)
|
||
nil '(t nil) nil "-fast")
|
||
(buffer-substring (point-min) (1- (point-max))))
|
||
"+")))
|
||
(with-temp-buffer
|
||
(apply #'call-process arg-list)
|
||
(goto-char (point-min))
|
||
(while (not (and (eolp) (bolp)))
|
||
(goto-char (line-end-position))
|
||
(let ((start-pos (line-beginning-position))
|
||
(has-pos (search-backward " has " (line-beginning-position) t)))
|
||
(when (integerp has-pos)
|
||
(while (equal (char-after has-pos) ? )
|
||
(decf has-pos))
|
||
(incf has-pos)
|
||
(while (equal (char-after start-pos) ? )
|
||
(incf start-pos))
|
||
(let* ((name (buffer-substring start-pos has-pos))
|
||
(first-char (aref name 0))
|
||
(last-char (aref name (1- (length name)))))
|
||
(unless (member first-char '(?. ?# ?,))
|
||
(when (and (equal last-char ?+) (equal name current-folder))
|
||
(setq name (substring name 0 (1- (length name)))))
|
||
(push
|
||
(cons name
|
||
(search-forward "(others)" (line-end-position) t))
|
||
results))))
|
||
(forward-line 1))))
|
||
(setq results (nreverse results))
|
||
(when (stringp folder)
|
||
(setq results (cdr results))
|
||
(let ((folder-name-len (length (format "%s/" (substring folder 1)))))
|
||
(setq results (mapcar (lambda (f)
|
||
(cons (substring (car f) folder-name-len)
|
||
(cdr f)))
|
||
results))))
|
||
results))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-remove-from-sub-folders-cache (folder)
|
||
"Remove FOLDER and its parent from `mh-sub-folders-cache'.
|
||
FOLDER should be unconditionally removed from the cache. Also the
|
||
last ancestor of FOLDER present in the cache must be removed as
|
||
well.
|
||
|
||
To see why this is needed assume we have a folder +foo which has
|
||
a single sub-folder qux. Now we create the folder +foo/bar/baz.
|
||
Here we will need to invalidate the cached sub-folders of +foo,
|
||
otherwise completion on +foo won't tell us about the option
|
||
+foo/bar!"
|
||
(remhash folder mh-sub-folders-cache)
|
||
(block ancestor-found
|
||
(let ((parent folder)
|
||
(one-ancestor-found nil)
|
||
last-slash)
|
||
(while (setq last-slash (mh-search-from-end ?/ parent))
|
||
(setq parent (substring parent 0 last-slash))
|
||
(unless (eq (gethash parent mh-sub-folders-cache 'none) 'none)
|
||
(remhash parent mh-sub-folders-cache)
|
||
(if one-ancestor-found
|
||
(return-from ancestor-found)
|
||
(setq one-ancestor-found t))))
|
||
(remhash nil mh-sub-folders-cache))))
|
||
|
||
|
||
|
||
;;; Folder Utilities
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-folder-name-p (name)
|
||
"Return non-nil if NAME is the name of a folder.
|
||
A name (a string or symbol) can be a folder name if it begins
|
||
with \"+\"."
|
||
(if (symbolp name)
|
||
(eq (aref (symbol-name name) 0) ?+)
|
||
(and (> (length name) 0)
|
||
(eq (aref name 0) ?+))))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-expand-file-name (filename &optional default)
|
||
"Expand FILENAME like `expand-file-name', but also handle MH folder names.
|
||
Any filename that starts with '+' is treated as a folder name.
|
||
See `expand-file-name' for description of DEFAULT."
|
||
(if (mh-folder-name-p filename)
|
||
(expand-file-name (substring filename 1) mh-user-path)
|
||
(expand-file-name filename default)))
|
||
|
||
(defvar mh-folder-hist nil)
|
||
|
||
;; Shush compiler.
|
||
(eval-when-compile (defvar mh-speed-flists-cache))
|
||
|
||
(defvar mh-allow-root-folder-flag nil
|
||
"Non-nil means \"+\" is an acceptable folder name.
|
||
This variable is used to communicate with
|
||
`mh-folder-completion-function'. That function can have exactly
|
||
three arguments so we bind this variable to t or nil.
|
||
|
||
This variable should never be set.")
|
||
|
||
(defvar mh-folder-completion-map (copy-keymap minibuffer-local-completion-map))
|
||
(define-key mh-folder-completion-map " " 'minibuffer-complete) ;Why???
|
||
|
||
(defvar mh-speed-flists-inhibit-flag nil)
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-speed-flists-active-p ()
|
||
"Check if speedbar is running with message counts enabled."
|
||
(and (featurep 'mh-speed)
|
||
(not mh-speed-flists-inhibit-flag)
|
||
(> (hash-table-count mh-speed-flists-cache) 0)))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-folder-completion-function (name predicate flag)
|
||
"Programmable completion for folder names.
|
||
NAME is the partial folder name that has been input. PREDICATE if
|
||
non-nil is a function that is used to filter the possible choices
|
||
and FLAG determines whether the completion is over."
|
||
(let* ((orig-name name)
|
||
(name (mh-normalize-folder-name name nil t))
|
||
(last-slash (mh-search-from-end ?/ name))
|
||
(last-complete (if last-slash (substring name 0 last-slash) nil))
|
||
(remainder (cond (last-complete (substring name (1+ last-slash)))
|
||
((and (> (length name) 0) (equal (aref name 0) ?+))
|
||
(substring name 1))
|
||
(t ""))))
|
||
(cond ((eq flag nil)
|
||
(let ((try-res (try-completion
|
||
name
|
||
(mapcar (lambda (x)
|
||
(cons (if (not last-complete)
|
||
(concat "+" (car x))
|
||
(concat last-complete "/" (car x)))
|
||
(cdr x)))
|
||
(mh-sub-folders last-complete t))
|
||
predicate)))
|
||
(cond ((eq try-res nil) nil)
|
||
((and (eq try-res t) (equal name orig-name)) t)
|
||
((eq try-res t) name)
|
||
(t try-res))))
|
||
((eq flag t)
|
||
(all-completions
|
||
remainder (mh-sub-folders last-complete t) predicate))
|
||
((eq flag 'lambda)
|
||
(let ((path (concat mh-user-path
|
||
(substring (mh-normalize-folder-name name) 1))))
|
||
(cond (mh-allow-root-folder-flag (file-exists-p path))
|
||
((equal path mh-user-path) nil)
|
||
(t (file-exists-p path))))))))
|
||
|
||
;; Shush compiler.
|
||
(eval-when-compile
|
||
(mh-do-in-xemacs
|
||
(defvar completion-root-regexp)
|
||
(defvar minibuffer-completing-file-name)))
|
||
|
||
(defun mh-folder-completing-read (prompt default allow-root-folder-flag)
|
||
"Read folder name with PROMPT and default result DEFAULT.
|
||
If ALLOW-ROOT-FOLDER-FLAG is non-nil then \"+\" is allowed to be
|
||
a folder name corresponding to `mh-user-path'."
|
||
(mh-normalize-folder-name
|
||
(let ((minibuffer-completing-file-name t)
|
||
(completion-root-regexp "^[+/]")
|
||
(minibuffer-local-completion-map mh-folder-completion-map)
|
||
(mh-allow-root-folder-flag allow-root-folder-flag))
|
||
(completing-read prompt 'mh-folder-completion-function nil nil nil
|
||
'mh-folder-hist default))
|
||
t))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-prompt-for-folder (prompt default can-create
|
||
&optional default-string allow-root-folder-flag)
|
||
"Prompt for a folder name with PROMPT.
|
||
Returns the folder's name as a string. DEFAULT is used if the
|
||
folder exists and the user types return. If the CAN-CREATE flag
|
||
is t, then a folder is created if it doesn't already exist. If
|
||
optional argument DEFAULT-STRING is non-nil, use it in the prompt
|
||
instead of DEFAULT. If ALLOW-ROOT-FOLDER-FLAG is non-nil then the
|
||
function will accept the folder +, which means all folders when
|
||
used in searching."
|
||
(if (null default)
|
||
(setq default ""))
|
||
(let* ((default-string (cond (default-string (format " (default %s)" default-string))
|
||
((equal "" default) "")
|
||
(t (format " (default %s)" default))))
|
||
(prompt (format "%s folder%s: " prompt default-string))
|
||
(mh-current-folder-name mh-current-folder)
|
||
read-name folder-name)
|
||
(while (and (setq read-name (mh-folder-completing-read
|
||
prompt default allow-root-folder-flag))
|
||
(equal read-name "")
|
||
(equal default "")))
|
||
(cond ((or (equal read-name "")
|
||
(and (equal read-name "+") (not allow-root-folder-flag)))
|
||
(setq read-name default))
|
||
((not (mh-folder-name-p read-name))
|
||
(setq read-name (format "+%s" read-name))))
|
||
(if (or (not read-name) (equal "" read-name))
|
||
(error "No folder specified"))
|
||
(setq folder-name read-name)
|
||
(cond ((and (> (length folder-name) 0)
|
||
(eq (aref folder-name (1- (length folder-name))) ?/))
|
||
(setq folder-name (substring folder-name 0 -1))))
|
||
(let* ((last-slash (mh-search-from-end ?/ folder-name))
|
||
(parent (and last-slash (substring folder-name 0 last-slash)))
|
||
(child (if last-slash
|
||
(substring folder-name (1+ last-slash))
|
||
(substring folder-name 1))))
|
||
(unless (member child
|
||
(mapcar #'car (gethash parent mh-sub-folders-cache)))
|
||
(mh-remove-from-sub-folders-cache folder-name)))
|
||
(let ((new-file-flag
|
||
(not (file-exists-p (mh-expand-file-name folder-name)))))
|
||
(cond ((and new-file-flag
|
||
can-create
|
||
(y-or-n-p
|
||
(format "Folder %s does not exist. Create it? "
|
||
folder-name)))
|
||
(message "Creating %s" folder-name)
|
||
(mh-exec-cmd-error nil "folder" folder-name)
|
||
(mh-remove-from-sub-folders-cache folder-name)
|
||
(when (boundp 'mh-speed-folder-map)
|
||
(mh-speed-add-folder folder-name))
|
||
(message "Creating %s...done" folder-name))
|
||
(new-file-flag
|
||
(error "Folder %s does not exist" folder-name))
|
||
((not (file-directory-p (mh-expand-file-name folder-name)))
|
||
(error "%s is not a directory"
|
||
(mh-expand-file-name folder-name)))))
|
||
folder-name))
|
||
|
||
|
||
|
||
;;; Message Utilities
|
||
|
||
;; Functions that would ordinarily be in mh-letter.el that are needed
|
||
;; by mh-show.el are found here in order to prevent the loading of
|
||
;; mh-letter.el until a message is actually composed.
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-in-header-p ()
|
||
"Return non-nil if the point is in the header of a draft message."
|
||
(< (point) (mh-mail-header-end)))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-extract-from-header-value ()
|
||
"Extract From: string from header."
|
||
(save-excursion
|
||
(if (not (mh-goto-header-field "From:"))
|
||
nil
|
||
(skip-chars-forward " \t")
|
||
(buffer-substring-no-properties
|
||
(point) (progn (mh-header-field-end)(point))))))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-goto-header-field (field)
|
||
"Move to FIELD in the message header.
|
||
Move to the end of the FIELD name, which should end in a colon.
|
||
Returns t if found, nil if not."
|
||
(goto-char (point-min))
|
||
(let ((case-fold-search t)
|
||
(headers-end (save-excursion
|
||
(mh-goto-header-end 0)
|
||
(point))))
|
||
(re-search-forward (format "^%s" field) headers-end t)))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-goto-header-end (arg)
|
||
"Move the cursor ARG lines after the header."
|
||
(if (re-search-forward "^-*$" nil nil)
|
||
(forward-line arg)))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-mail-header-end ()
|
||
"Substitute for `mail-header-end' that doesn't widen the buffer.
|
||
|
||
In MH-E we frequently need to find the end of headers in nested
|
||
messages, where the buffer has been narrowed. This function works
|
||
in this situation."
|
||
(save-excursion
|
||
;; XXX: The following replaces a call to rfc822-goto-eoh. Occasionally,
|
||
;; mail headers that MH-E has to read contains lines of the form:
|
||
;; From xxx@yyy Mon May 10 11:48:07 2004
|
||
;; In this situation, rfc822-goto-eoh doesn't go to the end of the
|
||
;; header. The replacement allows From_ lines in the mail header.
|
||
(goto-char (point-min))
|
||
(loop for p = (re-search-forward
|
||
"^\\([:\n]\\|[^: \t\n]+[ \t\n]\\)" nil 'move)
|
||
do (cond ((null p) (return))
|
||
(t (goto-char (match-beginning 0))
|
||
(unless (looking-at "From ") (return))
|
||
(goto-char p))))
|
||
(point)))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-header-field-beginning ()
|
||
"Move to the beginning of the current header field.
|
||
Handles RFC 822 continuation lines."
|
||
(beginning-of-line)
|
||
(while (looking-at "^[ \t]")
|
||
(forward-line -1)))
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-header-field-end ()
|
||
"Move to the end of the current header field.
|
||
Handles RFC 822 continuation lines."
|
||
(forward-line 1)
|
||
(while (looking-at "^[ \t]")
|
||
(forward-line 1))
|
||
(backward-char 1)) ;to end of previous line
|
||
|
||
;;;###mh-autoload
|
||
(defun mh-signature-separator-p ()
|
||
"Return non-nil if buffer includes \"^-- $\"."
|
||
(save-excursion
|
||
(goto-char (point-min))
|
||
(re-search-forward mh-signature-separator-regexp nil t)))
|
||
|
||
(provide 'mh-utils)
|
||
|
||
;; Local Variables:
|
||
;; indent-tabs-mode: nil
|
||
;; sentence-end-double-space: nil
|
||
;; End:
|
||
|
||
;; arch-tag: 1af39fdf-f66f-4b06-9b48-18a7656c8e36
|
||
;;; mh-utils.el ends here
|