How can you automate a find-dired query-replace? - emacs

M-x find-dired: you will be prompted for a root directory and a filename pattern.
Press t to "toggle mark" for all files found.
Press Q for "Query-Replace in Files..."
you will be prompted for query/substitution regexps.
How can you define a function like my-find-dired that goes through steps 1-3 for you, using in step 1 dir /foo and filename -iname \*.html, and takes you straight to step 4?
EDIT working on fn def:
I get the step 4 prompting, but it doesn't do anything, because none of the files are marked, so I'm thinking the second-to-last line must be wrong. Here are a couple tries:
(defun my-find-dired-and-replace ()
(interactive)
(find-dired "~/foo/" "-iname \*.html -o -iname \*.coffee -o -iname \*.styl")
(dired-mark-files-containing-regexp "\*")
(call-interactively 'dired-do-query-replace-regexp))
also tried just "*"
(defun my-find-dired-and-replace ()
(interactive)
(find-dired "~/foo/" "-iname \*.html -o -iname \*.coffee -o -iname \*.styl")
(dired-toggle-marks)
(call-interactively 'dired-do-query-replace-regexp))

When calling from a program, the approach will be slightly different than using interactive calls. What about that way:
(defun my-find-dired-and-replace ()
(interactive)
(find-name-dired "MY-DIR" "*.html")
(dired-mark-files-containing-regexp MY_REGEXP)
(dired-do-query-replace-regexp FROM TO))

Related

emacs cd for all splits

In emacs you can do M-x cd to change the default directory.
I usually have 5 splits/windows, so the cd I do in the first split does't affect the others. What If I want the cd to affect all my splits/buffers.
Is there an alternative command I can use?
There's nothing built-in but it's not too hard to write the function by hand:
(defun cd-all-windows (dir)
(interactive "Ddirectory: ")
(dolist (window (window-list))
(with-current-buffer (window-buffer window)
(cd dir))))
Put that in your .emacs and you should be able to run M-x cd-all-windows to get the desired effect.

how to specify multiple file extensions in rgrep?

I tried *.{cc,hh} but it doesn't work (this works for lgrep though). i also tried the method suggested her e http://compgroups.net/comp.emacs/searching-multiple-file-types-with-rgrep/95027 but it seems the interactive mode doesn't allow me to input space. Any idea?
*.cc *.hh is correct. The find command will then use something like:
\( -iname \*.cc -o -iname \*.hh \)
(If you supply a prefix argument, you can view/edit the command before it is executed.)
You can enter the space using quoted-insert: C-qSPC, or just-one-space: M-SPC
I was (in despair) rolling an elisp solution:
(defun mrgrep (pattern extensions dir)
(interactive "ssearch for: \nsextensions (space separated, no *): \nD")
(setq includes (mapconcat (lambda (ext)
(concat (format "--include=\"\\*%s\"" ext)))
(s-split " " extensions)
" "))
(setq cmd (format "grep -ir %s %s %s"
includes
pattern
(concat dir "*")))
(setq cmd (read-from-minibuffer "run grep like this: " cmd))
(compilation-start cmd 'grep-mode)
)
but phils explained how to enter the space !

How can I use M-x rgrep with the git grep command in Emacs?

I want to be able to use the normal M-x rgrep workflow (entering a path, a pattern and displaying the linked results in a *grep* buffer) but using git grep instead of the normal find command:
find . -type f -exec grep -nH -e {} +
I tried directly setting the grep-find-command variable:
(setq grep-find-command "git grep")
and using grep-apply-setting
(grep-apply-setting 'grep-find-command "git grep")
but neither seems to work. When I run M-x rgrep it just uses the same find command as before.
In fact, I'm pretty sure now that rgrep doesn't even use the grep-find-command variable, but I can't figure out where it's command is stored.
What about M-x vc-git-grep (C-x v f). Doesn't that do what you need?
It prompts you for:
search pattern (default: token at point, or region)
filename pattern (default: current file suffix)
base search directory (default, current dir)
Works nicely for me.
Turns out the relevant variable is actually grep-find-template. This takes a command with a few additional parameters:
<D> for the base directory
<X> for the find options to restrict directory list
<F> for the find options to limit the files matched
<C> for the place to put -i if the search is case-insensitive
<R> for the regular expression to search for
The default template looks like this:
find . <X> -type f <F> -exec grep <C> -nH -e <R> {} +
To make the command work with git grep, I had to pass in a few options to make sure git doesn't use a pager and outputs things in the right format. I also ignored a few of the template options because git grep already restricts the files searched in a natural way. However, it probably makes sense to add them back in somehow.
My new value for grep-find-template is
git --no-pager grep --no-color --line-number <C> <R>
After some cursory testing, it seems to work.
Note that you should set this variable using grep-apply-setting rather than modifying it directly:
(grep-apply-setting 'grep-find-template "git --no-pager grep --no-color --line-number <C> <R>")
Since I don't use two of the inputs to rgrep, I wrote my own git-grep command which temporarily stashes the old grep-find-template and replaces it with mine. This feels a bit hacky, but also seems to work.
(defcustom git-grep-command "git --no-pager grep --no-color --line-number <C> <R>"
"The command to run with M-x git-grep.")
(defun git-grep (regexp)
"Search for the given regexp using `git grep' in the current directory."
(interactive "sRegexp: ")
(unless (boundp 'grep-find-template) (grep-compute-defaults))
(let ((old-command grep-find-template))
(grep-apply-setting 'grep-find-template git-grep-command)
(rgrep regexp "*" "")
(grep-apply-setting 'grep-find-template old-command)))
With Emacs for Windows and Git Bash make sure PATH finds git.exe or vc-git-grep won't work:
(let ((dir "C:/Program Files/Tools/Git/bin"))
(setenv "PATH" (concat (getenv "PATH") ";" dir))
(setq exec-path (append exec-path '(dir))))
exec-path is not enough... resaons are explained here: Using git with emacs
Since vc-git-grep uses the directory of the buffer from which you run the function I also found a wrapper convenient:
(global-set-key [(control f8)]
(lambda() (interactive)
(with-current-buffer ROOT (call-interactively #'vc-git-grep))))
Here ROOT is a buffer (or function that evaluates a buffer) from whose directory the search begins.

Batch export of org-mode files from the command line

Assume that I have in a certain directory several org-mode files: foo1.org, foo2.org, etc. I would like to have a script (maybe a makefile) that I could invoke something like
$ generate-pdfs
and foo1.pdf, foo2.pdf, etc. will be generated.
I thought that something like emacs --batch --eval <MAGIC> is a good start, but I don't know the magic.
A solution that is solely inside emacs could be of interest as well.
As you said, Emacs has the --batch option to perform operations with Emacs from the shell. In addition to that, you can use the -l flag to load Emacs Lisp code from a file and execute it, and the -f flag to execute a single Lisp function.
Here is a basic example, which exports a single org-mode file to HTML:
emacs myorgfile.org --batch -f org-html-export-to-html --kill
Perhaps you want something more advanced like exporting/publishing a full org-mode project. I do not have sample code for that, but it should not be too complicated.
I also have a sample Makefile I wrote some time ago to export all org-mode files in the directory to HTML (and also copy the HTML files to another directory):
OUT_DIR=/some/output/dir/html
# Using GNU Make-specific functions here
FILES=$(patsubst %.org,$(OUT_DIR)/%.html,$(wildcard *.org))
.PHONY: all clean install-doc
all: install-doc
install-doc: $(OUT_DIR) $(FILES)
$(OUT_DIR):
mkdir -v -p $(OUT_DIR)
%.html: %.org
emacs $< --batch -f org-html-export-to-html--kill
$(OUT_DIR)/%.html: %.html
install -v -m 644 -t $(OUT_DIR) $<
rm $<
clean:
rm *.html
EDIT:
With Org-mode 8 and the new export engine the function for HTML export has changed.
To make the previous examples work with Org 7 or older, replace org-html-export-to-html with org-export-as-html.
I expect to publish (by the end of this week-end) OrgMk, a suite of Makefile and standalone Bash scripts (usable as well under Cygwin) just to do that! Even more: generation of HTML, Ascii, Beamer, etc.
You'll find it on my GitHub account: https://github.com/fniessen/ (where I already have Emacs configuration files, color themes and other stuff such as an Org Babel refcard -- in progress).
Mark a few org files in dired and call this:
(defun dired-org-to-pdf ()
(interactive)
(mapc
(lambda (f)
(with-current-buffer
(find-file-noselect f)
(org-latex-export-to-pdf)))
(dired-get-marked-files)))
If you know what async is, wrap the call as it can take a while.
update:
Here's a version that combines the awesome dired approach with the lame
other one:)
(defun dired-org-to-pdf ()
(interactive)
(let ((files
(if (eq major-mode 'dired-mode)
(dired-get-marked-files)
(let ((default-directory (read-directory-name "dir: ")))
(mapcar #'expand-file-name
(file-expand-wildcards "*.org"))))))
(mapc
(lambda (f)
(with-current-buffer
(find-file-noselect f)
(org-latex-export-to-pdf)))
files)))

How to start in the middle of command input

How can I have emacs start and be in the middle of a command input? Particularly, I want emacs to start in the middle of a command input find-file with a message in the small buffer saying:
Find file: ~/
and the cursor at the last character of it so that I can continue typing the remaining path to open the file I want.
You can execute one of the following commands on the command prompt or make a shell script containing it appropriately:
$ emacs -f find-file # if you want to start Emacs in the current direcoty
$ (cd ~; emacs -f find-file) # if you want to start Emacs in your home diretory
From the emacs(1) man page:
-f function, --funcall function
Excute the lisp function function
I have to admit that my lisp is a bit rusty, but this works for me. Drop it in your ~/.emacs file (or whatever init file you are using):
(add-hook 'emacs-startup-hook
(lambda ()
(if (= (length command-line-args) 1)
(call-interactively 'find-file))))
If you call emacs with no arguments, like this:
sawa#localhost:~$ emacs
It will invoke find-file for you. If, on the other hand, you invoke emacs with an argument, such as a filename, like this:
sawa#localhost:~$ emacs somefile.txt
It will default to just visiting somefile.txt