8

を押すと、シェルコマンドをすばやく実行できますM-!。私がやりたいことの1つは、現在のファイルに対してシェルクイック操作を実行することです。例として、PERFORCEを介してファイルをチェックアウトします。

M-! p4 edit buffer-file-name RET

(はい、PERFORCE統合がありますが、特定のワークフローよりもミニシェル/変数の問題に関心があります)

もちろん、buffer-file-nameコマンドがシェルに送信される前に、変数は評価されません。

これを行う簡単なオンザフライの方法はありますか?または、カスタムelisp関数をロールする必要がありますか?

4

6 に答える 6

4

実際、Cu M-: を使用することはほぼ正しいです。shell-quote-argumentin の使用についてはよくわかりません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)。もちろん、挿入したいのがバッファファイル名だけであれば、execute-shell-command-on-bufferより簡単です。

于 2012-04-12T14:11:02.457 に答える
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-"ので、今私の例は次のように完成することができます:

M-"p4 edit %sRET

関数を必要としない解決策を求めたので、これを答えとして受け入れません。

于 2012-04-12T14:07:31.963 に答える
1

任意の Lisp 式を評価し、その値を現在のバッファー (非値に設定している限り、ミニバッファーを含む) のポイントに挿入するためにC-u M-:(をユニバーサル プレフィックス引数と共に) を使用できます。eval-expressionenable-recursive-minibuffersnil

あなたの例では: C-u M-: buffer-file-name RET.

式の結果は Lisp 形式で出力されることに注意してください。つまり、その後の の呼び出しがLisp 値readを構築するような方法で引用されます。equal文字列の場合、これは二重引用符で囲むことを意味します。これは、下位シェルによって期待どおりに解釈される可能性があります。ただし、Elisp とシェルによる異なるエスケープが必要な特殊文字を含む文字列で問題が発生する場合があります。

より正しい方法はshell-quote-argument、phils のソリューションのように を使用します。以下は、Lisp 式を読み取り、その値を適切に引用されたシェル ワードとしてポイントに挿入する簡単な defun です。

(defun eval-to-shell-argument (form)
  (interactive "XEval: ")
  (insert (shell-quote-argument form)))

"X"の引数としてを使用すると、読み取りと評価のステップが自動的に行われinteractiveます。

追加するために編集: @tenpn が指摘するように、上記の解決策は、ポップアップのようなミニバッファーのようなバッファーローカル変数の挿入には機能しません (より正確には、ミニバッファーのバッファーローカル値を挿入しますbuffer-file-nameM-!便利である)。これは動作するように見える改訂版です。ミニバッファーがアクティブな場合、式の読み取りと評価中に、以前に選択されたウィンドウのバッファーが一時的にアクティブになります。

最終編集: @Stefan の回答から(minibuffer-selected-window)、以前に選択したウィンドウを見つけるために使用する必要があったことがわかります。(format "%s" ..)また、文字列内の特殊文字を引用しながら、文字列以外の値を挿入できるように を追加しました。最終版は次のとおりです。

(defun eval-to-shell-argument ()
  (interactive)
  (let* ((buffer
          (if (minibufferp)
              (window-buffer (minibuffer-selected-window))
            (current-buffer)))
         (result
          (with-current-buffer buffer
            (eval-minibuffer "Eval: "))))
    (insert (shell-quote-argument (format "%s" result)))))
于 2012-04-12T12:37:54.187 に答える
1

誰もが独自のバージョンを展開しているように見えるので、ここに私のバージョンを示します。これは、現在のファイル名またはマークされた dired-files または現在の dired ファイル%を、シェル コマンド内の a に置き換えます。と同じ規則に従う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))
于 2012-04-12T16:55:15.873 に答える
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*評価時にバッファが選択されるため、機能しません。1つの解決策は次のとおりです。

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

(それほどエレガントではありません、申し訳ありません。)

于 2012-04-12T12:32:14.567 に答える