emacs run shell command against current buffer's file name [duplicate] - vim

I can run a shell command quickly by hitting M-!. One thing I'd like to do is perform shell quick operations on the current file. An example would be checking the file out through perforce:
M-! p4 edit buffer-file-name RET
(Yes there are perforce integrations, but I'm more interested in the minishell/variable problem rather than a specific workflow)
Of course, the buffer-file-name variable is not evaluated before the command is sent to the shell.
Is there an easy on-the-fly way to do this? Or will I have to roll a custom elisp function?

It seems current Emacs has something built-in to achieve the desired result, after M-! (shell-command) press <down>, you will get the file name you are currently visiting on the prompt. Now you can edit it to add the command you want to run on it.
In dired-mode it will give you the file your cursor is currently on.

Indeed using C-u M-: is almost right. I'm not so sure about using shell-quote-argument in eval-to-shell-argument since it only works on strings making it impossible to use eval-to-shell-argument to insert a number or a symbol. You could try something like:
(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)))
and then bind this function in your minibuffer with (define-key minibuffer-local-map [?\M-:] 'sm-minibuffer-insert-val).
Of course, if the only thing you ever want to insert is the buffer-file-name, then your execute-shell-command-on-buffer is simpler.

I did roll my own elisp function, and it looks like this:
(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
I bound it to M-", so now my example can be completed with:
M-"p4 edit %sRET
I won't accept this as the answer, because I did ask for solutions that don't require a function.

You can use C-u M-: (eval-expression with a universal prefix argument) to evaluate any Lisp expression and insert its value at point in the current buffer (including minibuffers, as long as you have enable-recursive-minibuffers set to a non-nil value).
In your example: C-u M-: buffer-file-name RET.
Note that the result of the expression is printed in Lisp form: that is, quoted in such a way that a subsequent call to read would construct an equal Lisp value. For strings, this means enclosing in double quotes, which will probably be interpreted as you expect by the inferior shell. However, you may run into problems with strings that contain special characters, which need different escaping by Elisp and the shell.
The more correct way uses shell-quote-argument, as in phils' solution. Here's a quick defun that reads a Lisp expression and inserts its value at point as a properly quoted shell word:
(defun eval-to-shell-argument (form)
(interactive "XEval: ")
(insert (shell-quote-argument form)))
The read-and-evaluate step happens automatically by using an "X" as the argument to interactive.
Edited to add: As #tenpn notes, the above solution doesn't work for inserting buffer-local variables like buffer-file-name in a minibuffer like the one M-! pops up (more precisely, it inserts the buffer-local value of the minibuffer, which is unlikely to be useful). Here is a revised version which seems to work. If the minibuffer is active, it makes the buffer of the previously-selected window temporarily active while reading and evaluating an expression.
Final edit: From #Stefan's answer I see that I should have used (minibuffer-selected-window) to find the previously-selected window. I've also added a (format "%s" ..) to allow inserting non-string values, while still quoting special characters in strings. Here's the final version:
(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)))))

You can't do that with M-!, but you can evaluate arbitrary elisp from the minibuffer, so writing a function isn't strictly necessary:
M-: (shell-command (format "p4 edit %s" (shell-quote-argument buffer-file-name))) RET
In this case however, I think eshell is what you want to use:
M-x eshell-command RET p4 edit (eval buffer-file-name) RET
Edit: Except unfortunately that doesn't work, as the *eshell cmd* buffer is selected when that is evaluated. One solution would be:
M-x eshell-command RET p4 edit (eval buffer-file-name (other-buffer nil t)) RET
(Not quite as elegant, sorry.)

Everyone seems to be rolling their own version, so here's mine -- it will substitue the current filename or marked dired-files or current dired file wherever a % is in the shell command. It follows the same conventions as M-! so I bind it to that.
(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))

Related

Emacs delete up to the beginning of next word (like Vim 'dw')?

