1 ;;;; ri-ruby.el emacs wrapper around ri
3 ;; Author: Kristof Bastiaensen <kristof@vleeuwen.org>
6 ;; Copyright (C) 2004,2006 Kristof Bastiaensen
8 ;; This program is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 2 of the License, or
11 ;; (at your option) any later version.
13 ;; This program is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program; if not, write to the Free Software
20 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 ;;----------------------------------------------------------------------
27 ;; add the following to your init.el, replacing the filenames with
28 ;; their correct locations:
30 ;; (setq ri-ruby-script "/home/kristof/.xemacs/ri-emacs.rb")
31 ;; (autoload 'ri "/home/kristof/.xemacs/ri-ruby.el" nil t)
33 ;; You may want to bind the ri command to a key.
34 ;; For example to bind it to F1 in ruby-mode:
35 ;; Method/class completion is also available.
37 ;; (add-hook 'ruby-mode-hook (lambda ()
38 ;; (local-set-key 'f1 'ri)
39 ;; (local-set-key "\M-\C-i" 'ri-ruby-complete-symbol)
40 ;; (local-set-key 'f4 'ri-ruby-show-args)
48 ;; M-Tab for completion
53 ;; * The first time you give the ri command on xemacs, it may give
54 ;; strange behaviour in XEmacs. This is probably due to a
55 ;; bug in the way XEmacs handles processes under linux.
57 ;; * It is reported that the ruby-script doesn't work with XEmacs under
58 ;; MS-Windows. This is probably a bug in processes in XEmacs.
63 ;; rubikitch (http://www.rubyist.net/~rubikitch/):
64 ;; fixed highlighting under Emacs
68 (defvar ri-ruby-program
"ruby"
69 "The ruby program name.")
71 (defvar ri-ruby-script
"/cygdrive/c/cygwin/usr/share/emacs/site-lisp/ri/ri-emacs.rb"
72 "the ruby script to communicate with")
74 (defvar ri-ruby-process nil
75 "The current ri process where emacs is interacting with")
77 (defvar ri-ruby-history nil
80 (defvar ri-ruby-process-buffer nil
)
82 (defun ri-ruby-get-process ()
83 (cond ((or (null ri-ruby-process
)
84 (not (equal (process-status ri-ruby-process
) 'run
)))
86 (start-process "ri-ruby-process"
88 ri-ruby-program ri-ruby-script
))
89 (process-kill-without-query ri-ruby-process
) ;kill when ending emacs
90 (ri-ruby-process-check-ready)))
93 (defun ri-ruby-process-filter-expr (proc str
)
94 (let ((ansi-color-context nil
))
96 (set-buffer ri-ruby-process-buffer
)
97 (goto-char (point-max))
98 (insert-string (ansi-color-filter-apply str
)))))
100 (defun ri-ruby-process-filter-lines (proc str
)
102 (set-buffer ri-ruby-process-buffer
)
103 (goto-char (point-max))
104 (insert-string (ansi-color-apply str
))))
106 (defvar ri-startup-timeout
60)
107 (defun ri-ruby-process-check-ready ()
108 (let ((ri-ruby-process-buffer (generate-new-buffer " ri-ruby-output")))
111 (set-buffer ri-ruby-process-buffer
)
112 (set-process-filter ri-ruby-process
'ri-ruby-process-filter-expr
)
113 (ri-ruby-check-process ri-ruby-process-buffer
)
114 (accept-process-output ri-ruby-process ri-startup-timeout
)
115 (goto-char (point-min))
116 (cond ((not (looking-at "READY.*\n"))
117 (delete-process ri-ruby-process
)
118 (error "Couldn't start ruby script"))))
119 (set-process-filter ri-ruby-process t
)
120 (kill-buffer ri-ruby-process-buffer
))))
122 (defun ri-ruby-check-process (buffer)
123 (or (equal (process-status ri-ruby-process
) 'run
)
124 (let ((output (with-current-buffer buffer
125 (buffer-substring (point-min)
127 (error "Process is not running.\n" output
))))
129 (defun ri-ruby-process-get-expr (cmd param
)
130 (ri-ruby-get-process)
131 (let ((ri-ruby-process-buffer (generate-new-buffer " ri-ruby-output"))
132 (command (concat cmd
" " param
"\n")))
135 (set-buffer ri-ruby-process-buffer
)
136 (set-process-filter ri-ruby-process
'ri-ruby-process-filter-expr
)
137 (process-send-string ri-ruby-process command
)
138 (ri-ruby-check-process ri-ruby-process-buffer
)
139 (while (progn (goto-char (point-min))
140 (not (looking-at ".*\n"))) ;we didn't read a whole line
141 (ri-ruby-check-process ri-ruby-process-buffer
)
142 (accept-process-output ri-ruby-process
))
143 (goto-char (point-min))
144 (read (buffer-substring (point)
146 (set-process-filter ri-ruby-process t
)
147 (kill-buffer ri-ruby-process-buffer
))))
149 (defun ri-ruby-process-get-lines (cmd param
)
150 (ri-ruby-get-process)
151 (if (equal param
"") nil
152 (let ((ri-ruby-process-buffer (generate-new-buffer " ri-ruby-output"))
153 (command (concat cmd
" " param
"\n")))
156 (set-buffer ri-ruby-process-buffer
)
157 (set-process-filter ri-ruby-process
'ri-ruby-process-filter-lines
)
158 (process-send-string ri-ruby-process command
)
159 (ri-ruby-check-process ri-ruby-process-buffer
)
160 (while (progn (goto-char (point-max))
161 (goto-char (point-at-bol 0))
162 (not (looking-at "RI_EMACS_END_OF_INFO$")))
163 (ri-ruby-check-process ri-ruby-process-buffer
)
164 (accept-process-output ri-ruby-process
))
167 (buffer-substring (point-min) (point))))
168 (set-process-filter ri-ruby-process t
)
169 (kill-buffer ri-ruby-process-buffer
)))))
171 (defun ri-ruby-complete-method (str pred type
)
172 (let* ((cmd (cdr (assoc type
'((nil .
"TRY_COMPLETION")
174 (lambda .
"LAMBDA")))))
175 (result (ri-ruby-process-get-expr cmd str
)))
176 (if (and pred
(listp result
))
177 (setq result
(mapcar pred result
)))
180 (defun ri-ruby-read-keyw ()
181 (let* ((curr (current-word))
182 (match (ri-ruby-process-get-expr "LAMBDA" curr
))
183 (default (if match curr nil
))
184 (prompt (concat "method- or classname"
185 (if default
(concat " (default " default
")") "")
187 (keyw (completing-read prompt
'ri-ruby-complete-method
188 nil t
"" 'ri-ruby-history default
))
189 (classes (ri-ruby-process-get-expr "CLASS_LIST" keyw
))
190 (class (cond ((null classes
) nil
)
191 ((null (cdr classes
)) (caar classes
))
192 (t (completing-read (concat prompt keyw
197 (defun ri-ruby-method-with-class (meth classes
)
200 (concat meth
" [" (mapconcat 'car classes
", ") "]")))
202 (defun ri-ruby-complete-symbol ()
203 "Completion on ruby-mode."
205 (let* ((curr (current-word))
207 (classes (ri-ruby-process-get-expr "CLASS_LIST_WITH_FLAG" keyw
))
208 (completion (try-completion curr
'ri-ruby-complete-method nil
)))
209 (cond ((eq completion t
)
210 (message "%s" (ri-ruby-method-with-class curr classes
)))
212 (message "Can't find completion for \"%s\"" curr
)
214 ((not (string= curr completion
))
215 (delete-region (save-excursion (search-backward curr
) (point))
218 (setq classes
(ri-ruby-process-get-expr "CLASS_LIST_WITH_FLAG" completion
))
219 (message "%s" (ri-ruby-method-with-class completion classes
)))
221 (message "Making completion list...")
222 (with-output-to-temp-buffer "*Completions*"
223 (display-completion-list
224 (all-completions curr
'ri-ruby-complete-method
)))
225 (message "%s" (ri-ruby-method-with-class completion classes
))))))
227 (defun test-ri-ruby-complete-symbol ()
228 "Test of ri-ruby-complete-symbol."
230 (pop-to-buffer "*ruby completion test*")
233 (goto-char (point-min))
238 # (kill-process \"ri-ruby-process\")
241 (defun ri-ruby-show-args ()
243 (let* ((method (current-word))
244 (info (ri-ruby-process-get-lines "DISPLAY_ARGS" method
)))
246 (message "%s" info
))))
248 (defun ri (keyw &optional class
)
250 (interactive (ri-ruby-read-keyw))
251 (let* ((method (if class
(concat class
"#" keyw
) keyw
))
252 (info (ri-ruby-process-get-lines "DISPLAY_INFO" method
)))
253 (cond (info (ri-ruby-show-info method info
))
255 (t (setq method
(concat class
"::" keyw
))
256 (setq info
(ri-ruby-process-get-lines "DISPLAY_INFO" method
))
257 (if info
(ri-ruby-show-info method info
))))))
259 (cond ((fboundp 'with-displaying-help-buffer
) ; for XEmacs
260 (defun ri-ruby-show-info (method info
)
261 (with-displaying-help-buffer
262 (lambda () (princ info
))
263 (format "ri `%s'" method
))))
265 (defun ri-ruby-show-info (method info
)
266 (let ((b (get-buffer-create (format "ri `%s'" method
))))
268 (with-current-buffer b
269 (buffer-disable-undo)