ruby-block.el更新

ruby-modeで, endに対応する行をミニバッファへハイライトするマイナーモード.
elispの勉強のいっかんで作成.
前のエントリは, ここここ.
変更点は, 2つ.

  • マッチした行自体をdabbrev-highlightを参考にハイライト(強調表示)できるようにした.
  • 正規表現をちょっとだけ修正.

endの対応を見つける機構には, まだまだ問題が・・・(^^;)



行の強調表示は, デフォでは, ウザイかなってことでオフにしてある.
.emacsにコレ↓書けばオンになる.

(setq ruby-show-block-highlight-toggle t)

書かなくても, M-x ruby-show-block-highlight-toggle でもオン/オフを切り替えられる.


ソースは, こんな感じ.

;;; ruby-block.el --- highlight matching block

;; Copyright (C) 2007  khiker

;; Author: khiker <khiker.mail+memo@gmail.com>
;; Keywords: languages, faces

;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

;;; Commentary:

;; 2007-1-17(Wed) :
;; - マッチした行を dabbrev-highlight.el(http://www.namazu.org/~tsuchiya/elisp/) を参考にハイライトするように変更した.
;;   ハイライトするには, .emacsに以下を記述
;;   (setq ruby-show-block-highlight-toggle t)
;; - 正規表現をほんの少し修正
;;   def test
;;      define ...
;;   end
;;   というものがあったとき, defineにマッチするようになっていたのを修正.

;;--------------------------------------------------------------------------------
;; [やりたいこと]
;;--------------------------------------------------------------------------------
;;
;; - endの対応を見つける機構の修正.
;;   例えば, ヒアドキュメントのなかにコードがあったりすると平気で誤認識してくれる.
;;   このような, 誤認識するケース潰し.
;;

;;--------------------------------------------------------------------------------
;; [使用法]
;;--------------------------------------------------------------------------------
;;
;; .emacsへ以下を記述する
;;
;; (require 'ruby-block)
;; (ruby-show-block-mode t)
;;
;; (ruby-show-block-mode t)を記述しない場合は, M-x ruby-show-block-modeで有効となる.
;; また, マッチした行をハイライトするようにできる(デフォルトでは, オフ).
;; 同様に, .emacsへ以下を記述することでオンとなる.
;;
;; (setq ruby-show-block-highlight-toggle t)
;;
;; これは, 関数ruby-show-block-highlight-toggleを利用してもオン/オフを切り替えられる.
;;
;;--------------------------------------------------------------------------------

;;; Code:

(defvar ruby-show-block-idle-delay 0.50 "")

(defvar ruby-show-block-keyword-list
  (list "end" "for" "while" "until" "if" "class" "module" "case" "unless" "def" "begin" "do")
  "ハイライト対象となるキーワード.")

(defvar ruby-show-block-keyword-regex
  "^[ \t]*\\(\\(end\\|for\\|while\\|until\\|if\\|class\\|module\\|case\\|unless\\|def\\|begin\\)\\|[^#\n]*[) \t]\\(do\\)\\)[ \n\t]"
;  "^[ \t]*\\(\\(end\\|for\\|while\\|until\\|if\\|class\\|module\\|case\\|unless\\|def\\|begin\\)\\|[^#\n]*[) \t]\\(do\\)\\)"
;  "^[ \t]*\\(end\\|for\\|while\\|until\\|if\\|class\\|module\\|case\\|unless\\|def\\|begin\\|do\\)"
  "対応を探す際に利用する正規表現.")

(defvar ruby-show-block-idle-timer nil "")

;; モード変数
(defvar ruby-show-block-mode nil)
;(make-variable-buffer-local 'ruby-show-block)

;; ハイライト
(defvar ruby-show-block-highlight-face   'highlight "")
(defvar ruby-show-block-highlight-overlay nil       "")
;; ハイライトするかどうか
;; うーんこの変数なしでもっと簡単にできる気がする・・・.
(defvar ruby-show-block-highlight-toggle nil "")

(defun ruby-show-block-mode (&optional arg)
  "Rubyでendに対応するキーワードのある行の行番号とその行全体をミニバッファ上に表示するマイナーモード."
  (interactive "P")
  ;; モード変数の設定
  (cond
   ((< (prefix-numeric-value arg) 0)
    (setq ruby-show-block-mode nil)
    )
   (arg
    (setq ruby-show-block-mode t))
   (t
    (setq ruby-show-block-mode (not ruby-show-block-mode))
    )
   )
  ;; タイマーのスタート
  (if ruby-show-block-mode
      (progn
        (ruby-show-block-start-timer)
        )
    (ruby-show-block-stop-timer))
  )

(defun ruby-show-block-start-timer ()
  "ruby-show-block-idle-delay秒毎に, カーソル行のendに対応する行を表示するタイマーをスタートする."
  (when ruby-show-block-idle-timer
    (cancel-timer ruby-show-block-idle-timer))
  (setq ruby-show-block-idle-timer
        (run-with-idle-timer ruby-show-block-idle-delay t 'ruby-show-block-hook)))

(defun ruby-show-block-stop-timer ()
  "タイマーを停止する."
  (when ruby-show-block-idle-timer
    (cancel-timer ruby-show-block-idle-timer)
    (setq ruby-show-block-idle-timer nil)))

(defun ruby-show-block-hook ()
  "major-modeがruby-modeのときだけ実行するようにする."
  (when (eq major-mode 'ruby-mode)
    (condition-case err
        (ruby-show-block-function)
      (error
       (setq ruby-show-block-mode nil)
       (message "Error: %S; ruby-show-block-mode now disabled." err)))))

;; 実際に処理をする関数.
(defun ruby-show-block-function ()
  (let ((current
         (car (member (current-word) ruby-show-block-keyword-list)))
        )
    (cond
     ;; キーワードでは無かった場合.
     ((null current)
      '())
     ;; キーワードが「end」だった場合.
     ((string= "end" current)
      (let (wordpoint line-begin line-end line-string line-num)
        (setf wordpoint
              (save-excursion
                ;; endに対応するキーワードのポイントを返す.
                (do ((count 1)          ; doの返戻値.
                     (check 1))         ; 1かnilか. 終了条件判定.
                    ((null check) count)
                  ;; 次のような場合において, 「endのうしろ」(^)の位置にカーソルがあった場合,
                  ;;  while
                  ;;   ... ... ...
                  ;;  end
                  ;;     ^
                  ;; 検索において, endを含めてしまうことを抑止するために, ポイントを行頭に移動させる.
                  (beginning-of-line)
                  (if (null (re-search-backward ruby-show-block-keyword-regex (point-min) t 1))
                      ;; バッファの先頭に到達してしまった.
                      (progn
                        (setf count -1)  ; 返戻値を異常終了を示す値へ.
                        (setf check nil) ; 繰り返しを終了へ.
                        )
                    (if (string= (match-string 1) "end")
                        ;; マッチしたものが「end」.
                        (setf count (1+ count))
                      ;; マッチしたのものが「end」以外のキーワード.
                      (setf count (1- count))
                      ))
                  ;; その結果, countが0ならば, 終了へ.
                  (if (= count 0)
                      (progn
                        (setf count (match-beginning 1))
                        (setf check nil) ;繰り返しを終了へ.
                        ))
                  ))
              )
        ;; ポイントのある行全体を取得し, ミニバッファへ表示する.
        (if (> wordpoint 0)
            (save-excursion
              (goto-char wordpoint)
              (beginning-of-line)
              (setf line-begin (point))
              (end-of-line)
              (setf line-end (point))
              (message "%d: %s" (line-number-at-pos) (buffer-substring line-begin line-end))
              ;; ruby-show-block-highlight-toggleがtならば, ハイライトする
              (if ruby-show-block-highlight-toggle
                  (progn
                    ;; 対象となった行をハイライト.
                    (if ruby-show-block-highlight-overlay
                        (move-overlay  ruby-show-block-highlight-overlay line-begin line-end)
                      (setq ruby-show-block-highlight-overlay (make-overlay line-begin line-end)))
                    (overlay-put ruby-show-block-highlight-overlay 'face ruby-show-block-highlight-face)
                    (add-hook 'pre-command-hook 'ruby-show-block-highlight-done))
                )
              ))
        ))
     ;; 「end」以外のキーワードだった場合.
     (t
      '()
      ))
    )
  )

;; ハイライトした後, ハイライトした行の色を元に戻す動作.
(defun ruby-show-block-highlight-done ()
  (remove-hook 'pre-command-hook 'ruby-show-block-highlight-done)
  (if ruby-show-block-highlight-overlay
      (delete-overlay ruby-show-block-highlight-overlay)))

(defun ruby-show-block-highlight-toggle ()
  "ruby-show-block-modeのハイライトのオン/オフ切り替え"
  (interactive)
  (if ruby-show-block-highlight-toggle
      (setq ruby-show-block-highlight-toggle nil)
    (setq ruby-show-block-highlight-toggle t)))

(provide 'ruby-block)
;;; ruby-block.el ends here

にょろーん.