Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Tree: 7d44078057
Fetching contributors…

Cannot retrieve contributors at this time

346 lines (299 sloc) 12.3 KB
;;; rails-navigation.el --- emacs-rails navigation functions
;; Copyright (C) 2006 Dmitry Galinsky <dima dot exe at gmail dot com>
;; Authors: Dmitry Galinsky <dima dot exe at gmail dot com>,
;; Rezikov Peter <crazypit13 (at)>
;; Keywords: ruby rails languages oop
;; $URL$
;; $Id$
;;; 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 2
;; 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
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
(defun rails-nav:create-goto-menu (items title &optional append-to-menu)
(when append-to-menu
(dolist (l append-to-menu items)
(add-to-list 'items l t)))
(let ((selected
(when items
(list title (cons title items))))))
(if selected selected (message "No files found"))))
(defun rails-nav:goto-file-with-menu (dir title &optional ext no-inflector append-to-menu)
"Make a menu to choose files from and find-file it."
(let* (file
(ext (if ext ext "rb"))
(ext (concat "\\." ext "$"))
(dir (rails-core:file dir)))
(setq files (find-recursive-directory-relative-files dir "" ext))
(setq files (sort files 'string<))
(setq files (mapcar
(if no-inflector f (rails-core:class-by-file f))
(selected (rails-nav:create-goto-menu files title append-to-menu))
(if (symbolp selected)
(apply selected (list))
(rails-core:find-file-if-exist (concat dir selected))))))
(defun rails-nav:goto-file-with-menu-from-list (items title func &optional append-to-menu)
(selected (rails-nav:create-goto-menu (list->alist items) title append-to-menu))
(file (apply func (list selected)))
(rails-core:find-file-if-exist file))))
(defun rails-nav:goto-controllers ()
"Go to controllers."
(rails-core:controllers t)
"Go to controller.."
(defun rails-nav:goto-models ()
"Go to models."
"Go to model.."
(defun rails-nav:goto-functional-tests ()
"Go to functional tests."
"Go to functional test.."
(defun rails-nav:goto-unit-tests ()
"Go to functional tests."
"Go to unit test.."
(defun rails-nav:goto-observers ()
"Go to observers."
"Go to observer.."
(defun rails-nav:goto-mailers ()
"Go to mailers."
"Go to mailers.."
(defun rails-nav:goto-migrate ()
"Go to migrations."
"Go to migrate.."
(defun rails-nav:goto-helpers ()
"Go to helpers."
"Go to helper.."
(defun rails-nav:goto-plugins ()
"Go to plugins."
"Go to plugin.."
(lambda (plugin)
(concat "vendor/plugins/" plugin "/init.rb"))))
(defun rails-nav:goto-rspec-controllers ()
"Go to controller specs."
"Go to controller spec.."
(defun rails-nav:goto-rspec-lib ()
"Go to lib specs."
"Go to lib spec.."
(defun rails-nav:goto-rspec-models ()
"Go to model specs."
"Go to model spec.."
(defun rails-nav:goto-rspec-views ()
"Go to view specs."
"Go to view spec.."
(defun rails-nav:goto-rspec-fixtures ()
"Go to rspec fuxtures."
"Go to rspec fixtures.."
(defun rails-nav:create-new-layout (&optional name)
"Create a new layout."
(let ((name (or name (read-string "Layout name? "))))
(when name
(let* ((default-type (or rails-controller-layout:recent-template-type (car rails-templates-list)))
(type (completing-read (format "Create %s.[%s]? " name default-type)
rails-templates-list nil t default-type)))
(rails-core:find-file (rails-core:file (format "app/views/layouts/%s.%s" name type)))
(if (y-or-n-p "Insert initial template? ")
(insert rails-layout-template))))))
(defun rails-nav:goto-layouts ()
"Go to layouts."
(let ((items (list (rails-core:menu-separator)
(cons "Create new layout" 'rails-nav:create-new-layout))))
"Go to layout.."
(lambda (l)
(if (stringp l)
(rails-core:layout-file l)
(apply l (list))))
(defun rails-nav:goto-fixtures ()
"Go to fixtures."
"Go to fixture.."
(defun rails-nav:goto-stylesheets ()
"Go to stylesheets."
(rails-nav:goto-file-with-menu "public/stylesheets/" "Go to stylesheet.." "css" t))
(defun rails-nav:goto-javascripts ()
"Go to JavaScripts."
(rails-nav:goto-file-with-menu "public/javascripts/" "Go to stylesheet.." "js" t))
;;;;;;;;;; Goto file on current line ;;;;;;;;;;
(defmacro* def-goto-line (name (&rest conditions) &rest body)
"Go to the file specified by the current line. Parses the
current line for a series of patterns."
(let ((line (gensym))
(field (gensym))
(prefix (gensym)))
(defun ,name (,line ,prefix)
(block ,name
,@(loop for (sexpr . map) in conditions
`(let ((case-fold-search nil))
(when (string-match ,sexpr ,line)
(let ,(loop for var-acc in map collect
(if (listp var-acc)
`(,(first var-acc) (match-string ,(second var-acc) ,line))
(return-from ,name (progn ,@body)))))))))))
(defun rails-goto-file-on-current-line (prefix)
"Analyze a string (or ERb block) and open some file related with it.
For example, on a line with \"render :partial\" runing this
function will open the partial file. The function works with
\"layout 'name'\", \"render/redirect-to [:action => 'name',] [controller => 'n']\",
stylesheet_link_tag and other common
Rules for actions/controllers:
If you are in a controller, the cursor will be placed on the controller action.
If you in view, the view file related to the action will be opened.
Use prefix before the command to change this navigation direction."
(interactive "P")
(line (save-excursion
(if (rails-core:rhtml-buffer-p)
(loop for func in rails-on-current-line-gotos
until (when (funcall func line prefix) (return t))))
(message "Can't switch to some file from this line.")))))
(defvar rails-on-current-line-gotos
"Functions that will be called to analyze the line when
rails-goto-file-on-current-line is run.")
(def-goto-line rails-line-->stylesheet (("[ ]*stylesheet_link_tag[ ][\"']\\([^\"']*\\)[\"']"
(name 1)))
(format "Stylesheet \"%s\" does not exist do you whant to create it? " name)
(rails-core:stylesheet-name name)))
(def-goto-line rails-line-->partial (("\\([ ]*render\\|replace_html\\|insert_html\\).*:partial[ ]*=>[ ]*[\"']\\([^\"']*\\)[\"']"
(name 2)))
(format "Partial \"%s\" does not exist do you whant to create it? " name)
(rails-core:partial-name name)))
(def-goto-line rails-line-->action (("\\([ ]*render\\|replace_html\\|insert_html\\).*:action[ ]*=>[ ]*[\"'\:]\\([^\"']*\\)"
(name 2)))
(format "View \"%s\" does not exist do you whant to create it? " name)
(rails-core:view-name name)))
(def-goto-line rails-line-->layout (("^[ ]*layout[ ]*[\"']\\(.*\\)[\"']" (name 1)))
(let ((file-name (rails-core:layout-file name)))
(if (file-exists-p (rails-core:file file-name))
(rails-core:find-file file-name)
(rails-nav:create-new-layout name))))
(def-goto-line rails-line-->js (("^[ ]*javascript_include_tag[ ]*[\"']\\(.*\\)[\"']"
(name 1)))
(format "JavaScript file \"%s\" does not exist do you whant to create it? " name)
(rails-core:js-file name)))
(def-goto-line rails-line-->association-model (("^[ \t]*\\(has_one\\|belongs_to\\|has_many\\|has_and_belongs_to_many\\)[ \t].*:class_name[ \t]*=>[ \t]*[\"']\\([^\"']*\\)[\"']"
(name 2)))
(rails-core:find-file (rails-core:model-file name)))
(def-goto-line rails-line-->single-association-model (("^[ \t]*\\(has_one\\|belongs_to\\)[ \t]*:\\([a-z0-9_]*\\)" (name 2)))
(rails-core:find-file (rails-core:model-file name)))
(def-goto-line rails-line-->multi-association-model (("^[ \t]*\\(has_many\\|has_and_belongs_to_many\\)[ \t]*:\\([a-z0-9_]*\\)" (name 2)))
(rails-core:find-file (rails-core:model-file (singularize-string name))))
(def-goto-line rails-line-->class (("\\b\\(\\([A-Z][a-z]*\\)+\\)\\b" (name 1)))
(or (rails-core:find-file-if-exist (rails-core:model-file name))
(rails-core:find-file-if-exist (rails-core:controller-file name))
(rails-core:find-file-if-exist (rails-core:lib-file name))))
(defvar rails-line-to-controller/action-keywords
'("render" "redirect_to" "link_to" "form_tag" "start_form_tag" "render_component"
"form_remote_tag" "link_to_remote"))
(defun rails-line-->controller+action (line prefix)
(when (loop for keyword in rails-line-to-controller/action-keywords
when (string-match (format "^[ ]*%s " keyword) line) do (return t))
(let (action controller)
(when (string-match ":action[ ]*=>[ ]*[\"']\\([^\"']*\\)[\"']" line)
(setf action (match-string 1 line)))
(when (string-match ":controller[ ]*=>[ ]*[\"']\\([^\"']*\\)[\"']" line)
(setf controller (match-string 1 line)))
(if controller controller
(provide 'rails-navigation)
Jump to Line
Something went wrong with that request. Please try again.