.emacsの設定に役立つ関数

.emacsの中で定義していて便利だなと感じる関数/マクロの紹介。
とりあえず、aifとand-let*はUtilityとして必要かなと思います。
他にon-offを切り替えるトグルスイッチ見たいな関数を楽に定義できるdef-toggleというものを定義して使っています。

utilities

(require 'cl)

(defmacro aif (p true-clause &rest false-clause)
  (declare (indent 2))
  `(let ((it ,p))
     (if it ,true-clause ,@false-clause)))

(defun singlep (pair)
  (and (consp pair) (null (cdr pair))))

(defmacro and-let* (exp &rest body)
  (declare (indent 1) (debug t))
  `(%and-let* ,exp ,body))

(defmacro %and-let* (exp body)
  (cond ((null exp) `(progn ,@body))
	((singlep (car exp))
	 `(if ,@(car exp)
	      (%and-let* ,(cdr exp)
			 ,body)))
	(t `(let (,(car exp))
	      (and ,(caar exp) (%and-let* ,(cdr exp)
					  ,body))))))

def-toggle

(defmacro def-toggle (name docstring &rest body)
    (multiple-value-bind (docstring body) ;docstringに対応するためのdispatch
	(if (eq 'string (type-of docstring)) 
	    (values docstring body)
	    (values "" (cons docstring body)))
      (and-let* ((on-clause (aif (assoc-default :on body) `(progn ,@it)))
		 (off-clause (aif (assoc-default :off body) `(progn ,@it)))
		 (state (gensym)) (flag (gensym)))
        `(lexical-let (,state)
	   (defun ,name (&optional ,flag)
	     ,docstring
	     (interactive "P")
	     (case ,flag
	       ((1) (progn ,on-clause (setq ,state t)))
	       ((-1) (progn ,off-clause (setq ,state nil)))
	       (otherwise (,name (if (not ,state) 1 -1)))))))))

;;defunやdefmacroのように色をつける(他に良い方法があったら教えてください><)
(font-lock-add-keywords 'emacs-lisp-mode '(("(\\(def-toggle\\)" 1 font-lock-keyword-face)))

使い方

(def-toggle kmacro-start-stop-toggle 	
  "開始と終了を同じキーバインドで行える"
  (:on (kmacro-start-macro nil))
  (:off (kmacro-end-macro nil)))

(global-set-key [f3] 'kmacro-start-stop-toggle)