文脈を予想しながら適切にコピーと切り取りをしてくれるコマンド

カーソル周辺の文字列を適切に取ってくれるthing-at-pointがとても便利です。
ただ、いちいち切り取る文脈を指定するのが複雑だと感じていました。

そこで、(thing-at-point 'symbol)は'('等の上ではnilを返すことを利用して、

  1. (thing-at-point 'symbol)
  2. 失敗したら、(thing-at-point 'sexp)
  3. 失敗したら、(thing-at-point 'defun)

・・・のように振舞うコピーコマンドと切り取りコマンドを作ってみました。
キーワードの上で実行したらそのキーワードを切り取り、'('や')'、'{'や'}'の上で実行すればその式を丸ごと切り取り、それ以外の場所(Ctrl+aで戻れる行頭とか)で実行すれば関数をまるごと切り取ります。
関数の切り取り方には若干不満があって、大抵付けてある関数上のコメントが切り取れないというのがあります。その内改良するかもしれません。

(defun copy-at-point (thing)
  (kill-new (thing-at-point thing))
  (end-of-thing thing))

(defun copy-defun ()
  (let (start end)
    (beginning-of-defun)
    (setq start (point))
    (end-of-defun)
    (setq end (point))
    (kill-ring-save start end)))

(defun context-copy ()
  (interactive)
  (if (not (null (thing-at-point 'symbol)))
      (copy-at-point 'symbol)
    (if (not (null (thing-at-point 'sexp)))
	(copy-at-point 'sexp)
      (copy-defun))))

;;元のキーは iconify-or-deiconify-frame(Suspend)
(global-set-key "\C-z" 'context-copy)

(defun kill-at-point (thing)
  (let (start end)
    (beginning-of-thing thing)
    (setq start (point))
    (end-of-thing thing)
    (setq end (point))
    (kill-region start end)))

(defun kill-defun ()
  (let (start end)
    (beginning-of-defun)
    (setq start (point))
    (end-of-defun)
    (setq end (point))
    (kill-region start end)))

(defun context-kill ()
  (interactive)
  (if (not (null (thing-at-point 'symbol)))
      (kill-at-point 'symbol)
    (if (not (null (thing-at-point 'sexp)))
	(kill-at-point 'sexp)
      (kill-defun))))

;;元のキーは zap-to-char
(global-set-key "\M-z" 'context-kill)