将Emacs变量传递给minibuffer shell命令

时间:2012-04-12 10:40:18

标签: emacs emacs23

我可以通过点击 M - !快速运行shell命令。我想做的一件事是对当前文件执行shell快速操作。一个例子是通过perforce检查文件:

M - ! p4 edit buffer-file-name RET

(是的,有perforce集成,但我对minishell / variable问题而不是特定的工作流程更感兴趣)

当然,在将命令发送到shell之前,不会评估buffer-file-name变量。

有一种简单的即时方式吗?或者我是否必须推出自定义elisp功能?

6 个答案:

答案 0 :(得分:6)

M-!shell-command)按<down>后,当前Emacs似乎有内置功能可以获得所需的结果,您将获得当前正在访问的文件名提示。现在您可以编辑它以添加要在其上运行的命令。

dired-mode中,它会为您提供光标当前所在的文件。

答案 1 :(得分:4)

确实使用C-u M-:几乎是正确的。我不太确定在shell-quote-argument中使用eval-to-shell-argument,因为它仅适用于字符串,因此无法使用eval-to-shell-argument插入数字或符号。你可以尝试类似的东西:

(defun sm-minibuffer-insert-val (exp)
  (interactive
   (list (let ((enable-recursive-minibuffers t))
           (read-from-minibuffer "Insert: "
                                 nil read-expression-map t
                                 'read-expression-history))))
    (let ((val (with-selected-window (minibuffer-selected-window)
                 (eval exp)))
          (standard-output (current-buffer)))
      (prin1 val)))

然后使用(define-key minibuffer-local-map [?\M-:] 'sm-minibuffer-insert-val)在迷你缓冲区中绑定此功能。 当然,如果您想要插入的唯一内容是buffer-file-name,那么execute-shell-command-on-buffer就更简单了。

答案 2 :(得分:3)

滚动我自己的elisp函数,它看起来像这样:

(defun execute-shell-command-on-buffer (shell-command-text)
    (interactive "MShell command:")
    (shell-command (format shell-command-text (shell-quote-argument buffer-file-name)))
    )

https://gist.github.com/2367513

我将它绑定到 M - &#34; ,所以现在我的示例可以用以下内容完成:

米 - &#34; p4 edit %s RET

我不接受这个作为答案,因为我确实要求解决方案不需要功能。

答案 3 :(得分:1)

你不能用 M - !做到这一点,但是你可以从迷你缓冲区中评估任意的elisp,所以写一个函数并不是绝对必要的:

M - : (shell-command (format "p4 edit %s" (shell-quote-argument buffer-file-name))) RET

在这种情况下,我认为eshell是你想要使用的:

M-x eshell-command RET p4 edit (eval buffer-file-name) RET

编辑:不幸的是,这不起作用,因为评估时会选择*eshell cmd*缓冲区。一种解决方案是:

M-x eshell-command RET p4 edit (eval buffer-file-name (other-buffer nil t)) RET

(不太优雅,对不起。)

答案 4 :(得分:1)

您可以使用C-u M-:(带有通用前缀参数的eval-expression)来评估任何Lisp表达式并在当前缓冲区中的点处插入其值(包括minibuffers,只要您有{{1设置为非enable-recursive-minibuffers值。)

在您的示例中:nil

请注意,表达式的结果以Lisp形式打印:即,以C-u M-: buffer-file-name RET的后续调用构造read Lisp值的方式引用。对于字符串,这意味着用双引号括起来,这可能会被下层shell解释为您所期望的。但是,您可能会遇到包含特殊字符的字符串的问题,这些字符串需要通过Elisp和shell进行不同的转义。

更正确的方法是使用equal,就像phils的解决方案一样。这是一个快速定义,它读取一个Lisp表达式并将其值作为正确引用的shell单词插入其中:

shell-quote-argument

使用(defun eval-to-shell-argument (form) (interactive "XEval: ") (insert (shell-quote-argument form))) 作为"X"的参数,自动执行读取和评估步骤。

编辑添加:作为@tenpn备注,上述解决方案无法在像interactive一样的迷你缓冲区中插入缓冲区局部变量(如buffer-file-name) up(更确切地说,它插入了迷你缓冲区的缓冲区本地值,这不太可能有用)。这是一个似乎有效的修订版本。如果迷你缓冲区处于活动状态,则会在读取和评估表达式时使先前选择的窗口的缓冲区暂时处于活动状态。

最终修改:从@ Stefan的回答中我发现我应该使用M-!找到之前选择的窗口。我还添加了(minibuffer-selected-window)以允许插入非字符串值,同时仍引用字符串中的特殊字符。这是最终版本:

(format "%s" ..)

答案 5 :(得分:1)

每个人似乎都在推销他们自己的版本,所以这是我的 - 它会替换当前的文件名或标记的dired-files或当前的dired文件,只要%在shell命令中。它遵循与M-!相同的约定,因此我将其绑定到它。

(defun my-shell-command (command &optional output-buffer error-buffer)
  "Run a shell command with the current file (or marked dired files).
In the shell command, the file(s) will be substituted wherever a '%' is."
  (interactive (list (read-from-minibuffer "Shell command: "
                                           nil nil nil 'shell-command-history)
                     current-prefix-arg
                     shell-command-default-error-buffer))
  (cond ((buffer-file-name)
         (setq command (replace-regexp-in-string "%" (buffer-file-name) command nil t)))
        ((and (equal major-mode 'dired-mode) (save-excursion (dired-move-to-filename)))
         (setq command (replace-regexp-in-string "%" (mapconcat 'identity (dired-get-marked-files) " ") command nil t))))
  (shell-command command output-buffer error-buffer))