2023年3月28日
emacsはサードパティ製のパッケージを使わなくても、標準の関数を利用してコーディングが可能です。便利なのにデフォルトではバインドされていない関数があったりするので、オススメの関数ちょっと紹介します。それに加えて、関数を作成して編集が楽になるバインディングも紹介します。
全体のコードはページの最後にまとめてあります。
kill-this-buffer
;; 現在開いているバッファを閉じる
(global-set-key (kbd "C-c k") 'kill-this-buffer)
kill-this-buffer
は現在開いているバッファを閉じます。toggle-truncate-lines
;; 行の画面外の折り返しを切り替えるショートカット
(global-set-key (kbd "M-l") 'toggle-truncate-lines)
toggle-truncate-lines
はテキストがウィンドウの端まで到達し、画面外に文字を伸ばすのか、折り返すのかを切り分ける関数です。コーディングしているときは外部にはみ出したほうが読みやすかったり、はたまた文章を書くときは折り返されたほうが読みやすかったりします。はみ出した行を切り取る。
はみ出した行を折り返す。
表示の切り替えをすぐにできたほうが便利なので
M-l
にバインドします。M-l
はデフォルトではdowncase-word
が割り当てられています。これはカーソルの位置から見て前に大文字の単語があれば、それを全て小文字にするという関数です。コーディングでも文章を書くときでも利用するシーンは少ないので上書きします。comment-or-uncomment-region
選択している範囲のコードをコメントイン、コメントアウトを切り替える関数です。
コードを書いているときに素早くコメントアウトできるのは重要です。
;; 選択範囲を全てコメントアウト、コメントインする
(global-set-key (kbd "C-c /") 'comment-or-uncomment-region)
C-SPC
で選択モードにしてコメントアウトしたい範囲を選び、そのままC-c /
でコメントアウトします。コメントインもC-SPC
でコメントアウトされた範囲を選び、C-c /
でコメントインします。revert-buffer-no-confirm
ここからはemacsの標準の関数を使うのではなく、いろんなサイトを参考にして作った関数を使います。
revert-buffer-no-confirm
はバッファのリロード機能です。バッファはファイルを直接編集しているわけではないので、たまにファイルとバッファで差分が生まれます。特にgitを利用していて、ブランチを移動したり、リベースしたりすると、ファイルとバッファが異なる状態になります。バッファ側の内容を優先させるのではなく、gitで移動した先のファイル情報をバッファに適応したい場合に
revert-buffer-no-confirm
を実行してバッファをリロードします。;; バッファの再読み込みをC-M-rで実行する
(defun revert-buffer-no-confirm (&optional force-reverting)
(interactive "P")
(if (or force-reverting (not (buffer-modified-p)))
(revert-buffer :ignore-auto :noconfirm)
(error "The buffer has been modified")))
(global-set-key (kbd "C-M-r") 'revert-buffer-no-confirm)
上書きする
C-M-r
はデフォルトでisearch-backward-regexp
です。これは正規表現を利用してカーソルより前の文字を検索するバインドです。一般的にC-r
のisearch-backward
を使うので上書きしても問題ありません。kill-dired-buffers
emacsはバッファでフォルダを開くことできます。
C-x C-f
でファイルじゃなくフォルダを選んでエンターを押すと、フォルダ情報がバッファに展開されます。バッファに開かれたディレクトリバッファ内でフォルダを移動すると、このように、大量にディレクトリバッファが開かれます。
1つ1つ削除するのは大変なので、
kill-dired-buffers
で一括削除します。;; ディレクトリバッファを全て削除
(defun kill-dired-buffers ()
(interactive)
(mapc (lambda (buffer)
(when (eq 'dired-mode (buffer-local-value 'major-mode buffer))
(kill-buffer buffer)))
(buffer-list)))
(global-set-key (kbd "C-c d d") 'kill-dired-buffers)
この関数はそこまで使わないので、空いている
C-c d d
に割り振ります。mark-whole-word
mark-whole-wordはカーソルの下にある英単語全体を選択します。プログラムを書いていて、目的の変数にカーソルを移動して、その変数をコピーまたは切り取りしたいとします。
単語の先頭までカーソルを移動し、
C-SPC
で選択モードにして、変数の終わりまでカーソルを移動して、M-w
でコピー、C-w
で切り取りをするのは正直面倒です。mark-whole-word
を使えば一瞬で選択されます。;; カーソルの下にある単語を全体を選択
(defun mark-whole-word (&optional arg allow-extend)
"Like `mark-word', but selects whole words and skips over whitespace.
If you use a negative prefix arg then select words backward.
Otherwise select them forward.
If cursor starts in the middle of word then select that whole word.
If there is whitespace between the initial cursor position and the
first word (in the selection direction), it is skipped (not selected).
If the command is repeated or the mark is active, select the next NUM
words, where NUM is the numeric prefix argument. (Negative NUM
selects backward.)"
(interactive "P\\np")
(let ((num (prefix-numeric-value arg)))
(unless (eq last-command this-command)
(if (natnump num)
(skip-syntax-forward "\\\\s-")
(skip-syntax-backward "\\\\s-")))
(unless (or (eq last-command this-command)
(if (natnump num)
(looking-at "\\\\b")
(looking-back "\\\\b")))
(if (natnump num)
(left-word)
(right-word)))
(mark-word arg allow-extend)))
(global-set-key (kbd "C-c @") 'mark-whole-word)
変数にカーソルを合わせます。
C-c @
を実行すると、userAge
変数が全て選択されます。copy-word
このコマンドはカーソルの下にある単語をコピーします。1つ前の
mark-whole-word
は選択でしたが、こちらはそれのコピーバージョンです。;; カーソルを置いてある単語をコピーする
(defun copy-word (&optional arg)
"Copy words at point into kill-ring"
(interactive "P")
(defun get-point (symbol &optional arg)
"get the point"
(funcall symbol arg)
(point))
(defun copy-thing (begin-of-thing end-of-thing &optional arg)
"Copy thing between beg & end into kill ring."
(save-excursion
(let ((beg (get-point begin-of-thing 1))
(end (get-point end-of-thing arg)))
(copy-region-as-kill beg end))))
(copy-thing 'backward-word 'forward-word arg))
(global-set-key (kbd "C-c w") 'copy-word)
使い方は
mark-whole-word
と同じで、コピーしたい英単語の上でC-c w
を実行するだけでkill ringに単語がコピーされます。copy-whole-line
copy-whole-line
はカーソルがある行を丸ごとコピーするコマンドです。 ;; 一行を丸ごとコピー
(defun copy-whole-line (&optional arg)
"Copy current line."
(interactive "p")
(or arg (setq arg 1))
(if (and (> arg 0) (eobp) (save-excursion (forward-visible-line 0) (eobp)))
(signal 'end-of-buffer nil))
(if (and (< arg 0) (bobp) (save-excursion (end-of-visible-line) (bobp)))
(signal 'beginning-of-buffer nil))
(unless (eq last-command 'copy-region-as-kill)
(kill-new "")
(setq last-command 'copy-region-as-kill))
(cond ((zerop arg)
(save-excursion
(copy-region-as-kill (point) (progn (forward-visible-line 0) (point)))
(copy-region-as-kill (point) (progn (end-of-visible-line) (point)))))
((< arg 0)
(save-excursion
(copy-region-as-kill (point) (progn (end-of-visible-line) (point)))
(copy-region-as-kill (point)
(progn (forward-visible-line (1+ arg))
(unless (bobp) (backward-char))
(point)))))
(t
(save-excursion
(copy-region-as-kill (point) (progn (forward-visible-line 0) (point)))
(copy-region-as-kill (point)
(progn (forward-visible-line arg) (point))))))
(message (substring (car kill-ring-yank-pointer) 0 -1)))
(global-set-key (kbd "C-c l") 'copy-whole-line)
バインドキーは
C-c l
です。まとめ
バインドした関数とショートカットをまとめておきます。
- kill-this-buffer C-c k
- toggle-truncate-lines M-l
- comment-or-uncomment-region C-c /
- revert-buffer-no-confirm C-M-r
- kill-dired-buffers C-c d d
- mark-whole-word C-c @
- copy-word C-c w
- copy-whole-line C-c l
ここで挙げたもの以外にもEmacsは標準で搭載されていて便利な関数があるので、ぜひ自分で探して、バインドしてみてください。
;; 現在開いているバッファを閉じる
(global-set-key (kbd "C-c k") 'kill-this-buffer)
;; 行の画面外の折り返しを切り替えるショートカット
(global-set-key (kbd "M-l") 'toggle-truncate-lines)
;; 選択範囲を全てコメントアウト、コメントインする
(global-set-key (kbd "C-c /") 'comment-or-uncomment-region)
;; バッファの再読み込みをC-M-rで実行する
(defun revert-buffer-no-confirm (&optional force-reverting)
(interactive "P")
(if (or force-reverting (not (buffer-modified-p)))
(revert-buffer :ignore-auto :noconfirm)
(error "The buffer has been modified")))
(global-set-key (kbd "C-M-r") 'revert-buffer-no-confirm)
;; ディレクトリバッファを全て削除
(defun kill-dired-buffers ()
(interactive)
(mapc (lambda (buffer)
(when (eq 'dired-mode (buffer-local-value 'major-mode buffer))
(kill-buffer buffer)))
(buffer-list)))
(global-set-key (kbd "C-c d d") 'kill-dired-buffers)
;; カーソルの下にある単語を全体を選択
(defun mark-whole-word (&optional arg allow-extend)
"Like `mark-word', but selects whole words and skips over whitespace.
If you use a negative prefix arg then select words backward.
Otherwise select them forward.
If cursor starts in the middle of word then select that whole word.
If there is whitespace between the initial cursor position and the
first word (in the selection direction), it is skipped (not selected).
If the command is repeated or the mark is active, select the next NUM
words, where NUM is the numeric prefix argument. (Negative NUM
selects backward.)"
(interactive "P\\np")
(let ((num (prefix-numeric-value arg)))
(unless (eq last-command this-command)
(if (natnump num)
(skip-syntax-forward "\\\\s-")
(skip-syntax-backward "\\\\s-")))
(unless (or (eq last-command this-command)
(if (natnump num)
(looking-at "\\\\b")
(looking-back "\\\\b")))
(if (natnump num)
(left-word)
(right-word)))
(mark-word arg allow-extend)))
(global-set-key (kbd "C-c @") 'mark-whole-word)
;; カーソルを置いてある単語をコピーする
(defun copy-word (&optional arg)
"Copy words at point into kill-ring"
(interactive "P")
(defun get-point (symbol &optional arg)
"get the point"
(funcall symbol arg)
(point))
(defun copy-thing (begin-of-thing end-of-thing &optional arg)
"Copy thing between beg & end into kill ring."
(save-excursion
(let ((beg (get-point begin-of-thing 1))
(end (get-point end-of-thing arg)))
(copy-region-as-kill beg end))))
(copy-thing 'backward-word 'forward-word arg))
(global-set-key (kbd "C-c w") 'copy-word)
;; 一行を丸ごとコピー
(defun copy-whole-line (&optional arg)
"Copy current line."
(interactive "p")
(or arg (setq arg 1))
(if (and (> arg 0) (eobp) (save-excursion (forward-visible-line 0) (eobp)))
(signal 'end-of-buffer nil))
(if (and (< arg 0) (bobp) (save-excursion (end-of-visible-line) (bobp)))
(signal 'beginning-of-buffer nil))
(unless (eq last-command 'copy-region-as-kill)
(kill-new "")
(setq last-command 'copy-region-as-kill))
(cond ((zerop arg)
(save-excursion
(copy-region-as-kill (point) (progn (forward-visible-line 0) (point)))
(copy-region-as-kill (point) (progn (end-of-visible-line) (point)))))
((< arg 0)
(save-excursion
(copy-region-as-kill (point) (progn (end-of-visible-line) (point)))
(copy-region-as-kill (point)
(progn (forward-visible-line (1+ arg))
(unless (bobp) (backward-char))
(point)))))
(t
(save-excursion
(copy-region-as-kill (point) (progn (forward-visible-line 0) (point)))
(copy-region-as-kill (point)
(progn (forward-visible-line arg) (point))))))
(message (substring (car kill-ring-yank-pointer) 0 -1)))
(global-set-key (kbd "C-c l") 'copy-whole-line)
Ted
大学でコンセンサスアルゴリズムを研究。卒業後ベンチャー企業に入社してフルスタックでWebサービスを開発。現在は大手IT企業に転職し、プログラミングを行っている。AIにプログラマーの仕事を奪って欲しいと願っている。