emacs のテキストモードで Shift+Tab を実現する
秀丸のような Shift+Tab のバックタブ(逆インデント)を emacs で実現してみた。
タブ位置の調整
emacs ではインデントの考え方が特殊で、テキストモードで (setq tab-width 4) としても効果がない。tab-width に従うのは C 言語モードの Tab キーに割り当てられている c-indent-line-or-region で、テキストモードの Tab キーに割り当てられている tab-to-tab-stop は tab-stop-list というインデント位置のリストに従う。例として幅 4 のソフトタブの設定を以下に示す。
(add-hook 'text-mode-hook '(lambda() (define-key text-mode-map "\C-i" 'tab-to-tab-stop) (define-key text-mode-map [backtab] 'backtab) (setq tab-stop-list '(4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120 124 128)) (setq indent-tabs-mode nil)))
バックタブ
超汚くて恐縮だが、以下のように (backtab) を実装した。
(defun backtab() "Do reverse indentation" (interactive) (back-to-indentation) (delete-backward-char (if (< (current-column) (car tab-stop-list)) 0 (- (current-column) (car (let ((value (list 0))) (dolist (element tab-stop-list value) (setq value (if (< element (current-column)) (cons element value) value)))))))))
追記(リージョンの対応)
やっつけ実装ですが、複数行まとめてタブを入れたり、タブを抜いたりできます。
(defun backtab-line-or-region () (interactive) (if mark-active (save-excursion (setq count (count-lines (region-beginning) (region-end))) (goto-char (region-beginning)) (while (> count 0) (backtab) (forward-line) (setq count (1- count))) (setq deactivate-mark nil)) (backtab))) (defun tab-to-tab-stop-line-or-region () (interactive) (if mark-active (save-excursion (setq count (count-lines (region-beginning) (region-end))) (goto-char (region-beginning)) (while (> count 0) (tab-to-tab-stop) (forward-line) (setq count (1- count))) (setq deactivate-mark nil)) (tab-to-tab-stop)))