3

I have the function below in my .emacs which I use quite frequently to put the filename/path of a local file in the current buffer. It is working nicely, however, I'd like it to have ido completion. But I seem unable to achieve that... maybe you can help me.

(defun insert-file-name (filename &optional args)
  "Insert name of file FILENAME into buffer after point.

  Prefixed with \\[universal-argument], expand the file name to
  its fully canocalized path.  See `expand-file-name'.

  Prefixed with \\[negative-argument], use relative path to file
  name from current directory, `default-directory'.  See
  `file-relative-name'.

  The default with no prefix is to insert the file name exactly as
  it appears in the minibuffer prompt."
  ;; Based on insert-file in Emacs -- ashawley 20080926
  (interactive "*fInsert file name: \nP")
  (cond ((eq '- args)
         (insert (expand-file-name filename)))
        ((not (null args))
         (insert (filename)))
        (t
         (insert (file-relative-name filename)))))
elemakil
  • 3,681
  • 28
  • 53

1 Answers1

4

With ido-everywhere turned-on, (interactive "f") will normally use ido-read-file-name, which will not only provide automatic completion for your function, but also almost everywhere.

If you want to have ido completion only for this function, but not everywhere, you can explicitly call ido-read-file-name in the interactive form. One side effect of using ido in your case is that it seems to always return a full path, making the distinction between filename and (expand-file-name filename) effectless.

(defun insert-file-name (filename &optional args)
  "Insert name of file FILENAME into buffer after point.

  Prefixed with \\[universal-argument], expand the file name to
  its fully canocalized path.  See `expand-file-name'.

  Prefixed with \\[negative-argument], use relative path to file
  name from current directory, `default-directory'.  See
  `file-relative-name'.

  The default with no prefix is to insert the file name exactly as
  it appears in the minibuffer prompt."
  ;; Based on insert-file in Emacs -- ashawley 20080926
  (interactive `(,(ido-read-file-name "File Name: ")
                 ,current-prefix-arg))
  (cond ((eq '- args)
         (insert (expand-file-name filename)))
        ((not (null args))
         (insert filename))
        (t
         (insert (file-relative-name filename)))))
François Févotte
  • 19,520
  • 4
  • 51
  • 74
  • I have re-checked and even though `ido-everywhere` is `t`, the old function does not use `ido` for completion. Maybe `ido-everywhere` doesn't work with the format of `interactive` used by the function? – elemakil May 27 '13 at 13:14
  • Alright, after some more investigation I found [this](http://stackoverflow.com/questions/11505878/get-ido-in-dired-buffers) question, which led me to the solution: One shall **never** use `(setq ido-everywhere t)` but rather `(ido-everywhere t)` which is contraire to most beginner's guides and the pre-selected `.emacs.d` configs I think. – elemakil May 27 '13 at 13:20
  • Well, it does on my system (GNU Emacs 23.2.1, Debian flavour), without any init file. Have you tried deactivating your init file to check if `ido-everywhere` might be broken by some customization in it? (run `emacs -q`, eval your defun, activate `ido-mode` and `ido-everywhere`, and see if it changes anything) – François Févotte May 27 '13 at 13:23
  • See my second comment; changing the way `ido-everywhere` is activated is **really** important... The code you presented above works in any case! – elemakil May 27 '13 at 13:25
  • Yes, I saw your comment after posting mine. In any case, the mode activation is a very important broadly adopted convention in Emacs: modes should be activated using `(mode-name +1)` and deactivated using `(mode-name -1)`. Simply using `(mode-name)` toggles the mode and could lead to unpredictable results. Simply setting the variable isn't enough, as you just discovered. – François Févotte May 27 '13 at 15:00