web developer & system programmer

coder . cl

ramblings and thoughts on programming...

directory based hooks in emacs

published: 08-10-2010 / updated: 08-10-2010
posted in: development, emacs, programming, tips
by Daniel Molina Wegener

Some time ago, I was using ecb-mode — Emacs Code Browser — hooks to specify which hook will run on certain directory, so I was configuring Emacs to run certain hook based on the directory of the file. The ecb-after-directory-change-hook was great to integrate Emacs and well defined project specific indentation modes for C, C++ and some other languages. Each project has its own indentation style, for example for Python extensions, you must use the python style: (setq c-default-style "python"); for the Linux Kernel you must use the “linux” style: (setq c-default-style "linux"); for GNU related tools, you must use the gnu style: (setq c-default-style "gnu") and for the FreeBSD operating system, you must the knf style: (setq c-default-style "knf").

This small trick, will allow you to use certain style and run your project specific hook based on the directory name or file name that is visited by Emacs.

(defvar dmw-visit-file-mode-list
  '(("/home/dmw" caffeine-c-mode-hook)
    ("/work/src/caffeine" caffeine-c-mode-hook)
    ("/work/src/caffeine++" caffeine-c++-mode-hook)
    ("/work/src/fireservice" caffeine-c++-mode-hook)
    ("/work/src/Linux" gnu-c++-mode-hook)
    ("/work/src/FreeBSD" caffeine-c-mode-hook)
    ("/work/src/jaxer/products/server/src" caffeine-c++-mode-hook)
    ("/work/src/syslog-ng" caffeine-c-mode-hook)
    ("/work/src/pyxser" python-c-mode-hook)
    ("/work/gae/gae-1.3.7/cclp" python-mode-hook)
    ("/work/gae/gae-1.3.7/todo" python-mode-hook)
    ("/work/gae/gae-1.3.7" python-mode-hook)
    ("/work/www" dmw-php-mode-hook)))

(defun dmw-directory-based-c-hook ()
  (make-local-variable 'tab-width)
  (make-local-variable 'indent-tabs-mode)
  (make-local-variable 'fill-column)
  (make-local-variable 'tab-width)
  (make-local-variable 'c-tab-always-indent)
  (make-local-variable 'c-auto-hungry-initial-state)
  (make-local-variable 'c-default-style)
  (make-local-variable 'c-indent-level)
  (make-local-variable 'c-auto-hungry-initial-state)
  (make-local-variable 'c-block-comment-prefix)
  (make-local-variable 'c-basic-offset)
  (make-local-variable 'c-offsets-alist)
  (make-local-variable 'c-tab-always-indent)
  (make-local-variable 'fill-column)
  (dolist (dir-mode-pair dmw-ecb-directory-change-alist)
    (let ((dir-name (concat (first dir-mode-pair) ".*"))
          (mode-is (car (last dir-mode-pair)))
          (match-dir-based (string-match
                            (concat (first dir-mode-pair) ".*")
      (if (and (numberp match-dir-based)
               (>= match-dir-based 0))
          (funcall mode-is))))
  (message ">>> done dmw-directory-based-c-hook..."))

Where each hook function on the dmw-visit-file-mode-list, runs each time that a file is visited. For example if I visit a file on the "/work/src/pyxser" directory, it will run the python-c-mode-hook function as mode hook.

;;; I add dmw-directory-based-c-hook to both C and C++ mode hook lists
(add-hook 'c-mode-hook 'dmw-directory-based-c-hook)
(add-hook 'c++-mode-hook 'dmw-directory-based-c-hook)
;;; instead of adding directly the python-c-mode-hook
(add-hook 'c-mode-hook 'python-c-mode-hook)
;;; which is only one, so, I leave project specific hooks to be handled
;;; based on its directory

And the python-c-mode-hook hook function, looks as follows:

(defun python-c-mode-hook ()
  (setq c-default-style "python")
  (setq tab-width 4)
  (setq indent-tabs-mode nil)
  (setq c-tab-always-indent t)
  (setq c-basic-offset 4)
  (setq c-auto-hungry-initial-state 'none)
  (setq c-tab-always-indent t)
  (setq c-block-comment-prefix "* ")
  (setq fill-column 78)
  (c-set-offset 'arglist-cont 4)
  (c-set-offset 'arglist-cont-nonempty 4)
  (c-set-offset 'statement-cont 4)
  (c-set-offset 'label [0])
  (c-set-style "python")
  (message ">>> done python-c-mode-hook (style %s)" c-indentation-style))

Happy programming under Emacs ;)

2 comments to “directory based hooks in emacs”

  1. Great stuff. I use it for having a specific variable width face for reading textfiles in a specific directory (variable width works better for long texts).

    There is an error above however:

    (dolist (dir-mode-pair dmw-ecb-directory-change-alist)

    should read:

    (dolist (dir-mode-pair dmw-visit-file-mode-list)
  2. Thanks! Your hack is good too ;-)

post a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>