So I'm trying to delete some whitespace at the beginning of a line and when I press M-d I end up removing more content than I need to:
(add-to-list 'load-path
"~/path-to-yasnippet")
(require 'yasnippet)
(yas-global-mode 1)
^ ^
| |__ want to delete to here
|
|___ Cursor here
I've looked several places but haven't been able to do what Vim's dw command does.
For instance, Emacs' commands for operating on words don't do seem to do it.
Actually I just found out:
M-\
Does it for me since I only needed to delete white space.
There are many different solutions to this, so here is one:
(defun forward-kill-whitespace-or-word ()
"If `point' is followed by whitespace kill that.
Otherwise call `kill-word'"
(interactive)
(if (looking-at "[ \t\n]")
(let ((pos (point)))
(re-search-forward "[^ \t\n]" nil t)
(backward-char)
(kill-region pos (point)))
(kill-word 1)))
EDIT:
p should have been pos.
There are several ways to understand what you want to do:
delete whitespace at the beginning of a line
delete any characters at the beginning of a line
delete any characters up to but not including the beginning of the next word, regardless of where you are on a line and of whether there are any line breaks before the next word
mimic the behavior of Vim's dw command
I'm choosing to address item 3, since this is what I wanted to do myself.
The action I wanted to perform was equivalent to the following series of commands:
set-mark-command
forward-word
backward-word
kill-region
This is what I did:
turned on macro recording
executed the commands (via their key bindings, but you could execute them via their function names as well)
saved the macro
associated a name with that macro
copied the macro contents to my init file as a function
associated the function with a key binding
The macro contents look like this:
;; kill all characters up to but not including the start of the next word
;; (unlike kill-word, which kills the next word as well)
(fset 'my-delete-to-start-of-word
(lambda (&optional arg) "Keyboard macro." (interactive "p") (kmacro-exec-ring-item (quote ([67108896 C-right C-left delete] 0 "%d")) arg)))

Emacs: Is it possible to list all matching lines for a certain query string for marked files in dired?

I found out M-x occur the other day.
(How to achieve code folding effects in Emacs?)
I wonder if I could list all matching lines in multiple files(or buffers) preferably marked in dired mode.
Files
This can be done using package noccur which can be installed from MELPA.
It provides two functions:
noccur-dired that will perform multi-occur on dired marked files
noccur-project that will perform multi-occur on all files in current project. This is recursive.
From documentation a typical usage is: M-x noccur-project RET foo RET
The occur buffer's content can then be edited with occur-edit-mode (bound to e). To save changes in all modified buffer and go back to occur-mode press C-c C-c.
Buffers
This can be done using the built-in ibuffer. Mark buffers with m key, then key O to launch ibuffer-do-occur on marked buffers. I personally activate ibuffer using (defalias 'list-buffers 'ibuffer) in my .emacs.
You can also use the built-in multi-occur-in-matching-buffers that will perform multi-occur on buffers matching a regexp. Typical usage is M-x multi-occur-in-matching-buffers RET ext$ RET regexp RET where ext$ is regexp for buffers already opened in Emacs, and regexp is what to match.
M-x multi-occur
M-x multi-occur-in-matching-buffers
and also:
M-x multi-occur-in-this-mode
(defun get-buffers-matching-mode (mode)
"Returns a list of buffers where their major-mode is equal to MODE"
(let ((buffer-mode-matches '()))
(dolist (buf (buffer-list))
(with-current-buffer buf
(if (eq mode major-mode)
(add-to-list 'buffer-mode-matches buf))))
buffer-mode-matches))
(defun multi-occur-in-this-mode ()
"Show all lines matching REGEXP in buffers with this major mode."
(interactive)
(multi-occur
(get-buffers-matching-mode major-mode)
(car (occur-read-primary-args))))
You may try
(defun dired-do-multi-occur (regexp)
"Run `multi-occur' with REGEXP on all marked files."
(interactive (list (read-regexp "Regexp: ")))
(multi-occur (mapcar 'find-file-noselect (dired-get-marked-files)) regexp))
Run it in a dired buffer with M-x dired-do-multi-occur or bind it to a key of your liking.
Warning: all marked files will be opened by emacs.
In Icicles, use M-s M-s m (command icicle-search-dired-marked-recursive) to search the marked files in the current Dired buffer and in all marked subdirs, recursively.
Similarly, in your bookmark-list display the same key, M-s M-s m, searches the targets of all marked bookmarks. And similarly for Ibuffer and Buffer Menu: M-s M-s m searches the marked buffers.
This is Icicles search, which is a different kind of incremental search (and on-demand replace). You can confine searching within particular contexts (defined by a regexp). The search hits are updated incrementally as you change your search pattern. You can combine multiple search patterns, to refine your search progressively. You can cycle through any set of search hits or access them directly. You can change cycle orders --- you are not limited to buffer-occurrence order.
http://www.emacswiki.org/emacs/Icicles_-_Search_Commands%2c_Overview
Let me improve on the answer of mk1 since I think it is the best one so far. This keeps the same history of previous searches of occur and allows for the optional argument for displaying more lines after or before the match (using C-u followed by a number before calling the function), just as in standard occur.
(defun dired-do-multi-occur (regexp &optional nlines)
"Run `multi-occur' with REGEXP on all dired marked files."
(interactive (occur-read-primary-args))
(multi-occur (mapcar 'find-file-noselect (dired-get-marked-files)) regexp nlines))
Wrt Dired:
Not sure whether you are asking (a) to regexp-search the files marked in Dired or (b) to mark files (in Dired) whose contents match a regexp. - or (c) something else.
You can do the former (search marked files) using A (or M-S a C-M-s for incremental regexp search). And this answer lets you search all files marked here and in marked subdirs (recursively).
You can do the latter (mark the files whose contents match) using %q (dired-mark-files-containing-regexp).

Any editor/IDE that supports or could be hacked to support viewing diffs live while editing?

Is there any editor/IDE that provides a live view of differences (probably using diff) while I am editing a file. The ideal setting would be when I open a file for editing in such a diff-mode, the file is buffered in two independent panes (but put side by side), so that when I edit the contents of one, the differences of the two are highlighted for me.
There doesn't seem to be an existing Emacs mode to do exactly what you want, but a cursory googling turned up this and this.
From the second one (with mildly fixed formatting):
(defun diff-buffer-against-file (context)
"diff the current [edited] buffer and the file of the same name"
(interactive "P")
(let (($file buffer-file-name)
($tempFile "/tmp/emacs.diff")
($tempBuffer "emacs.diff"))
(delete-other-windows)
(push-mark (point) t)
(generate-new-buffer $tempFile)
(copy-to-buffer $tempBuffer (point-min) (point-max))
(set-buffer $tempBuffer)
(write-file $tempFile)
(shell-command (concat (if context "diff -c " "diff ") $file " " $tempFile))
(kill-buffer $tempFile)
(pop-mark)))
(global-set-key "\C-cd" 'diff-buffer-against-file)
The operation looks a bit too intense to bind to a change hook, but there's nothing preventing you from doing so if you're into that sort of thing.
Edit: Stefan points out that diff-buffer-with-file exists, and has the behavior you're looking for (it takes a buffer, and diffs that buffer with its file, showing that output in an unfocused temporary buffer), so you don't even need to define the above. I did try it though, and the naive
(defun diff-current (start end len) (diff-buffer-with-file (current-buffer)))
(add-hook 'after-change-functions 'diff-current)
makes editing too uncomfortable for my tastes. You'll probably want to follow Stefan's suggestion and use a timeout instead of diffing immediately on every change.

Is there a way to get emacs tag-search command to output all results to a buffer?

Is there a way to get Emacs tags-search command to collect all search results in a buffer? Something like the way results from 'grep' and 'tags-apropos' are collected in a compilation buffer?
Using M-, to iterate over the results isn't very effective if there are a large number of hits, so it'd be great if there was a way to browse and search through the results in a buffer.
Thanks,
Benj
Try etags-select
I misinterpreted your question in my first answer. Here's something that works, but is kind of bad in that it uses synchronous calls to grep so everything blocks while it's working. Improvements are left as an exercise to the reader:
(require 'etags)
(require 'grep)
(defun tags-search-sel (regexp)
"Search through all files listed in tags table for match for REGEXP.
Show all matches at once."
(interactive "sTags search (regexp): ")
;; Get all unique filenames in TAGS files.
(let ((keep-going t) files)
(when (visit-tags-table-buffer)
(while keep-going
(save-excursion
(goto-char (point-min))
(while (re-search-forward "\f\n\\([^\n]+\\),[0-9]*\n" nil t)
(add-to-list 'files
(expand-file-name
(buffer-substring (match-beginning 1) (match-end 1))
(file-truename default-directory)))))
(setq keep-going (visit-tags-table-buffer t))))
;; grep through every file for regexp
(when files
(grep-compute-defaults)
(let ((outbuf (get-buffer-create "*tags-search-sel*")))
(with-current-buffer outbuf
(setq buffer-read-only nil)
(erase-buffer)
(insert "Searching for '" regexp "' in tags files ...\n\n")
(dolist (file files)
(call-process-shell-command (concat grep-command regexp " " file) nil t))
(grep-mode)
(setq overlay-arrow-position nil)
(set-buffer-modified-p nil)
(setq buffer-read-only t)
(goto-char (point-min)))
(pop-to-buffer outbuf)))))
See icicle-tags-search. It lets you search all source files listed in tags tables for matches for a given regexp.
You see all matches of the regexp in the source-code files, as search hits to visit. All tags in a given tags file are used, including duplicate tags from the same or different source files.
By default, all tags files are used, but if you provide a prefix
argument then only the current tag table is used.
Search for matches, with completion, cycling, and search-hit replacement.
After specifying the regexp that defines the search contexts, type
input (e.g. regexp or other pattern) to match within the contexts.
The contexts that match your input are available as completion
candidates. You can use S-SPC to further narrow the candidates,
typing additional patterns to match.
By default, candidates are in order of buffer occurrence, but you can
sort them in various ways using C-,.
You can alternatively choose to search, not the search contexts as
defined by the context regexp you provide, but the non-contexts, that
is, the text in the files that does not match the regexp. To do this,
use C-M-~ during completion. (This is a toggle, and it affects only
future search commands, not the current one.)
See the doc for command icicle-search for more information.

How can I operate on more Emacs buffers at the same time?

I am looking for an equivalent of the :bufdo Vim command in Emacs. :bufdo takes an argument - another command - and executes the command on all open buffers. I have not yet found a similar feature in Emacs.
Depending on what your command is, you can do:
M-: (mapc (lambda (b) (set-buffer b) (*command*)) (buffer-list))
But, I have a feeling you want something not so lispy. Take a look at keyboard macros. Namely, decide what you want to do:
C-x ( <do-your-command> C-x )
M-: (mapc (lambda (b) (set-buffer b) (kmacro-end-and-call-macro)) (buffer-list))
You'd probably want to define that last part as a function if you use it much:
(defun bufdo ()
"execute last macro on all buffers, ala bufdo from vi"
(interactive)
(mapc (lambda (b)
(with-current-buffer b
(kmacro-end-and-call-macro)))
(buffer-list)))
Note: code is untested
You can also checkout ibuffer, it allows you to mark buffers you like to operate on with m and then you can execute something on it with E. Other common operations are also available, e.g. query-replace on Q. Just check out the menu or the mode description (C-h m).
BTW, similar things are also possible from dired, although it doesn't seem to give you an eval command.
Take a look at buffer-list (function). It returns a list of all the open buffers (BUFFER objects). See the manual for a simple example of using it with mapcar (which operates on every element of the list, and accumulates the results). You would probably also find set-buffer, which programatically sets the current buffer from Emacs Lisp, useful.

Resources