Skip to content
This repository
tree: 04b321f50e
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 117 lines (94 sloc) 3.949 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
;;; ri.el --- Ruby Documentation Lookup

;; Copyright (C) 2008 Phil Hagelberg

;; Author: Phil Hagelberg <technomancy@gmail.com>
;; Version: 0.3
;; Keywords: tools, documentation
;; Created: 2008-09-19
;; URL: http://www.emacswiki.org/cgi-bin/wiki/RiEl
;; EmacsWiki: RiEl

;; This file is NOT part of GNU Emacs.

;;; License:

;; This program 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 3 of the
;; License, or (at your option) any later version.
;;
;; This program 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.

;;; Commentary:

;; ri.el provides an Emacs frontend to Ruby's `ri' documentation
;; tool. It offers lookup and completion.

;; This version will load all completion targets the first time it's
;; invoked. This can be a significant startup time, but it will not
;; have to look up anything after that point. It also has no external
;; dependencies except for having `ri' on your path. If RDoc 2.x is
;; not installed, it will fall back to ri 1.x.

;;; TODO:

;; * Replace Const.method with Const::method on the fly
;; * Hyperlinked ri-follow command
;; * Font Lock
;; * Flex matching?

;;; Code:

(require 'thingatpt)

;; Borrow this functionality from ido.
(unless (functionp 'ido-find-common-substring)
  (require 'ido))

(defvar ri-mode-hook nil
  "Hooks to run when invoking ri-mode.")

(defvar ri-names nil
  "All RI completion targets.")

;;;###autoload
(defun ri (&optional ri-documented)
  "Look up Ruby documentation."
  (interactive)
  (setq ri-documented (or ri-documented (ri-completing-read)))
  (let ((ri-buffer-name (format "*ri %s*" ri-documented)))
    (if (get-buffer ri-buffer-name)
        (switch-to-buffer ri-buffer-name)
      (let ((ri-buffer (get-buffer-create ri-buffer-name)))
        (display-buffer ri-buffer)
        (with-current-buffer ri-buffer
          (erase-buffer)
          (insert (shell-command-to-string (format "ri %s"
                                                   ri-documented)))
          (goto-char (point-min))
          (ri-mode))))))

(defun ri-mode ()
  "Mode for viewing Ruby documentation."
  (buffer-disable-undo)
  (kill-all-local-variables)
  (local-set-key (kbd "q") 'quit-window)
  (local-set-key (kbd "RET") 'ri-follow)
  (setq mode-name "ri")
  (setq major-mode 'ri-mode)
  (setq buffer-read-only t)
  (run-hooks 'ri-mode-hook))

;;; Completion

(defun ri-completing-read ()
  "Read the name of a Ruby class, module, or method to look up."
  (setq ri-names (or ri-names (ri-names)))
  (completing-read "RI: " ri-names nil nil (ri-symbol-at-point)))

(defun ri-names ()
  "One-liner to make RI spit out every class, module, and method name."
  (let ((ri-output (shell-command-to-string "ruby -rubygems -e \"require 'rdoc/ri/reader'; require 'rdoc/ri/cache'; require 'rdoc/ri/paths'; puts RDoc::RI::Reader.new(RDoc::RI::Cache.new(RDoc::RI::Paths.path(true, true, true, true))).all_names.join(\\\"\n\\\")\"")))
    (split-string (if (string-match "no such file to load" ri-output)
                      ;; Fall back to ri 1.x
                      (shell-command-to-string "ri -l")
                    ri-output))))

(defun ri-symbol-at-point ()
  ;; TODO: make this smart about class/module at point
  (let ((ri-symbol (symbol-at-point)))
    (if (and ri-symbol (member ri-symbol ri-names))
        (symbol-name ri-symbol)
      "")))

(defun ri-query (string)
  "Passes the `command' to the `ri' subprocess."
  (with-current-buffer (process-buffer (ri-get-process))
    (erase-buffer)
    (process-send-string (ri-get-process) (concat string "\n"))
    (accept-process-output (ri-get-process) 3 0 t)
    (buffer-string)))

(provide 'ri)
;;; ri.el ends here
Something went wrong with that request. Please try again.