views:

774

answers:

3

I'm starting to use objective C, and objective C mode works perfectly fine. However, ObjC uses .h files, just like C and C++. I need to be able to use all three. Does anyone know how to get emacs to tell if it should be in objC mode or C/C++ mode?

EDIT: There seems to be some confusion on what I'm asking for. The problem is that I have some .h files that are associated with .m files, and some .h files that are associated with .c files and some that are associated with .cpp files. What I WANT is something that I can stick in my c-mode-common-hook or somewhere that will check to see if it's an objective C .h file, and then force it to objective C-mode, or something. The idea being that then I can just open a .h file and it will automatically be in the correct mode.

Obviously I can manually change mode when I'm in the file, but that's a pain, and I often forget until I hit tab and something wacky happens. This is the solution I'm using now.

I think that the header comment is probably the right way to do this, but in order for it to be TRULY useful, I need to figure out how to get XCode to put the comment in there when It's creating the file for me...

EDIT2:

I'm currently using the header-comment solution. Until I can figure out how to make XCode automatically add the comment, I'm using the following elisp function:

(defun bp-add-objC-comment ()
  "Adds the /* -*- mode: objc -*- */ line at the top of the file"
  (interactive)
  (objc-mode)
  (let((p (point)))
    (goto-char 0)
    (insert "/* -*- mode: objc -*- */\n")
    (goto-char (+ p  (length "/* -*- mode: objc -*- */\n")))))
+11  A: 

You can put a comment like this in the first line of the file:

/* -*- mode: objc -*- */

or

// -*- mode: c++ -*-

as appropriate. More details in Specifying File Variables in the Emacs manual.

legoscia
that will work, yes. I was looking for a LITTLE less effort, but I can make a script to do that...
Brian Postow
Now, I need a way to automatically add that when Xcode creates the file...
Brian Postow
+1  A: 

I would use eproject to help me handle this. Assuming that I don't mix-and-match languages inside a given project, I could just create a .eproject file in the project root that contains the text:

:cc-header-type :objc

Then, I'd set some sort of default mode for .h files:

(add-to-list 'auto-mode-alist '("[.]h$" . c-mode))

Then, add a hook for that mode:

(add-hook 'c-mode-hook (lambda ()
    (let ((header-style (eproject-attribute :cc-header-type)))
        (when (and header-style
                   (string-match "[.]h$" (buffer-file-name)))
            (case header-style
                (:objc (objc-mode))
                (:c++  (c++-mode))
                (:c    (c-mode))))))

Now the mode will be changed automatically according to the setting you make in the .eproject file. (Note that the .eproject file is not the only way to set variables for eproject; if you have a heuristic to detect objective c projects, eproject can get the variable that way also.)

Anyway, if this works for you, let me know so I can add it to the eproject wiki.

jrockway
Actually, I WILL need to mix C++ and Objective C files in one project...
Brian Postow
+3  A: 

Ok, how about a solution that doesn't require putting a special comment in the file?

Check this out:

;; need find-file to do this
(require 'find-file)
;; find-file doesn't grok objc files for some reason, add that
(push ".m" (cadr (assoc "\\.h\\'" cc-other-file-alist)))

(defun my-find-proper-mode ()
  (interactive)
  ;; only run on .h files
  (when (string-match "\\.h\\'" (buffer-file-name))
    (save-window-excursion
      (save-excursion
        (let* ((alist (append auto-mode-alist nil))  ;; use whatever auto-mode-alist has
               (ff-ignore-include t)                 ;; operate on buffer name only
               (src (ff-other-file-name))            ;; find the src file corresponding to .h
               re mode)
          ;; go through the association list
          ;; and find the mode associated with the source file
          ;; that is the mode we want to use for the .h file
          (while (and alist
                      (setq mode (cdar alist))
                      (setq re (caar alist))
                      (not (string-match re src)))
            (setq alist (cdr alist)))
          (when mode (funcall mode)))))))

(add-hook 'find-file-hook 'my-find-proper-mode)

This uses Emacs' built in package to find the corresponding .h/.cc files. So, if the header file you just opened corresponds to a file in c++-mode, the .h file gets put in that mode, if the source is a objc-mode file, the header gets put in that mode.

No special Emacs variables in the comments required.

Trey Jackson
Interesting. I'll have to look at that more carefully to see exactly how it is working. Very nice!
Brian Postow