| 1 |
;;; rails-ruby.el --- provide features for ruby-mode |
| 2 |
|
| 3 |
;; Copyright (C) 2006 Dmitry Galinsky <dima dot exe at gmail dot com> |
| 4 |
|
| 5 |
;; Authors: Dmitry Galinsky <dima dot exe at gmail dot com> |
| 6 |
|
| 7 |
;; Keywords: ruby rails languages oop |
| 8 |
;; $URL$ |
| 9 |
;; $Id$ |
| 10 |
|
| 11 |
;;; License |
| 12 |
|
| 13 |
;; This program is free software; you can redistribute it and/or |
| 14 |
;; modify it under the terms of the GNU General Public License |
| 15 |
;; as published by the Free Software Foundation; either version 2 |
| 16 |
;; of the License, or (at your option) any later version. |
| 17 |
|
| 18 |
;; This program is distributed in the hope that it will be useful, |
| 19 |
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 20 |
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 21 |
;; GNU General Public License for more details. |
| 22 |
|
| 23 |
;; You should have received a copy of the GNU General Public License |
| 24 |
;; along with this program; if not, write to the Free Software |
| 25 |
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 26 |
|
| 27 |
;;; Code: |
| 28 |
|
| 29 |
;; setup align for ruby-mode |
| 30 |
(require 'align) |
| 31 |
|
| 32 |
(defconst align-ruby-modes '(ruby-mode) |
| 33 |
"align-perl-modes is a variable defined in `align.el'.") |
| 34 |
|
| 35 |
(defconst ruby-align-rules-list |
| 36 |
'((ruby-comma-delimiter |
| 37 |
(regexp . ",\\(\\s-*\\)[^/ \t\n]") |
| 38 |
(modes . align-ruby-modes) |
| 39 |
(repeat . t)) |
| 40 |
(ruby-string-after-func |
| 41 |
(regexp . "^\\s-*[a-zA-Z0-9.:?_]+\\(\\s-+\\)['\"]\\w+['\"]") |
| 42 |
(modes . align-ruby-modes) |
| 43 |
(repeat . t)) |
| 44 |
(ruby-symbol-after-func |
| 45 |
(regexp . "^\\s-*[a-zA-Z0-9.:?_]+\\(\\s-+\\):\\w+") |
| 46 |
(modes . align-ruby-modes))) |
| 47 |
"Alignment rules specific to the ruby mode. |
| 48 |
See the variable `align-rules-list' for more details.") |
| 49 |
|
| 50 |
(add-to-list 'align-perl-modes 'ruby-mode) |
| 51 |
(add-to-list 'align-dq-string-modes 'ruby-mode) |
| 52 |
(add-to-list 'align-sq-string-modes 'ruby-mode) |
| 53 |
(add-to-list 'align-open-comment-modes 'ruby-mode) |
| 54 |
(dolist (it ruby-align-rules-list) |
| 55 |
(add-to-list 'align-rules-list it)) |
| 56 |
|
| 57 |
;; hideshow ruby support |
| 58 |
|
| 59 |
(defun display-code-line-counts (ov) |
| 60 |
(when (eq 'code (overlay-get ov 'hs)) |
| 61 |
(overlay-put ov 'face 'font-lock-comment-face) |
| 62 |
(overlay-put ov 'display |
| 63 |
(format " ... %d lines" |
| 64 |
(count-lines (overlay-start ov) |
| 65 |
(overlay-end ov)))))) |
| 66 |
|
| 67 |
(eval-after-load "hideshow" |
| 68 |
(unless 'hs-set-up-overlay |
| 69 |
(setq hs-set-up-overlay 'display-code-line-counts))) |
| 70 |
|
| 71 |
(add-hook 'hs-minor-mode-hook |
| 72 |
(lambda () |
| 73 |
(unless hs-set-up-overlay |
| 74 |
(setq hs-set-up-overlay 'display-code-line-counts)))) |
| 75 |
|
| 76 |
(defun ruby-hs-minor-mode (&optional arg) |
| 77 |
(interactive) |
| 78 |
(require 'hideshow) |
| 79 |
(unless (assoc 'ruby-mode hs-special-modes-alist) |
| 80 |
(setq |
| 81 |
hs-special-modes-alist |
| 82 |
(cons (list 'ruby-mode |
| 83 |
"\\(def\\|do\\)" |
| 84 |
"end" |
| 85 |
"#" |
| 86 |
(lambda (&rest args) (ruby-end-of-block)) |
| 87 |
;(lambda (&rest args) (ruby-beginning-of-defun)) |
| 88 |
) |
| 89 |
hs-special-modes-alist))) |
| 90 |
(hs-minor-mode arg)) |
| 91 |
|
| 92 |
;; flymake ruby support |
| 93 |
|
| 94 |
(require 'flymake nil t) |
| 95 |
|
| 96 |
(defconst flymake-allowed-ruby-file-name-masks |
| 97 |
'(("\\.rb\\'" flymake-ruby-init) |
| 98 |
("\\.rxml\\'" flymake-ruby-init) |
| 99 |
("\\.builder\\'" flymake-ruby-init) |
| 100 |
("\\.rjs\\'" flymake-ruby-init)) |
| 101 |
"Filename extensions that switch on flymake-ruby mode syntax checks.") |
| 102 |
|
| 103 |
(defconst flymake-ruby-error-line-pattern-regexp |
| 104 |
'("^\\([^:]+\\):\\([0-9]+\\): *\\([\n]+\\)" 1 2 nil 3) |
| 105 |
"Regexp matching ruby error messages.") |
| 106 |
|
| 107 |
(defun flymake-ruby-init () |
| 108 |
(condition-case er |
| 109 |
(let* ((temp-file (flymake-init-create-temp-buffer-copy |
| 110 |
'flymake-create-temp-inplace)) |
| 111 |
(local-file (file-relative-name |
| 112 |
temp-file |
| 113 |
(file-name-directory buffer-file-name)))) |
| 114 |
(list rails-ruby-command (list "-c" local-file))) |
| 115 |
('error ()))) |
| 116 |
|
| 117 |
(defun flymake-ruby-load () |
| 118 |
(when (and (buffer-file-name) |
| 119 |
(not (file-remote-p (buffer-file-name))) ; FIX: cabo |
| 120 |
(string-match |
| 121 |
(format "\\(%s\\)" |
| 122 |
(string-join |
| 123 |
"\\|" |
| 124 |
(mapcar 'car flymake-allowed-ruby-file-name-masks))) |
| 125 |
(buffer-file-name))) |
| 126 |
(setq flymake-allowed-file-name-masks |
| 127 |
(append flymake-allowed-file-name-masks flymake-allowed-ruby-file-name-masks)) |
| 128 |
(setq flymake-err-line-patterns |
| 129 |
(cons flymake-ruby-error-line-pattern-regexp flymake-err-line-patterns)) |
| 130 |
(flymake-mode t) |
| 131 |
(local-set-key (rails-key "d") 'flymake-display-err-menu-for-current-line))) |
| 132 |
|
| 133 |
(when (featurep 'flymake) |
| 134 |
(add-hook 'ruby-mode-hook 'flymake-ruby-load)) |
| 135 |
|
| 136 |
;; other stuff |
| 137 |
|
| 138 |
(defun ruby-newline-and-indent () |
| 139 |
(interactive) |
| 140 |
(newline) |
| 141 |
(ruby-indent-line)) |
| 142 |
|
| 143 |
(defun ruby-toggle-string<>simbol () |
| 144 |
"Easy to switch between strings and symbols." |
| 145 |
(interactive) |
| 146 |
(let ((initial-pos (point))) |
| 147 |
(save-excursion |
| 148 |
(when (looking-at "[\"']") ;; skip beggining quote |
| 149 |
(goto-char (+ (point) 1)) |
| 150 |
(unless (looking-at "\\w") |
| 151 |
(goto-char (- (point) 1)))) |
| 152 |
(let* ((point (point)) |
| 153 |
(start (skip-syntax-backward "w")) |
| 154 |
(end (skip-syntax-forward "w")) |
| 155 |
(end (+ point start end)) |
| 156 |
(start (+ point start)) |
| 157 |
(start-quote (- start 1)) |
| 158 |
(end-quote (+ end 1)) |
| 159 |
(quoted-str (buffer-substring-no-properties start-quote end-quote)) |
| 160 |
(symbol-str (buffer-substring-no-properties start end))) |
| 161 |
(cond |
| 162 |
((or (string-match "^\"\\w+\"$" quoted-str) |
| 163 |
(string-match "^\'\\w+\'$" quoted-str)) |
| 164 |
(setq quoted-str (substring quoted-str 1 (- (length quoted-str) 1))) |
| 165 |
(kill-region start-quote end-quote) |
| 166 |
(goto-char start-quote) |
| 167 |
(insert (concat ":" quoted-str))) |
| 168 |
((string-match "^\:\\w+$" symbol-str) |
| 169 |
(setq symbol-str (substring symbol-str 1)) |
| 170 |
(kill-region start end) |
| 171 |
(goto-char start) |
| 172 |
(insert (format "'%s'" symbol-str)))))) |
| 173 |
(goto-char initial-pos))) |
| 174 |
|
| 175 |
(require 'inf-ruby) |
| 176 |
|
| 177 |
(defun run-ruby-in-buffer (buf script &rest params) |
| 178 |
"Run CMD as a ruby process in BUF if BUF does not exist." |
| 179 |
(message "run-ruby-in-buffer %s" params) |
| 180 |
(let ((abuf (concat "*" buf "*"))) |
| 181 |
(when (not (comint-check-proc abuf)) |
| 182 |
(set-buffer (apply #'make-comint buf rails-ruby-command nil script params))) |
| 183 |
(pop-to-buffer abuf) |
| 184 |
(when (fboundp 'inf-ruby-mode) |
| 185 |
(inf-ruby-mode) |
| 186 |
(when (< (rails-core:current-rails-major-version) 3) |
| 187 |
(make-local-variable 'inf-ruby-first-prompt-pattern) |
| 188 |
(make-local-variable 'inf-ruby-prompt-pattern) |
| 189 |
(setq inf-ruby-first-prompt-pattern "^>> " |
| 190 |
inf-ruby-prompt-pattern "^>> " |
| 191 |
inf-ruby-buffer (current-buffer)))))) |
| 192 |
|
| 193 |
(defun complete-ruby-method (prefix &optional maxnum) |
| 194 |
(if (capital-word-p prefix) |
| 195 |
(let* ((cmd "x = []; ObjectSpace.each_object(Class){|i| x << i.to_s}; x.map{|i| i.match(/^%s/) ? i.gsub(/^%s/, '') : nil }.compact.sort{|x,y| x.size <=> y.size}") |
| 196 |
(cmd (if maxnum (concat cmd (format "[0...%s]" maxnum)) cmd))) |
| 197 |
(el4r-ruby-eval (format cmd prefix prefix))) |
| 198 |
(save-excursion |
| 199 |
(goto-char (- (point) (+ 1 (length prefix)))) |
| 200 |
(when (and (looking-at "\\.") |
| 201 |
(capital-word-p (word-at-point)) |
| 202 |
(el4r-ruby-eval (format "::%s rescue nil" (word-at-point)))) |
| 203 |
(let* ((cmd "%s.public_methods.map{|i| i.match(/^%s/) ? i.gsub(/^%s/, '') : nil }.compact.sort{|x,y| x.size <=> y.size}") |
| 204 |
(cmd (if maxnum (concat cmd (format "[0...%s]" maxnum)) cmd))) |
| 205 |
(el4r-ruby-eval (format cmd (word-at-point) prefix prefix))))))) |
| 206 |
|
| 207 |
|
| 208 |
(provide 'rails-ruby) |