0

I created two template files template.c and template.h in my ~/.emacs.d/autoinsert.

I have this in my ~/.emacs.d/init.el:

; Insert default content for new files
(auto-insert-mode)  ;;; Adds hook to find-files-hook
(setq auto-insert-directory "~/.emacs.d/autoinsert/") ;;; *NOTE* Trailing slash important
(setq auto-insert-query t)
(define-auto-insert "\.c" "template.c")
(define-auto-insert "\.h" "template.h")

If I create a new c file in /tmp/, emacs uses the correct template.c.

However, if I create a new c file in ~, emacs uses template.h.

Why does emacs select the h template for a c file, but only if I am in my home directory?

1 Answer 1

2

You need to escape the backslash in a string:

...
(define-auto-insert "\\.c" "template.c")
(define-auto-insert "\\.h" "template.h")

Otherwise, the CONDITION part of the first element in auto-insert-alist (the h entry) is .h and since it's a regexp, the . matches any single character (except newline) and so the first entry matches /home/<anything>.

You should also probably limit the match at the end of the suffix, so e.g. .class does not match the .c condition:

(define-auto-insert "\\.c$" "template.c")
;; or ...
(define-auto-insert "\\.c\\'" "template.c")

EDIT in response to comment: Backslashes are confusing because they are used as an escaping mechanism in multiple places. In a regex, the dot needs escaping so that the regex parser should not misinterpret it as the any metacharacter. So you need to escape it with a backslash (that's role 1: escaping metacharacters in regexes). The trouble is that regexes are represented as strings and the string parser in elisp uses backslash as its own escape mechanism: \n in a string e.g. is interpreted as a newline, \t is interpeted as a TAB character, \f is interpreted as a FORM FEED character (^L), \a is interpreted as a BEL character (^G) but most other \<char> sequences are interpreted as the character itself (e.g. \p is just p). That's role 2: escaping characters in a string - note that this has nothing whatsoever to do with regexes. But now the question is: how do you insert a literal backslash in a string like a Windows path name which uses literal backslashes, e.g. "C:\path\in\Windows\of\a\file\named\foo"? Try typing that in your *scratch* buffer and evaluating it with C-j: you will get

"C:pathinWindowsof^G^Lile
amed^Loo"

No backslashes anywhere!

The answer is: you escape the backslash, i.e. double-up the backslash - IOW, \\ in a string is interpreted as a single literal backslash. The string that you have to give to elisp should be "C:\\path\\in\\Windows\\of\\a\\file\\named\\foo". The doubled-up backslashes are really a single literal backslash in the string (e.g. "a\b" has length 2 - it consists of the two characters a and BACKSPACE); and "a\\b" has length 3 - it consists of the three characters a, \ and b).

So a regex that matches any character followed by a c is .c and the string representation of this regex is ".c". A regex that matches a literal . followed by c is \.c and the string representation of that regex is "\\.c".

3
  • Thanks, working now! I'm not sure why two backslashes, though. I understand that the dot needs escaping, but I though the single backslash would do that?
    – Gauthier
    Commented Jun 27 at 15:42
  • 1
    See edit - hope it helps.
    – NickD
    Commented Jun 27 at 16:48
  • Aargh - I forgot to surround a bunch of things with backquotes and then a third meaning of backslash (it's used as an escape character in the version of Markdown that SE uses) screwed up the display of them. Sorry about that: I think I fixed everything, but if you see something strange, please let me know.
    – NickD
    Commented Jun 27 at 20:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.