diff options
| -rw-r--r-- | message-templ.el | 353 | 
1 files changed, 353 insertions, 0 deletions
| diff --git a/message-templ.el b/message-templ.el new file mode 100644 index 0000000..333d8ac --- /dev/null +++ b/message-templ.el @@ -0,0 +1,353 @@ +;;; message-templ.el --- Template feature for message. + +;; Copyright (C) 1998,1999,2000 Masahiro MURATA <muse@ba2.so-net.ne.jp> +;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org> +;; Copyright (C) 2004 ARISAWA Akihiro <ari@mbf.sphere.ne.jp> + +;; Author: ARISAWA Akihiro <ari@mbf.sphere.ne.jp> +;; Keywords: mail, news, template + +;; This file is not part of GNU Emacs. + +;; This program 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. +;; +;; This program 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., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. +;; + +;;; Commentary: + +;; Original codes are wl-template.el and wl-draft.el. + +;;; Code: + +(require 'message) +(autoload 'article-display-x-face "gnus-art" nil t) + +(defgroup message-temp nil +  "Template for message composing." +  :group 'message) + +(defcustom message-templ-alist nil +  "Alist of template. +First element of each list is a string specifies the name of the template. +Remaining elements indicate actions." +  :type '(repeat (list (string :tag "Name") +		       (repeat +			:inline t +			(choice (cons (sexp :tag "Field(Variable)") +				      (sexp :tag "Value")) +				(sexp :tag "Function"))))) +  :group 'message-templ) + +(defcustom message-templ-visible-select t +  "*If non-nil, select template with visible." +  :type 'boolean +  :group 'message-templ) + +(defcustom message-templ-confirm nil +  "*If non-nil, require your confirmation when selected template." +  :type 'boolean +  :group 'message-templ) + +(defcustom message-templ-buffer-lines 7 +  "*Lines of template buffer." +  :type 'integer +  :group 'message-templ) + +(defvar message-templ-default-name "default") +(defvar message-templ-buffer-name "*Message-Template*") +(defvar message-templ-mode-map nil) + +(defvar message-templ nil) +(defvar message-templ-cur-num 0) +(defvar message-templ-max-num 0) +(defvar message-templ-draft-buffer nil) +(defvar message-templ-preview nil) +(defvar message-templ-config-variables nil) + +(defvar message-templ-config-sub-function-alist +  '((body		. message-templ-config-sub-body) +    (top		. message-templ-config-sub-top) +    (bottom		. message-templ-config-sub-bottom) +    (header		. message-templ-config-sub-header) +    (header-top		. message-templ-config-sub-header-top) +    (header-bottom	. message-templ-config-sub-header) +;    (part-top		. message-templ-config-sub-part-top) +;    (part-bottom	. message-templ-config-sub-part-bottom) +    (body-file		. message-templ-config-sub-body-file) +    (top-file		. message-templ-config-sub-top-file) +    (bottom-file	. message-templ-config-sub-bottom-file) +    (header-file	. message-templ-config-sub-header-file) +    (template		. message-templ-config-sub-template) +    (x-face		. message-templ-config-sub-x-face))) + +(unless message-templ-mode-map +  (setq message-templ-mode-map (make-sparse-keymap)) +  (define-key message-templ-mode-map "p" 'message-templ-prev) +  (define-key message-templ-mode-map "n" 'message-templ-next) +  (define-key message-templ-mode-map "q" 'message-templ-abort) +  (define-key message-templ-mode-map "\r" 'message-templ-set) +  (define-key message-templ-mode-map "\n" 'message-templ-set)) + +(defsubst message-templ-config-sub-eval-insert (content &optional newline) +  (let (content-value) +    (when (and content +	       (stringp (setq content-value (eval content)))) +      (insert content-value) +      (when newline (insert "\n"))))) + +(defun message-templ-config-sub-body (content) +  (message-goto-body) +  (delete-region (point) (point-max)) +  (message-templ-config-sub-eval-insert content)) + +(defun message-templ-config-sub-top (content) +  (message-goto-body) +  (message-templ-config-sub-eval-insert content)) + +(defun message-templ-config-sub-bottom (content) +  (goto-char (point-max)) +  (message-templ-config-sub-eval-insert content)) + +(defun message-templ-config-sub-header (content) +  (message-goto-eoh) +  (message-templ-config-sub-eval-insert content 'newline)) + +(defun message-templ-config-sub-header-top (content) +  (goto-char (point-min)) +  (message-templ-config-sub-eval-insert content 'newline)) + +;(defun message-templ-config-sub-part-top (content) +;  (goto-char (mime-edit-content-beginning)) +;  (message-templ-config-sub-eval-insert content 'newline)) + +;(defun message-templ-config-sub-part-bottom (content) +;  (goto-char (mime-edit-content-end)) +;  (message-templ-config-sub-eval-insert content 'newline)) + +(defsubst message-templ-config-sub-file (content) +  (let ((coding-system-for-read 'undecided) +	(file (expand-file-name (eval content)))) +    (if (file-exists-p file) +	(insert-file-contents file) +      (error "%s: no exists file" file)))) + +(defun message-templ-config-sub-body-file (content) +  (message-goto-body) +  (delete-region (point) (point-max)) +  (message-templ-config-sub-file content)) + +(defun message-templ-config-sub-top-file (content) +  (message-goto-body) +  (message-templ-config-sub-file content)) + +(defun message-templ-config-sub-bottom-file (content) +  (goto-char (point-max)) +  (message-templ-config-sub-file content)) + +(defun message-templ-config-sub-header-file (content) +  (message-goto-eoh) +  (message-templ-config-sub-file content)) + +(defun message-templ-config-sub-template (content) +  (setq message-templ-config-variables +	(message-templ-insert (eval content)))) + +(defun message-templ-config-sub-x-face (content) +  (save-restriction +    (message-narrow-to-headers) +    (message-remove-header "X-Face")) +  (message-position-on-field "X-Face" "From") +  (nnheader-insert-file-contents content)) + +(defun message-templ-config-sub-function (field content) +  (let (func) +    (when (setq func (assq field message-templ-config-sub-function-alist)) +      (let (message-templ-config-variables) +	(funcall (cdr func) content) +	;; for message-templ-config-sub-template +	(cons t message-templ-config-variables))))) + +(defun messsage-templ-config-exec-sub (clist) +  (let (config local-variables) +    (while clist +      (setq config (car clist)) +      (cond +       ((functionp config) +	(funcall config)) +       ((consp config) +	(let ((field (car config)) +	      (content (cdr config)) +	      ret-val) +	  (cond +	   ((stringp field) +	    (save-restriction +	      (message-narrow-to-headers) +	      (message-remove-header field)) +	    (message-position-on-field field) +	    (insert (eval content))) +	   ((setq ret-val (message-templ-config-sub-function field content)) +	    (when (cdr ret-val) ;; for message-templ-config-sub-template +	      (setq local-variables (nconc local-variables (cdr ret-val))))) +	   ((boundp field) ;; variable +	    (make-local-variable field) +	    (set field (eval content)) +	    (setq local-variables (nconc local-variables (list field)))) +	   (t +	    (error "%s: not variable" field))))) +       (t +	(error "%s: not supported type" config))) +      (setq clist (cdr clist))) +    local-variables)) + +(defun message-templ-preview-p () +  "Return non-nil when preview template." +  message-templ-preview) + +(defun message-templ-apply (name) +  "Apply NAME template to draft." +  (let (template) +    (when name +      (when (string= name "") +	(setq name message-templ-default-name)) +      (when (setq template (cdr (assoc name message-templ-alist))) +	(save-excursion +	  (messsage-templ-config-exec-sub template)))))) + +(defun message-templ-mode () +  "Major mode for message template. + +\\{message-templ-mode} + +Entering Message-Templ mode calls the value of `message-templ-mode-hook'." +  (kill-all-local-variables) +  (setq mode-name "Message-Templ" +	major-mode 'message-templ-mode) +  (use-local-map message-templ-mode-map) +  (set (make-local-variable 'font-lock-defaults) +       '(message-font-lock-keywords t)) +  (setq buffer-read-only t) +  (run-hooks 'message-templ-mode-hook)) + +(defun message-templ-select (&optional arg) +  "Select template from `message-templ-alist'." +  (interactive "P") +  (if (not (if arg +	       (not message-templ-visible-select) +	     message-templ-visible-select)) +      (message-templ-apply +       (completing-read (format "Template (%s): " message-templ-default-name) +			message-templ-alist)) +    (let* ((begin message-templ-default-name) +	   (work message-templ-alist)) +      (when (and begin (cdr (assoc begin message-templ-alist))) +	(while (not (string= (car (car work)) begin)) +	  (setq message-templ-cur-num (1+ message-templ-cur-num)) +	  (setq work (cdr work)))) +      (setq message-templ nil +	    message-templ-cur-num 0 +	    message-templ-max-num (length message-templ-alist)) +      (setq message-templ-draft-buffer (current-buffer)) +      (if (get-buffer-window message-templ-buffer-name) +	  (select-window (get-buffer-window message-templ-buffer-name)) +	(let* ((cur-win (selected-window)) +	       (size (min +		      (- (window-height cur-win) +			 window-min-height 1) +		      (- (window-height cur-win) +			 (max window-min-height +			      (1+ message-templ-buffer-lines)))))) +	  (split-window cur-win (if (> size 0) size window-min-height)) +	  ;; goto the bottom of the two... +	  (select-window (next-window)) +	  ;; make it display... +	  (let ((pop-up-windows nil)) +	    (switch-to-buffer (get-buffer-create message-templ-buffer-name))))) +      (set-buffer message-templ-buffer-name) +      (message-templ-mode) +      (message-templ-show)))) + +(defun message-templ-show (&optional arg) +  "Show reference INDEX in `message-templ-alist'. +vARG is ignored."			; ARG ignored this version (?) +  (save-excursion +    (set-buffer message-templ-buffer-name) +    (let ((buffer-read-only nil) +	  (message-templ-preview t) +	  (mail-header-separator  "--header separater--")) +      (erase-buffer) +      (goto-char (point-min)) +      (message-templ-insert +       (setq message-templ +	     (car (nth message-templ-cur-num message-templ-alist))) +       mail-header-separator) +      (let ((gnus-article-buffer (current-buffer))) +	(article-display-x-face)) +      (setq mode-line-process (concat ":" message-templ)) +      (set-buffer-modified-p nil)))) + +(defun message-templ-next () +  "Display next reference in other buffer." +  (interactive) +  (when (= message-templ-max-num +	   (setq message-templ-cur-num (1+ message-templ-cur-num))) +    (setq message-templ-cur-num 0)) +  (message-templ-show)) + +(defun message-templ-prev () +  "Display previous reference in other buffer." +  (interactive) +  (setq message-templ-cur-num (if (zerop message-templ-cur-num) +				  (1- message-templ-max-num) +				(1- message-templ-cur-num))) +  (message-templ-show)) + +(defun message-templ-abort () +  "Exit from electric reference mode without inserting reference." +  (interactive) +  (setq message-templ nil) +  (delete-window) +  (kill-buffer message-templ-buffer-name) +  (when (buffer-live-p message-templ-draft-buffer) +    (set-buffer message-templ-draft-buffer) +    (let ((win (get-buffer-window message-templ-draft-buffer))) +      (when win (select-window win))))) + +(defun message-templ-set () +  "Exit from electric reference mode and insert selected reference." +  (interactive) +  (if (and message-templ-confirm +	   (not (y-or-n-p "Are you sure ? "))) +      (message "") +    (delete-window) +    (kill-buffer message-templ-buffer-name) +    (when (buffer-live-p message-templ-draft-buffer) +      (set-buffer message-templ-draft-buffer) +      (message-templ-apply message-templ) +      (let ((win (get-buffer-window message-templ-draft-buffer))) +	(when win (select-window win)))))) + +(defun message-templ-insert (name &optional mail-header) +  "Insert NAME template. +Set header-separator is MAIL-HEADER." +  (let ((template (cdr (assoc name message-templ-alist))) +	(mail-header-separator (or mail-header +				   mail-header-separator))) +    (when template +      (when mail-header +	(insert mail-header-separator "\n")) +      (messsage-templ-config-exec-sub template)))) + +(provide 'message-templ) +;;; message-templ.el ends here | 
