隣接するバッファに瞬時に移動する
やばい。。これは便利だな。。
http://www-tsujii.is.s.u-tokyo.ac.jp/~yoshinag/tips/elisp_tips.html#buffer
;;; 隣接するバッファに C-,(降順) C-.(昇順) で瞬時に移動 ;; http://www-tsujii.is.s.u-tokyo.ac.jp/~yoshinag/tips/elisp_tips.html#buffer (defvar my-ignore-blst ; 移動の際に無視するバッファのリスト '("*Help*" "*Mew completions*" "*Completions*" "*Shell Command Output*" "*Buffer List*")) (defvar my-vblst nil) ; 移動開始時の buffer list を保存 (defvar my-bslen 15) ; buffer list 中の buffer name の最長値 (defvar my-blst-display-time 2) ; buffer list の表示時間 (defface my-cbface ; buffer list 中の current buffer を示す face '((t (:foreground "red" :underline t))) nil) (defvar my-op-mode) ; 自動設定される変数 (1 前移動 2 次移動 3 ID移動 4 フィルタ) (defvar my-spliter-alist ; バッファ表示中のバッファ間のスプリッタ '((1 . " < ") (2 . " > ") (3 . " ") (4 . " / "))) (defvar my-prompt-alist ; バッファ表示中のプロンプト '((1 . "[<<-] ") (2 . "[->>] ") (3 . "") (4 . ""))) (defun my-visible-buffers (blst &optional reg) (if (eq blst nil) '() (let ((bufn (buffer-name (car blst)))) (if (or (= (aref bufn 0) ? ) ; ミニバッファと (not (string-match (or reg "") bufn)) ; reg を含まないバッファと (member bufn my-ignore-blst)) ; 無視するバッファには移動しない (my-visible-buffers (cdr blst) reg) (cons (car blst) (my-visible-buffers (cdr blst) reg)))))) (defun my-buf-id (buf) (format "%s) " (length (memq buf (reverse my-vblst))))) (defun my-show-buffer-list () (let* ((prompt (cdr (assq my-op-mode my-prompt-alist))) (spliter (cdr (assq my-op-mode my-spliter-alist))) (len (string-width prompt)) (str (mapconcat (lambda (buf) (let ((bs (copy-sequence (buffer-name buf)))) (if (> (string-width bs) my-bslen) ; 切り詰め (setq bs (concat (substring bs 0 (- my-bslen 2)) ".."))) (setq len (+ len (string-width (concat bs spliter)))) (when (eq buf (current-buffer)) ; 表示中のバッファは強調表示 (put-text-property 0 (length bs) 'face 'my-cbface bs)) (cond ((> len (frame-width)) ;; frame 幅で適宜改行 (setq len (+ (string-width (concat prompt bs spliter)))) (concat "\n" (make-string (string-width prompt) ? ) bs)) (t (concat (and (= my-op-mode 3) (my-buf-id buf)) bs))))) ; ID my-vblst spliter))) (cond ((<= my-op-mode 2) ; 単純移動 (let (message-log-max) (message "%s%s" prompt str)) (if (sit-for my-blst-display-time) (message nil))) ; 表示を消す ((= my-op-mode 3) ; バッファの ID を指定して移動 (let* ((id-str (read-string (concat str "\nSpecify Buffer ID: "))) (id (string-to-number id-str))) (if (and (>= id 1) (<= id (length my-vblst))) ;; 移動できる ID なら (switch-to-buffer (nth (1- id) my-vblst)) ;; 移動する ;; 空文字列をIDに指定して、さらにIDを指定しようとしていたら終了 (unless (and (eq my-op-mode 3) (string= id-str "")) ; (*) (my-show-buffer-list))))) ; さもなければ my-op-mode で再処理 ((= my-op-mode 4) ; バッファ名を正規表現でフィルタ (let* ((reg (read-string (concat str "\nBuffer-name regexp: ")))) ;; フィルタで絞込みをかけて移動候補のバッファを再設定 (setq my-vblst (or (my-visible-buffers my-vblst reg) my-vblst)) ;; 空文字列で絞込みしていなければ、更新された移動候補の先頭に移動 (when (not (string= reg "")) (switch-to-buffer (car my-vblst))) ;; 空文字列で絞込みして、さらに絞込みをしようとしていたら終了 (when (or (not (eq my-op-mode 4)) (not (string= reg ""))) ; (*) (my-show-buffer-list)))) ; さもなければ my-op-mode に従い再処理 ))) (defun my-operate-buffer (mode) (setq my-op-mode mode) ;; my-show-buffer-list 中の read-string を潰す↓の exit-minibuffer より先に ;; ↑で my-op-mode に mode を指定しておく (*) 時に有効 (when (window-minibuffer-p (selected-window)) (exit-minibuffer)) (unless (eq last-command 'my-operate-buffer) ; バッファリスト初期化 (setq my-vblst (my-visible-buffers (buffer-list)))) (when (<= my-op-mode 2) (let* ((blst (if (= my-op-mode 2) my-vblst (reverse my-vblst)))) (switch-to-buffer (or (cadr (memq (current-buffer) blst)) (car blst))))) (my-show-buffer-list) (setq this-command 'my-operate-buffer)) (defun my-sellect-visible-buffers () (interactive) (my-operate-buffer 3)) (defun my-filter-visible-buffers () (interactive) (my-operate-buffer 4)) (global-set-key [?\C-,] (lambda () (interactive) (my-operate-buffer 1))) (global-set-key [?\C-.] (lambda () (interactive) (my-operate-buffer 2))) (global-set-key [?\C-@] 'my-sellect-visible-buffers) (global-set-key [?\C-\;] 'my-filter-visible-buffers)