Emacs: Navigating to compile error
I'm setting up emacs as my ruby development environment. I run tests by doing M-x compile and then rake test. I've set up compile-error-regexp-alist appropriately so that the resulting compile buffer can recognize test failures and make them clickable, but I'm facing trouble getting compile-find-file to use the correct directory to find the file from. Suppose I'm visiting the file proj-home/test/ruby-test-file.rb and hit M-x compile and then u开发者_StackOverflow社区se "rake test" for the compile-command. The resultant compile-buffer has "proj-home/test/" set as the default-directory while the rake test output has errors user [./test/ruby-test-file.rb:nn]. So when compile-find-file tries to find the file specified in the error message, it looks in "proj-home/test/./test/ruby-test-file.rb" which is obviously wrong.
How do I make compile-find-file to look in the right place? I've spent quite some time debugging the functions and reading through the function definitions in compile.el, but no joy yet. One thing that did surprise me is that running rake test from inside a shell cd'd to "proj-home/test" correctly runs the tests (even tho' the Rakefile is in "proj-home" and not "proj-home/test"), so it looks like rake has some intelligence built-in which allows it to search up the directory tree and find the Rakefile in parent directories.
This intelligence in rake might be confusing emacs as to what is the current directory it should use.
The emacs wiki here: http://www.emacswiki.org/emacs/CompileCommand has a code snippet to find a file by searching parent directories (under "Running Make with the closest Makefile"), but I still haven't figured out if/where I need to use that code snippet.
You could try to define an advice around compile to set the correct default directory:
(defadvice compile (around set-rail-test-dir (command &optional comint))
"set the correct directory"
(if (and (string-match "rake test" command)
(string-match "\(.*\)/test/$" default-directory))
(let ((default-directory (match-string 1 default-directory)))
ad-do-it)
ad-do-it))
(ad-activate 'compile)
You might want to use something more clever to set the correct directory, and to know if it should be set or no (maybe using one of the code snippet you gave), but the idea is to use this code to change the compile function without redefining it.
I finally used the following code to set the default-directory in the compile command as suggested by Remi
(defun ancestor-directory-with (file-name &optional directory)
(let ((dir (or directory default-directory))
(root (expand-file-name "/"))) ;the win32 builds should translate this correctly
(if (directory-has-file-p dir file-name)
dir
(if (equal (directory-file-name dir) (directory-file-name root))
default-directory
(ancestor-directory-with file-name (expand-file-name ".." dir))))))
(defun directory-has-file-p (directory file-name)
(file-exists-p (expand-file-name file-name directory)))
Using this to set the default-directory in the compile command helped me get the correct behaviour.
精彩评论