0

[I apologize for the poor title, but couldn't come up with a better one.]

bin chen asked on Google+:

How to input relative path of (buffer-file-name) in minibuffer after M-! in #emacs?

I thought if the buffer-file-name is saved in a register, it should be accessible by invoking insert-register (C-x r i) while at the shell-command prompt.

(defun save-buffer-file-name-in-register ()
    (set-register ?F (buffer-file-name))
    (set-register ?D (file-name-directory buffer-file-name)))

(defadvice shell-command (before save-buffer-file-name)
  "Save buffer-file-name to register F before running shell-command"
  (save-buffer-file-name-in-register))

(ad-activate 'shell-command)

When I invoke shell-command (M-!) followed by insert-register (C-x r i), I get the error message: Register does not contain any text.

But when I run list-registers I do see that the registers F and D are set with the appropriate values. If I run the shell-command again, I can access the values from the registers previously saved.

Is it possible that the registers are being set too late for the first time? How can I fix the code to do what I want?

Edit: Changed around to before (Thanks to @phils)

Prakash K
  • 3,020
  • 1
  • 20
  • 11

2 Answers2

2

n.b. You have defined around advice, not before advice.

Around advice acts as a wrapper, and must include the token ad-do-it to execute the code of the function it is wrapping.

You have effectively replaced the body of the shell-command function with a call to save-buffer-file-name-in-register

As to your main question, I'd need to check the documentation, but I suspect that because the arguments to the advised function are available to advice, the original function's interactive declaration probably executes before the advice does, which would explain why your register values are not visible at the interactive shell-command prompt.

(If the around in the above code is indeed what you were using, the fact that you were still being prompted for a shell command would seem to verify this sequence.)

phils
  • 71,335
  • 11
  • 153
  • 198
  • Thanks for your response. I was playing with both `around` and `before`, and "around" in the above code was the result of a incorrect paste from my emacs buffer. The version I actually tried and wanted to ask about was the "before" version. – Prakash K Mar 06 '12 at 03:42
2

When the interactive form runs, your advice hasn't executed yet. See: this question

You need to specify an interactive form in your advice that redefines the original if you want to stick with this approach. However, this approach is a little fancy-pants for the sake of fancy-pants-ness.

Just define your own interactive function which does what you want without registers.

(defun insert-cur-dir ()
  (interactive)
  (let ((dir-name (file-name-directory (buffer-file-name (window-buffer (minibuffer-selected-window))))))
    (insert (or dir-name ""))))

(define-key minibuffer-local-map (kbd "C-c i") 'insert-cur-dir)

An alternative, but way awesomer approach is to use yasnippet.

Community
  • 1
  • 1
event_jr
  • 17,467
  • 4
  • 47
  • 62
  • Thanks for your response and link to the other question. Could you elaborate on why you think it is *fancy-pants for the sake of fancy-pants-ness*? I am not proficient in elisp, nor the right way of doing things. I thought `defadvice` was the perfect way to accomplish it with least amount of code, and without defining additional keybindings. – Prakash K Mar 06 '12 at 03:53
  • `defadvice` is a last resort solution. If you want to stick to your original approach (i.e. put value into register), it would be quite straight forward to make your own command that calls `shell-command` instead of advising it. Also commands typically don't make heavy use of registers. – event_jr Mar 06 '12 at 07:36