読者です 読者をやめる 読者になる 読者になる

ruby-modeの C-M-a, C-M-eの挙動

emacs ruby

MELPAで取得できる ruby-modeの ruby-beginning-of-defun(C-M-aに bind)は
moduleの中で定義される classや関数の定義には移動してくれません。


定義は以下のようになっています。

(defun-region-command ruby-beginning-of-defun (&optional arg)
  "Move backward to next beginning-of-defun.
With argument, do this that many times.
Returns t unless search stops due to end of buffer."
  (interactive "p")
  (and (re-search-backward (concat "^\\(" ruby-block-beg-re "\\)\\_>")
                           nil 'move (or arg 1))
       (progn (beginning-of-line) t)))

大事なのは ruby-block-beg-reなんですが、これは以下のようになっています。

(defconst ruby-block-beg-keywords
  '("class" "module" "def" "if" "unless" "case" "while" "until" "for" "begin" "do")
  "Keywords at the beginning of blocks.")

(defconst ruby-block-beg-re
  (regexp-opt ruby-block-beg-keywords)
  "Regexp to match the beginning of blocks.")


行頭でスペースなしで defとか classとかある場合にしか移動できません。
moduleの中だろうが関数、class単位で移動して欲しいということで、
関数を作成し、独自に割当てました。

(defun my/ruby-beginning-of-defun (&optional arg)
  (interactive "p")
  (and (re-search-backward (concat "^\\s-+\\(" ruby-block-beg-re "\\)\\_>")
                           nil 'move)
       (progn (back-to-indentation) t)))

(defun my/ruby-end-of-defun (&optional arg)
  (interactive "p")
  (and (re-search-forward (concat "^\\s-+\\(" ruby-block-end-re "\\)\\($\\|\\b[^_]\\)")
                          nil 'move (or arg 1))
       (progn (beginning-of-line) t))
  (forward-line 1)
  (back-to-indentation))

(define-key ruby-mode-map (kbd "C-M-a") 'my/ruby-beginning-of-defun)
(define-key ruby-mode-map (kbd "C-M-e") 'my/ruby-end-of-defun)

ほとんど同じですが、先頭にスペースがある defとか classでも移動するように
しました。これで期待通りです。