74

I would like emacs to mark files that are generated as read-only when they're opened. The part of the puzzle that I'm missing is how to check if a file "exists". I currently have the following:

;;
;; get file extension
;;
(defun get-ext (file-name)
  (car (cdr (split-string file-name "\\."))))

;; 
;; get the base name of the file
;;
(defun base-name (file-name)
  (car (split-string file-name "\\.")))

;;
;; if an 'lzz' file exists for this header, mark it as read only
;;
(defun mark-read-only ()
  (if (string= (get-ext (cur-file)) "h")
      (if ( ??file-exists??? (concat (base-name (cur-file)) ".lzz") )
          (toggle-read-only))))

What can I use for "???file-exists???"?

Once I find this, I'll add "mark-read-only" to the appropriate hook (which I think is the find-file-hook).

BACKGROUND

We use lzz as a code generator to simplify our C/C++ development process. Briefly, lzz takes a single input file (which looks very like C/C++) and generates header and source files as appropriate.

By default, lzz includes #line directives so that the debugger points to the original source and not the generated source, however, to reduce compilation dependencies we normally disable these directives in header files. The result is that when debugging templates or inline functions, the debugger normally points to the generated header file and not the original source file.

This is not a big deal, however, recently I've found that when debugging I'll make a quick modification to the displayed file and then I'll rebuild. Of course this normally means that the change I made disappears because the file I edited is generated and so the changes are "blown away" during the library rebuild.

SOLUTION

Thanks to everyone for their help and comments. A special thanks to cobbal for pointing out the correct function to use.

Here's the resulting code (with updates based on the other comments here too):

(defun cur-file ()
  "Return the filename (without directory) of the current buffer"
  (file-name-nondirectory (buffer-file-name (current-buffer)))
  )

(defun mark-generated-as-read-only ()
  "Mark generated source files as read only.
Mark generated files (lzz or gz) read only to avoid accidental updates."
  (if
      (or (string= (file-name-extension (cur-file)) "h")
          (string= (file-name-extension (cur-file)) "cpp"))
      (cond
       (
        (file-exists-p (concat (file-name-sans-extension (cur-file)) ".lzz"))
        (toggle-read-only))
       (
        (file-exists-p (concat (file-name-sans-extension (cur-file)) ".gz") )
        (toggle-read-only))
       )
    )
  )
Community
  • 1
  • 1
Richard Corden
  • 21,389
  • 8
  • 58
  • 85
  • 3
    Instead of putting comments above your functions, in Elisp, you can write them in the first line of a function declaration. It called the "docstring". See http://www.gnu.org/software/emacs/elisp/html_node/Documentation-Basics.html – viam0Zah Jun 03 '09 at 12:39
  • 9
    Note: your first two functions come with Emacs, they are named 'file-name-extension and 'file-name-sans-extension – Trey Jackson Jun 03 '09 at 15:49

3 Answers3

109

try file-exists-p

"Return t if file filename exists (whether or not you can read it.)".

Note that it's not spesific to files and works for directories too.

ideasman42
  • 42,413
  • 44
  • 197
  • 320
cobbal
  • 69,903
  • 20
  • 143
  • 156
  • 4
    Why doesn't this function appear when I do a "C-H a" appros search for it? I tried searching for file and going through the results for 'exists', and there are no matches at all for exists! – Richard Corden Jun 03 '09 at 09:13
  • yeah, I tried looking for 'exists' that way, then found the function 'find-file-existing' in files.el, opened that up and found the file-exists-p. don't know why it doesn't show up under C-H a – cobbal Jun 03 '09 at 09:15
  • 17
    file-exists-p doesn't show up under "C-H a" because it's not an "interactive" function. It should show up under "M-x apropos" though. – Edric Jun 03 '09 at 09:22
  • 11
    Which is exactly why I have this in my .emacs (define-key help-map "a" 'apropos) That way "C-h a" finds looks through all symbols for me. – Trey Jackson Jun 03 '09 at 13:58
  • 1
    Speaking of file-exists-p, this function is also a way to check if a directory exists. There is no separate directory-exists-p. – Yoo May 31 '10 at 15:32
  • 9
    Yes there is, it's called `file-directory-p`. – Hugh Sep 05 '11 at 02:16
  • 4
    @Trey You can also set `apropos-do-all` to non-nil to get `apropos-command` (default "C-h a" binding) to search non-interactive functions – scry May 12 '14 at 04:33
  • 2
    use the prefix command with `C-h a` to also get non interactive functions. `C-u C-h a` – sebs Dec 03 '14 at 04:18
17
  • Depending on what you need, you might want file-readable-p instead of file-exists-p.

  • Apropos will only get you so far. Icicles provides apropos completion and progressive completion which let you find help easily for command, function, variable, etc. names that match subparts in an arbitrary order (is it file-exists-p or exists-file-p?).

Drew
  • 29,895
  • 7
  • 74
  • 104
8

Use f.el, modern library for file and directory manipulation. You can use f-exists?, f-file?, f-directory? and many other predicates. The library is better than standard functions, because it's every file related function you'll ever need under one namespace.

Mirzhan Irkegulov
  • 17,660
  • 12
  • 105
  • 166