3

I'm currently trying to move from vim to emacs so be gentle with me ;)

In Vim, one of my favorite features is auto commands, I'll have one for each project for example:

au BufEnter c:/projects/foo/* :call FooSetup()
au BufEnter c:/projects/bar/* :call BarSetup()

This will call the correct setup whenever I switch buffers and change setting like the root directory, make program, error format etc.

The closest emacs equivalent I've been able to find is mode hooks, which seem much more limited.


Edit - The solution, by combining both answers below:

(defun my/test ()
  (when (and buffer-file-name (string-match "c:/projects/foo/.*" (buffer-file-name)))
    (message "foo")
    (setq default-directory "c:/projects/foo"))
  (when (and buffer-file-name (string-match "c:/projects/bar/.*" (buffer-file-name)))
    (message "bar")
    (setq default-directory "c:/projects/bar")))
(add-hook 'buffer-list-update-hook #'my/test)
flukus
  • 193
  • 5
  • 1
    Have a look at .dir-locals.el or Directory Variables. – Kaushal Modi Jan 14 '16 at 02:50
  • Thanks, I think that's exactly what I'm after. Will this work when switching between buffers/windows as well? – flukus Jan 14 '16 at 03:12
  • Actually, it looks like this doesn't cut it. Only variables can be set, you can't do things like changing directories. – flukus Jan 16 '16 at 21:31
  • 1
    It is possible but probably not exactly as you might be doing in vim. If you give a specific use case, I can give an answer for that. Usually you either set the correct hooks, enable correct minor modes or use dir or file local variables. – Kaushal Modi Jan 16 '16 at 21:34
  • One specific case is to set the root directory (setq "c:/dir") whenever you switch buffers. I found a work around for this by using eval.The bigger problem seems to be that it is only fired when you open a buffer, so if I had two files from different projects open in a split window, the correct settings would not be there when I switch between them. – flukus Jan 16 '16 at 22:17
  • 1
    I don't use it myself, but you mind find projectile useful. Among other things, it provides quick navigation among files in a project. – Tyler Jan 19 '16 at 14:12

2 Answers2

3

You need the buffer-list-update-hook.

From C-h v buffer-list-update-hook,

Hook run when the buffer list changes.
Functions running this hook are, get-buffer-create, make-indirect-buffer, rename-buffer, kill-buffer, bury-buffer-internal and select-window.

You can check out the More Standard Hooks section in the Emacs Lisp Reference Manual for info about this and other standard hooks too.

As an example, check out the below snippet which, after evaluating, will show you the current buffer name after switching buffers.

(defun my/test ()
  (message (buffer-name)))
(add-hook 'buffer-list-update-hook #'my/test)

If you have the projectile package installed, you can use the projectile-project-root function, to get the current buffer project root directory.

Kaushal Modi
  • 25,651
  • 4
  • 80
  • 183
  • Careful though, this hook is run very often, including every time a temporary buffer is used (because it needs to be created and killed). – wasamasa Jan 19 '16 at 06:23
  • @wasamasa +1. Another approach would be to have something like (let ((default-directory (projectile-project-root)))..) in whichever function that is using the default-directory variable. – Kaushal Modi Jan 19 '16 at 12:03
2

The most similar way to do it in emacs would probably be to use find-file-hook:

(defun some-directory-setup ()
  (when (string-match "/path/to/dir/.*" (buffer-file-name))
    (..do stuff..)))
(add-hook 'find-file-hook 'some-directory-setup)

As for using .dir-locals.el, you can use eval if you want to do something other than change settings. For example, you could have ((nil . ((eval . (message "Hello world."))))) in the .dir-locals.el file to execute actual code.

noctuid
  • 439
  • 3
  • 11
  • I'll play around with this, but from what I've read this even only fires when a file is first loaded and not when you switch between windows, is that correct? – flukus Jan 18 '16 at 03:03
  • buffer-list-update-hook is somewhat similar (it will run whenever you switch buffers). I don't understand what you would be doing that would need this though. EDIT: I see someone else answered; glad you found what you need. – noctuid Jan 18 '16 at 16:50
  • For buffer local variables your solution would work fine. For global ones though you need it to run on every window change. See my edit in the question. – flukus Jan 18 '16 at 20:38
  • @flukus What global variable is there that you don't want to make buffer local? default-directory is normally buffer local isn't it? – noctuid Jan 20 '16 at 20:13
  • It looks that way, this is one of the things I'm still learning :) – flukus Jan 20 '16 at 20:55
  • Just so you know, for a variable that is normally global, you can use make-local-variable to make it local (or setq-local if you want to also set it). – noctuid Jan 20 '16 at 21:59