Notes on Mastering Emacs: Chapter 6: The Practicals of Emacs
The following notes were taken while discussing Chapter 6 of the book Mastering Emacs by Mickey Petersen (2022 edition) in book discussion group meetings.
An index of notes for all chapters are available at notes.html.
Contents
- Exploring Emacs
- Project Management
- Xref
- Working with Log Files
- Highlighting
- Auto-Revert Mode
- Auto Revert Tail Mode
- Browsing Tarballs
- Dired: Thumbnail Image Browser
- DocView
- TRAMP
- EWW: Emacs Web Wowser
- Invoking External Browser
- Dired
- Shell Commands
- Compiling in Emacs
- Shells in Emacs
Exploring Emacs
The book suggests the following techniques to explore Emacs:
-
Reading the manual. For example, type
M-x info RET
orC-h i
, then navigate to theEmacs
hyperlink, then typeC-s version control RET
, and then navigate to the node namedVersion Control
to read the corresponding manual.Note that the section named The Info Manual in Chapter 3 offers more alternatives to reach a specific node in a more straightforward manner. For example,
C-h i m emacs RET m Version Control RET
accomplishes the same result. Alternatively,C-h R emacs RET m Version Control RET
also accomplishes the same result. Yet another way to accomplish the same result is to evaluate the Elisp expression(info "(emacs)Version Control")
. See section Info in chapter 3 notes for more details.Yet another way to explore the manual is to use the
info-apropos
command. For example, typeM-x info-apropos RET version control RET
to find manuals which have the string "version control" in them. -
Using apropos. For example, type
C-h d version control RET
to search for all symbols whose documentation string contains the specified pattern. Then typeC-h a ^vc- RET
to search for all commands that match this pattern. This is a convenient way to list the vc commands. Also, see section Apropos in chapter 3 notes for more details. -
Exploring prefix keys. For example, type
C-x v C-h
to list all key sequences bound to the prefix keyC-x v
. This is in fact a convenient way to list all the vc key bindings. Also, see section Discovering and Remembering Keys in chapter 3 notes for more details. -
Describe what a key does. For example, type
C-h k
followed byC-x v v
to see the command that is bound to the latter key sequence as well as its documentation string along with other details like the keymap where the key binding is found, the file where the command is defined, other key bindings for the same command, etc. See section Describe in chapter 3 notes for some more details. -
Describe commands. For example, type
C-h f vc-dir RET
to see information about thevc-dir
command. See section Describe in chapter 3 notes for some more details. -
Find mode commands. Type
C-h m
to see the documentation strings of the current major mode and minor modes. A brief summary of the minor modes is shown first, followed by the major mode description. This is followed by documentation strings of the minor modes separated by page breaks (the form feed character that is rendered as^L
in Emacs). See section Describe in chapter 3 notes for some more details. -
Type
M-X
to runexecute-extended-command-for-buffer
which executes commands that are relevant to the current buffer. While offering completions, it limits the completions to commands relevant to the current buffer. See section M-X: Execute Extended Command for Buffer of chapter 3 notes for more details.
Project Management
Emacs comes with a project management package
named project.el
which offers commands to operate on
projects. When we use a project management command like C-x p
f
to visit a file in the current project, this package
automatically detects the top-level directory of the project by
checking parent directories for version control system artifacts
(e.g., .git
directory) and presents files within that
top-level directory as autocomplete options.
The following complete key sequences demonstrate the package management commands mentioned in the book:
-
C-x p p ... TAB RET ~/git/foo/ RET f README.md
: This awkward key sequence discovers a new project directory at~/git/foo/
and then finds the file namedREADME.md
in it. As soon as the key sequencef
is typed above, the new project directory is discovered and added to~/.emacs.d/projects
which is where the list of known projects is saved. -
C-x p p bar TAB RET f Makefile
: Assuming there is already a known project withbar
in its name (say,~/git/bar/
) that was discovered earlier, this key sequence switches to that project and finds the file named inMakefile
in it. -
C-x p f dev/build.sh RET
: Find file nameddev/build.sh
in the current project. -
C-x p f build TAB RET
: Same as above ifdev/build.sh
is the only match forbuild
. Otherwise, it presents all files in the current project containingbuild
anywhere in its path name as autocomplete options. -
C-x p f bar TAB RET build TAB RET
: When we typeC-x p f
while visiting a file that does not belong to any project, then its prompts for a project name. In this example, we typebar TAB RET
to automatically expand it to a known project name such as~/git/bar/
and enter it. Then we typebuild TAB RET
to automatically expand it to a file name such asdev/build.sh
and enter it.It is worth noting a general point that whenever we invoke a project command while visiting a file that does not belong to a project, the project command prompts for the project name. After we enter the project name, the project command runs on our chosen project. This general point applies to other project commands that come later in this list.
-
C-x p b Makefile RET
: Switch to a buffer namedMakefile
in the current project. While entering the buffer name whenTAB
is typed, completion options present buffer names from the current project only. -
C-x p k yes RET
: Kill all buffers belonging to the current project. -
C-x p g ^key\> RET
: Find all matches for the regular expression^key\>
in the current project. The matches are found in all files in the project regardless of whether they are currently open in Emacs or not. The matches are displayed in a buffer named*xref*
. We can navigate this buffer using key sequences liken
,p
, etc. TypeC-h m
in this buffer to see a list of key sequences supported in this buffer. As we navigate this buffer and go from one match to another usingn
,p
, etc. the files containing the match are loaded in a split window automatically with the matching lines automatically centred in that window. -
C-x p r ^key\> RET =key= RET
: Find all matches for the regular expression pattern^key\>
in the current project and replace them with=key=
. The modified files are not automatically saved though. They needed to be saved later explicitly. -
C-x p c RET
: Compiles the current project. By default, it offers asmake -f
as the command to be run in the project root. If a specificmake
target needs to be executed or if another command needs to be executed, then the default command offered may be edited before typingRET
. -
C-x p v
: Runs VC-Dir in the current project's root which in turn shows version control status for the project root. -
C-x p s
: Start shell in the current project's root directory. -
C-x p d RET
: Start Dired in the current project's root directory. -
C-x p D
: Same as above. -
C-x p d doc/tutorial/ RET
: Start Dired in thedoc/tutorial/
subdirectory in the current project.
There are several more project management key bindings.
Type C-x p C-h
to see a complete list of them.
Xref
Xref provides a generic framework to support commands for cross-referencing in Emacs. While there are several ways to set it up and configure it, the book mentions a particular way to set it up using a couple of external tools. The next two subsections discuss the setup work involved before we can use Xref in a modern way. The remaining subsections discuss how to use Xref.
Xref Setup
By default when we try to look up a definition of an identifier in,
say, a C file or Python file, by typing M-.
, it
presents a minibuffer for us to select a tags table file (typically
named TAGS
). This requires setting up
a TAGS
file with a tool like ctags
. The
book, however, does not explore this method for good reason.
Typically the TAGS
file needs to be created with a tool
like ctags
or etags
for every project we
work on. This file contains an index of names found in source code
files. We need to periodically update it as the code of our
projects evolve, so that this index remains up-to-date. For a long
time, this was the only way to maintain an index of the names found
in a source code, so that we could perform cross-referencing in
editors like Vim and Emacs. Relying on a tool
like grep
to search the code on the fly was deemed to
be quite slow. However, with modern, fast hardware we do not have
to work like this anymore. Further, there are search tools
like ag
and rg
which are extremely fast.
Given these modern developments, there are simpler ways to set up
cross-referencing in Emacs.
The book suggets installing an external package
named dumb-jump
. It can be installed from MELPA with
the key sequence M-x package-install dumb-jump RET
.
See github.com/jacktasia/dumb-jump
for more details about this package. After installing this package,
add the following code to the Emacs initialisation file:
(add-hook 'xref-backend-functions #'dumb-jump-xref-activate)
Here is a minimal Elisp code that sets up dumb-jump
from scratch and configures it as mentioned above:
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
(unless package-archive-contents
(package-refresh-contents))
(dolist (package '(dumb-jump))
(unless (package-installed-p package)
(package-install package)))
(add-hook 'xref-backend-functions #'dumb-jump-xref-activate)
The above code configures Emacs to use MELPA, retrieve the latest
list of packages available there, install dumb-jump
from it, as well as set up a hook to activate it automatically when
we use certain Xref commands.
Search Tools for Xref
Once Xref is set up with dumb-jump
as explained in the
previous section, open a source code file (say, a C file or a Python
file), move the cursor over to some identifier and
type M-.
to search that identifier in your environment.
By default, it searches for the identifier in files of the same type
found under the home directory with a tool like ag
,
rg
, or grep
(the first one it finds).
There is an exception to this rule though. If
neither ag
nor rg
is found and only GNU
grep is found, then typing M-.
on an indentifier
searches the identifier in all files in the home directory (as
opposed to searching for files of a specific type). If BSD grep is
found instead, then this is not a problem and only files of the
current type is searched for the identifier.
Further, while looking up definitions within a Git repository, this
package invokes the git grep
command to restrict
searches to the repository directory.
Let us now look at a few examples of the actual search commands that
are executed under the hood when we type M-.
.
If neither ag
nor rg
is installed and we
only have grep
on our system, typing M-.
while the cursor is on an identifier named foo
in a
Python file leads to the execution of a command like this when BSD
grep is found:
grep -REn --include '*.py' -e '\s*\bfoo\s*=[^=\n]+' -e 'def\s*foo\b\s*\(' -e 'class\s*foo\b\s*\(?' /Users/susam
If GNU grep is found instead, then all files (not
just *.py
files) are searched with a command like this:
grep -rEn -e '[[:space:]]*\bfoo[[:space:]]*=[^=\n]+' -e 'def[[:space:]]*foo\b[[:space:]]*\(' -e 'class[[:space:]]*foo\b[[:space:]]*\(?' /home/susam
If rg
is the only additional search tool installed,
then the following command is executed:
rg --color never --no-heading --line-number -U --pcre2 --type py '\s*\bfoo\s*=[^=\n]+|def\s*foo\b\s*\(|class\s*foo\b\s*\(?' /home/susam
If ag
is installed, then the following command is
executed:
ag --nocolor --nogroup --python '\s*\bfoo\s*=[^=\n]+|def\s*foo\b\s*\(|class\s*foo\b\s*\(?' /home/susam
When we type M-.
in a file that belongs to a Git
repository, only the repository directory is searched with a command
like this:
git grep --color=never --line-number --untracked -E '\s*\bfoo\s*=[^=\n]+|def\s*foo\b\s*\(|class\s*foo\b\s*\(?' -- /home/susam/repo/*.py
The book makes a mention of rg
and remarks about the
impressive speed with which it searches the file system. I
recommend it too. Since the M-.
command may search the
whole home directory, if the home directory is very large, having a
fast search tool like rg
or ag
makes a
significant difference. For example what could normally take 10 to
20 seconds to search using grep
might only take a
second or two with rg
or ag
. I
use M-.
with rg
.
Four Most Common Xref Commands
The book mentions the following commands as the four most common commands we should know about:
-
M-.
: Find definitions of the identifier at point. If a unique definition is found, then the file containing the definition is automatically opened and the definition is centred in the window. If multiple possible candidates are found, then they are displayed in an Xref buffer that we can navigate using key sequences liken
orp
. As we navigate the Xref buffer, the source of each match is automatically opened in a split window and the matching line is centred. -
M-,
: Go back to whereM-.
was last invoked. -
M-? foo RET ~/git/foo/ RET
: Find all occurrences of the wordfoo
in files of the same type as the current file in the project directory~/git/foo/
. It does not restrict the search to definitions only. If the current file belongs to a project already, then we could simply typeM-? foo RET
. In fact, since the input to the minibuffer prompt is the identifier at the point by default, we could simply typeM-? RET
to search for the current identifier in the current project. -
C-M-. foo RET
: Find symbols matching the given pattern. Although the documentation mentions that this supports regular expressions, it seemed to treat the given pattern as an identifier and searched for that identifier literally. In fact, therg
commands that were executed under the hood were exactly the same as the ones executed byM-.
. Thus withdumb-jump
enabled, bothM-.
andC-M-.
behave similarly. The only difference is thatM-.
searches for the identifier at the point whereasC-M-.
searches for the identifier we enter at the minibuffer as input.
When multiple cross-references are displayed in the Xref buffer, we can use the following key sequences to work with the Xref buffer.
-
n
: Move to the next cross-reference. The source of the cross-reference is automatically displayed in another window. -
n
: Move to the previous cross-reference. The source of the cross-reference is automatically displayed in another window. -
.
: Same asn
. -
,
: Same asp
. -
RET
: Jump to the source of the current cross-reference. -
TAB
: Hide Xref buffer and jump to the source. -
C-o
: Show the source of the cross-reference at point in a separate window but keep the point in the Xref window. This is useful when we navigate the Xref buffer using normal Emacs commands likeC-p
,C-n
,C-s
, etc. While navigating the Xref buffer with these normal Emacs commands, the source of the cross-references at the point is not automatically displayed. The key sequenceC-o
helps us to display the cross-reference at the point in this case. -
r
: Perform search and replace in the names of the references displayed in the Xref buffer. However, I did not find this to be working successfully withdumb-jump
. Any attempt to use this command withdumb-jump
always led me to the following error:No suitable matches here
. This key sequence does work as expected when Xref is invoked from Dired as going to be explained in the next section.
Xref and Dired
Here are some key sequences that demonstrate how we can use Xref with Dired.
-
C-x d RET
: Edit current directory using Dired. -
n
: Move to the next line.C-n
also works. -
p
: Move to the previous line.C-p
also works. -
m
: Mark the file or subdirectory at the point. -
u
: Unmark the file or subdirectory at the point. -
A f.. RET
: Find all matches for the regular expressionf..
in the marked files and subdirectories. The matches are always displayed in an Xref buffer, even when a single match is found. -
Q f.. RET bar RET
: Find all matches for the regular expressionf..
in the marked files and subdirectories and replace them withbar
.
Working with Log Files
In this section of the book, it discusses a set of commands that are useful for working with log files. Note that some of these commands have been already introduced in the previous chapters. The following list presents the commands discussed in this section of the book:
-
C-x C-f
: Find a file. -
C-x C-r
: Find file and open in read-only mode. -
C-x C-q
: Toggle read-only mode. -
M-x flush-lines RET b.. RET
: Delete lines in region that match the regular expressionb..
. If no region is active, then delete matching lines between the point and end of buffer. The deleted lines are not copied to kill ring. See section Deleting and Keeping Lines of chapter 5 notes for more details. -
M-x keep-lines RET b.. RET
: Keep lines in region that match the regular expressionb..
and delete the rest. If no region is active, then keep matching lines between the point and end of buffer, and delete the rest. The deleted lines are not copied to kill ring. See section Deleting and Keeping Lines of chapter 5 notes for more details. -
M-s o b.. RET
: Show all lines in the current buffer matching the regular expressionb..
. If the region is active, then show matching lines from the region only. The matches are shown in a new Occur mode buffer. The book makes a special mention that we can runM-s o
on an Occur mode buffer to filter it further and get the results in another Occur mode buffer. See section Occur Mode in chapter 4 notes for more details.
Highlighting
Section Working with Log Files of Chapter 6 of the book also introduces highlighting commands that can be very useful for highlighting certain strings in the log file. The highlighting commands are demonstrated below with an example.
-
First create a buffer with the following content.
foo bar baz Foo Bar Baz FOO BAR BAZ foo bar baz Foo Bar Baz FOO BAR BAZ
-
Now type
M-s h p f.. SPC b.. RET RET
to highlight the phrases matching the regular expressionf.. b..
in a case-insensitive and whitespace-insensitive manner. A total of six matches will be highlighted because the first two words and the whitespace between them in all lines match this phrase pattern when we ignore the case of the words and the amount of whitespace. The secondRET
is meant to accept the default face offered to us for highlighting. -
Now type
M-s h p b.z RET RET
to highlight the phrases matching the regular expressionb.z
. Again we select the default face offered to us for highlighting. At this point, we should see two sets of highlighting in two different faces. -
Now move the cursor to one of the first set of highlights and type
M-s h u RET
. Those highlights will be unhighlighted. TheRET
key accepts the default unhighlighting pattern offered to us. It happens to be the pattern with which the highlight under the cursor was highlighted. That is why this key sequence ends up unhighlighting the highlight under the cursor.If the cursor were not over a highlgiht, then the default unhighlighting pattern offered to us would have been the pattern we used for the last highlight. In that case, we could type
M-s h u f.. b.. RET
to explicitly specify the unhighlighting pattern. -
Now type
M-s h u RET
again to remove the second set of highlights too. -
Type
M-s h p F.. SPC B.. RET RET
to perform a case-sensitive but whitespace-insensitive highlighting. When there is an uppercase letter in the pattern, the highlighting becomes case-sensitive. -
Type
M-s h u RET
to remove the previous highlighting. -
Type
M-s h r f.. SPC b.. RET RET
to perform a case-insensitive but whitespace-sensitive highlighting. This time, there are only three matches from the first three lines. -
Type
M-s h u RET
to remove the previous highlighting. -
Type
M-s h r F.. SPC B.. RET RET
to perform a case-sensitive and whitespace-sensitive highlighting. The matching strings are found in the second and third lines. -
Move the cursor to lowercase
bar
and typeM-s h .
to highlight symbol at point. All six occurrences of this symbol are highlighted in a case-insensitive manner because the symbol at point is written in all lowercase. -
Move the cursor to
Baz
and typeM-s h .
to highlight symbol at point. Only two occurrences of this symbol get highlighted. The highlighted symbols match the symbolBaz
exactly (case-sensitive match). The highlighting is done in case-sensitive manner because the symbol at point has at least one uppercase letter.
Auto-Revert Mode
The following steps demonstrate how to use
the revert-buffer
command and then how to
use auto-revert-mode
.
-
In a terminal, run the following command:
: > /tmp/log.txt && while true; do date >> /tmp/log.txt; sleep 1; done
You could use
ansi-term
within Emacs too as the terminal if you are familiar with it. -
Now within Emacs, type
C-x C-f /tmp/log.txt RET
. -
Wait for a few seconds and type
M-x revert-buffer RET yes RET
to update the buffer with the latest content of the file from the file system. -
Type
M-x auto-revert-mode RET
to enable automatic update of the buffer as the file changes on the file system. Note that this reloads the entire file whenever a change is detected, so this could be inefficient while working with very large files. -
Type
M->
to go to the end of the buffer. This moves the cursor to the end of the buffer. Doing this ensures that as the buffer is automatically updated, the cursor automatically keeps moving to the end of the file. -
Terminate the command of step 1 and run this command in a terminal:
echo hello > /tmp/log.txt
The content of the buffer should now automatically truncate and update to just the text
hello
. -
Run the command in step 1 again and confirm that the content of the buffer in Emacs gets updated automatically.
-
Type
M-x auto-revert-mode RET
to disable automatic update of the buffer.
Auto Revert Tail Mode
The mode named auto-revert-tail-mode
is similar
to auto-revert-mode
. However,
unlike auto-revert-mode
which reloads the entire file
on every update, the auto-revert-tail-mode
only follows
the tail of the buffer and appends any new text found to the buffer.
The following steps demonstrate this:
-
Like in the previous section, run the following command:
: > /tmp/log.txt && while true; do date >> /tmp/log.txt; sleep 1; done
-
Type
M-x auto-revert-tail-mode RET
. Note that this command follows the tail of the file only. It does not reload the entire file. This can be confirmed with the next step. -
Terminate the command of step 1 and run this command in a terminal:
echo hello > /tmp/log.txt
The buffer for this file in Emacs should automatically update to show the text
hello
at the bottom. But notice all the earlier text remains intact. The earlier text does not disappear from the buffer because Emacs does not reload the entire file whenauto-revert-tail-mode
is enabled. -
Run the command in step 1 again and confirm that the content of the buffer begins to get updated automatically again.
-
As of Emacs 28.2, unfortunately running
M-x auto-revert-tail-mode RET
is not sufficient to disable automatic updates in the buffer. This command does disable the mode but the buffer continues to be updated everytime the file changes. This is very likely a bug in this mode.As a workaround, disabling
auto-revert-mode
ends up stopping the auto-update behaviour. There are two ways to do this. You could typeM-x auto-revert-mode RET
twice: once to enable it and a second time to disable it. Alternatively, just simply typeC-0 M-x auto-revert-mode RET
which invokes the mode with a prefix argument of zero which ends up disabling the mode.
Browsing Tarballs
The following steps demonstrate how we can not only browse a tarball but also edit files in it and save them back to the tarball.
-
First, create a directory of text files with the following shell commands:
mkdir -p foo/bar/baz/ echo hello foo > foo/foo.txt echo hello bar > foo/bar/bar.txt echo hello baz > foo/bar/baz/baz.txt tar -caf /tmp/foo.tgz foo/
-
Confirm that the tarball looks good with these shell commands:
tar -tf /tmp/foo.tgz tar -xOf /tmp/foo.tgz
-
Within Emacs, type
C-x C-f /tmp/foo.tgz RET
to open the tarball. A list of all entries in the tarball is displayed in a Tar buffer. -
Type
n
andp
to navigate the Tar buffer down and up, respectively. -
With the cursor on the line containing
foo/bar/baz/baz.txt
, typeRET
. The content of this entry is now displayed in a new buffer. -
Now in the buffer that displays the content of
baz.txt
, edit its content. Say, typeC-a !
to append an exclamation point to this buffer. -
Type
C-x C-s
to save this buffer. This updates the entry offoo/bar/baz/baz.txt
within the buffer forfoo.tgz
. However, the updated tarball is not written to the file system yet. -
Type
C-x b foo.tgz RET
to go back to the buffer with the tarball entry listing. -
Finally, type
C-x C-s
to save the tarball to the file system. -
Now repeat step 2. The updated content of
foo/bar/baz/baz.txt
should now appear in the output.
Dired: Thumbnail Image Browser
Assuming there is a directory ~/foo/
that contains
several image files as well as files of other types, the
command M-x image-dired RET ~/foo/ RET
creates a
preview buffer of all images in the directory and displays it along
with a normal dired buffer showing the directory listing. Both
buffers are displayed in two separate windows.
When the preview buffer is first launched, all image files found in
the directory are automatically marked. This can be seen
in the Dired buffer. However the preview buffer does not reflect
this immediately. Type m
in the preview buffer to
force it to pick the current list of marked images and highlight
them.
As a best practice, remember to type m
soon after
launching image-dired
so that the marked images are
accurately displayed in the preview buffer.
Within the preview buffer, the following key sequences are supported:
-
C-f
: Move to next image. -
C-b
: Move to the previous image. -
C-n
: Move to next row of images. -
C-p
: Move to previous row of images. -
RET
: Display the original image in a display buffer. -
m
: Mark an image file. -
u
: Unmark an image file. -
d
: Flag an image file for deletion. -
t t
: Tag marked thumbnails. If no thumbnails are marked, tag the current thumbnail. -
t r
: Remove tag from marked thumbnails. If no thumbnails are marked, remove tag from the current thumbnail. -
l
: Rotate thumbnail left. -
r
: Rotate thumbnail right.
Preview Buffer Quirks
The m
, u
, or d
commands in
the preview buffer are actually meant to mark, unmark, or flag the
corresponding files in the Dired buffer. The highlighting or
unhighlighting that occurs in the preview buffer is merely a
convenience feature. The preview buffer may not always accurately
reflect the most recent list of all marked and flagged files.
Always keep an eye on the Dired buffer to check the most recent
state of the files.
Especially, if we go back to the Dired buffer and mark, unmark, or
flag files, the preview buffer does not reflect it automatically.
We need to go to the preview buffer again and perform at least one
similar operation (m
, u
,
or d
) in the preview buffer for it to be updated again.
This is why it is important to keep an eye on the Dired buffer to
get an accurate account of which files are marked or flagged.
Working on Marked Files
Say we have marked some image files using the key
sequence m
in the preview buffer. Now we can perform
various operations on these marked files. For example, to copy the
marked files to /tmp/
directory, in a Dired buffer,
type C /tmp/ RET
. To move them instead, type R
/tmp/
.
Deleting Images
When we flag thumbnails by typing d
in the preview
buffer, the corresponding files are flagged for deletion in the
Dired buffer. The first column of the flagged file entries contain
the letter D
in the Dired buffer. Type x
in the Dired buffer to permanently delete (expunge) the flagged
files.
Tagging and Untagging
If there are marked images, then the tagging and untagging commands executed in the preview buffer work on those marked images. Otherwise, they work on image corresponding to the current thumbnail. We will refer to these images that the tagging or untagging commands work on as target images in the next few paragraphs..
The key sequence t t trip;oxford;uk RET
tags the target
images with the tags trip
, oxford
,
and uk
. The tags must be separated by semicolon as
shown in the preceding example. The tags are saved in a path set in
the image-dired-db-file
variable. Type C-h v
image-dired-db-file
to read this path. Typically, it is
something like ~/.emacs.d/image-dired/.image-dired_db
.
We will call this the DB file. This file may be manually inspected
to see how this command and the next command affect the tags for
each thumbnail. Alternatively, type C-t e
in a Dired
buffer to view and edit the tags of the target files.
The key sequence t r trip RET
removes the
tag trip
from the target images. By virtue of how this
functionality is implemented, a key sequence like t r
t.*d
removes the tags trip;oxford
and trip;salford
(if present) from the DB file but it
does not remove a tag like trip;cambridge
(if present).
Using Tags
Tagging thumbnails could be useful if we want to later mark files by
tags. In a Dired buffer, the key sequence C-t f t.*d
will mark all files whose thumbnails have tags (as they appear in
the tags file) matching the regular expression t.*d
.
For example, images that have with tags trip;oxford;uk
as well as trip;london;uk
will be marked but images
with tags trip;bath;uk
and trip;liverpool;uk
will not be marked.
Display Buffer
When we type RET
in the preview buffer, the original
image is displayed in a display buffer. The following key sequences
are supported in the display buffer:
-
s
: Resize image to fit window. -
f
: Display current image in full size. -
q
: Quit window.
The book makes a note that when we open an image file directly from
a Dired buffer, the image is opened in image-mode
which
is more powerful than the display buffer we get when we open an
image from the thumbnail preview window.
DocView
When a PDF or another document of a supported format is opened in
Emacs, they are converted to images on the fly and displayed in
Emacs. In this section, we will discuss working with PDFs only.
The converted images are cached at the directory set in
the doc-view-cache-directory
variable.
Type C-h v auto-mode-alist RET
and search
for doc-view
in the help buffer to see the list of file
formats that Emacs tries to open in DocView.
Ghostscript needs to be installed so that DocView can convert the
PDF into images. Further, for some commands where we perform
text-based operations on the PDF, we need the pdftotext
command so that DocView can extract text from the PDF.
Type C-h v doc-view-ghostscript-program RET
and C-h v doc-view-pdftotext-program RET
to see the
external programs that DocView depends on. These programs can be
installed with the following command on a Debian or Debian-based
Linux distribution:
apt-get install ghostscript poppler-utils
On a macOS system, run the following command instead:
brew install ghostscript poppler
The following list presents some of the key bindings supported by DocView:
-
n
: Go to next page. -
p
: Go to previous page. -
C-x ]
: Same asn
. -
C-x [
: Same asp
. -
SPC
: Scroll up if possible or go to next page. -
DEL
: Scroll down if possible or go to the previous page. -
S-SPC
: Same as above. -
M-<
: View the first page. -
M->
: View the last page. -
+
: Enlarge the document. -
-
: Shrink the document. -
0
: Reset the document size to the initial one. -
W
: Fit the image width to the window width. -
H
: Fit the image height to the window height. -
P
: Fit the image to the window such that neither the document width nor the document height exceed the window width or height, respectively. -
F
: Resize the window so it just fits the page. When there is only window in the frame, the window cannot be resized independently of the frame, so the frame is resized instead. -
M-x doc-view-presentation RET
: Display document in presentation mode, i.e., as a full screen slide show.
Although not mentioned in the book, here are some commands that show
how to perform text-based operations on the PDF. These commands
need pdftotext
to be installed.
-
C-s ^f..\> RET
: Initiate a new search for lines that begin with a three-lettered word beginning with the letterf
. The cursor does not move to the first match automatically. To make the cursor move to the first match, typeC-s
. This is also explained in the next point. -
C-s
: When a search has been initiated, jump to the next match for the last search that was initiated. -
C-u C-s ^b..\> RET
: Initiate a new search. This is useful when a search was already initiated and we want to abandon that search and start another new search. -
C-r
: Similar toC-s
but works in reverse direction. All three commands mentioned above work withC-r
too. -
C-t
: Show tooltip for the current location. Normally, this shows a tooltip like "Page 100 of 314" to describe the current page. When a search is in progress, the tooltip includes all the matches from the current page too. -
C-c C-t
: Show the current document's content as text. Then type the key sequenceC-c C-c
to switch to editing the document andC-c C-c
again to switch to viewing the document. The key sequenceC-c C-c
is elaborated a little more in the next point. -
C-c C-c
: Toggle between editing or viewing the document. In case of PDF, switching to editing the document may not be very helpful because the binary code of the document is opened for editing in this mode which is quite non-trivial to edit directly.
DocView Resolution
If the text in the document looks pixelated in Emacs, set
the doc-view-resolution
variable to 300 as follows:
(setq doc-view-resolution 300)
This sets the dots per inch resolution used to render the documents to 300. This offers a good trade-off between high quality rendering and fast rendering. After setting this variable, type the following key sequences:
-
M-x doc-view-clear-cache RET
to delete the cache directory. -
C-x k
to kill the existing DocView buffer (if any). -
C-x C-f document.pdf RET
to open the document (saydocument.pdf
) again!
Clearing the cache directory and reopening the document in this manner regenerates the images from the documents with the updated resolution.
TRAMP
TRAMP stands for Transparent Remote Access, Multiple Protocol. The general syntax of paths supported by TRAMP is:
/method:[user@][hostname[#port]]:[path]
Here are some complete key sequences that demonstrate various ways to open a remote file using TRAMP:
-
C-x C-f /ssh:alice@box:~/foo.txt RET
: Edit file in a remote host via SSH. -
C-x C-f /ssh:susam@box#22:~/foo.txt RET
: Same as above. However the port is explicitly specified this time. -
C-x C-f /scp:alice@box:~/foo.txt RET
: Edit file in a remote host via SCP. -
C-x C-f /ssh:box:~/foo.txt RET
: Edit file in a remote host via SSH after logging into it with the username of the current user in the current shell. -
C-x C-f /ssh:alice@:~/foo.txt RET
: Edit file in localhost via SSH after logging into it as a specific user. -
C-x C-f /ssh::~/foo.txt RET
: Edit file in localhost via SSH after logging into it with the username of the current user in current shell. -
C-x C-f /sudo::/etc/hosts
: Edit file as superuser. -
C-x c-f /sudo:alice@:~/foo.txt RET
: Edit file as a specific user. -
C-x C-f /sudoedit::/etc/hosts
: Edit file as superuser but do not keep an open session running in the background for security reasons. This method has worse performance than thesudo
method. -
C-x C-f /su::/etc/hosts
: Edit file as theroot
user. -
/su:alice@:~/foo.txt
: Edit file as a specific user. -
/su:alice@localhost:~/foo.txt
: Same as above. -
C-x C-f /sudo:: RET
: Browse theroot
user's home directory as superuser. -
C-x C-f /su:: RET
: Browse theroot
user's home directory with Dired. -
C-x C-f /-:: RET
: Usetramp-default-method
(scp
by default) to connect totramp-default-host
(currenthostname
by default). With the default values of these variables, this leads to connecting to the local system as the current user via SCP and browsing the current user's home directory in Dired.
This chapter recommends looking up the info manual
page (tramp) Internal methods
but this is very likely
an error. For example, evaluating (info "(tramp)Internal
methods")
leads to the following error:
user-error: No such node or anchor: Internal methods
Instead evaluate (info "(tramp)Inline methods")
to
reach the correct node that describes the various connection
methods.
Default Directory
The variable default-directory
is buffer local.
Typically, this is automatically set to the directory where Emacs
was launched or to the directory of the currently visited file.
Commands like C-x C-f
defaults to looking up files in
this directory.
While editing a remote file via TRAMP, the value for this variable
may look something like /ssh:alice@box:/home/alice/
.
The @
character is displayed in the mode line while
editng a remote file.
The chapter presents the following examples of commands that work seamlessly on a remote machine:
-
C-x d
: Manage remote files and directories. We can even copy files (using the key sequenceC
) between remote and local dired sessions. -
M-x compile RET RET
: Runmake -k
(the default) or an arbitrary command remotely. The result is shown in the*compilation*
buffer. -
M-x rgrep RET f.. RET *.txt RET RET
: Usefind
andgrep
together to search for the patternf..
in files matching the pattern*.txt
in the current remote directory. -
M-x shell RET
: Open shell on the remote system in the current remote directory. -
M-x eshell RET
: Open Eshell on the remote system in the current remote directory.
With Eshell we can go directly into remote directories seamlessly. The following Eshell session illustrates this:
Welcome to the Emacs shell ~ $ uname Darwin ~ $ cd /ssh:alice@box:~/foo/ /ssh:alice@box:/home/alice/foo $ hostname debian /ssh:alice@box:/home/alice/foo $
Multi-Hops
Here are some commands that illustrate how multi-hops work:
-
C-x C-f /ssh:alice@box|ssh:bob@localhost:~/foo.txt RET
: First log in asalice
intobox
and then from there log in asbob
into the same system. -
C-x C-f /ssh:alice@box|sudo:box:/etc/hosts RET
: First log in asalice
intobox
and then edit file as superuser. -
C-x C-f /ssh:alice@box|sudo::/etc/hosts RET
: Same as above. -
C-x C-f /ssh:alice@box|sudo:bob@box:~/bar.txt RET
: First log in asalice
intobox
and then usesudo
to edit file asbob
in the latter user's home directory. -
C-x C-f /ssh:alice@box|su::/etc/hosts RET
: First log in asalice
intobox
and then edit file asroot
. -
C-x C-f /ssh:alice@box|su:bob@:~/bar.txt RET
: First log in asalice
intobox
and then edit file asbob
. -
C-x C-f /ssh:alice@box|su:bob@box:~/bar.txt RET
: Same as above. -
C-x C-f /ssh:alice@box1|ssh:bob@box2|ssh:carol@box3:~/foo.txt
: An example of two hops.
Bookmarks with key sequences like C-x r m
(bookmark-set
), C-x r l
(bookmark-bmenu-list
), and C-x r b
(bookmark-jump
) work seamlessly for remote files
(including multi-hops).
Eshell works seamlessy too across multi-hops. Here is an Eshell session that illustrates it:
~ $ uname Darwin ~ $ cd '/ssh:alice@box1|ssh:bob@box2|ssh:carol@box3:/home/carol/foo/bar/' /ssh:alice@box1|ssh:bob@box2|ssh:carol@box3:/home/carol/foo/bar $ uname Linux /ssh:alice@box1|ssh:bob@box2|ssh:carol@box3:/home/carol/foo/bar $
EWW: Emacs Web Wowser
The following commands are useful to get started with EWW.
-
M-x eww RET hello RET
: Search for the word "hello" with DuckDuckGo. If the buffer*eww*
already exists, then reuse that buffer, otherwise create such a buffer. The search engine can be customised by setting the variableeww-search-prefix
(it is"https://duckduckgo.com/html/?q="
by default). -
C-u M-x eww RET hello RET
: Like previous command except that it creates a new EWW buffer. -
M-x eww RET example.net RET
: Visit the URL http://example.net. Reuses the*eww*
buffer if it exists. -
M-x eww RET http://example.net/ RET
: Same as above. -
C-u M-x eww RET example.net RET
: Like before but creates a new EWW buffer.
In the EWW buffer, the following navigation keys work:
-
TAB
: Skip to the next link. -
S-TAB
orC-M-i
: Skip to the previous link. -
RET
: Browse the URL under point. -
C-u RET
: Browse the URL under point using an external browser. This is especially useful when we know that the URL we want to open does not render well in EWW. -
&
: Open the current page in an external browser. Note that unlike the previous command, this command opens the current page. The previous command opens the URL under point instead. -
q
: Quit EWW. -
l
: Go to the previously displayed page. -
r
: Go to the next displayed page. -
b
: Bookmark the current page. -
B
: Show bookmarks. -
H
: Show history of the current EWW buffer. The most recently visited URLs are displayed on top and the oldest ones are shown at the bottom. The current URL is not displayed in the history. Only the older URLs are shown in the history. -
R
: View the main "readable" parts of the current page. This command uses heuristics to find the parts of the web page that contains the main content and omits the non-content part like navigation menus etc. -
M-s M-w
: Search the web for the text in the region. If there is no region, then prompt for a search string. -
M-RET
: Open link in a new EWW buffer. -
s
: Prompt for an EWW buffer to display and switch to the selected buffer. This is similar to changing to tabs in a desktop web browser. -
w
: If the point is on a URL or just after a URL, then copy that URL to the kill ring. If the point is at any other place, copy the URL of the current page.
Further, EWW supports a few semantic browsing methods. The pertaining commands are presented below. However note that whether these commands would work on a page or not depends on whether the page provides the relevant navigation aids required by these commands. Here are the key sequences for such commands:
-
p
: Go to the page marked previous. A page is marked previous if there is a<link>
tag or an<a>
tag for it with the attributerel="prev"
(a standard value for the attribute) orrel="previous"
(non-standard value supported by EWW). -
n
: Go to the page marked next. A page is marked next if there is a<link>
tag or an<a>
tag for it with the attributerel="next"
. -
u
: Go to the page marked up. A page is marked up if there is a<link>
or an<a>
tag for it with the attributerel="up"
. -
t
: Go to the page marked top. A page is marked top if there is a<link>
tag or an<a>
tag for it with the attributerel="start"
orrel="home"
orrel="contents"
.
Invoking External Browser
If we would rather open a URL using our desktop web browser, then we
can use the browse-url
command like this: M-x
browse-url RET http://example.net/ RET
.
This command very conveniently picks up the word or domain name at
the point or just before the point and uses that as the default
value for the URL input. Therefore if the cursor is already on a
URL, then we can simply type M-x browse-url RET RET
to
visit it.
Dired
Dired: Getting Started
There are several ways to start Dired. Some examples are presented below:
-
C-x C-f ~/foo/bar/ C-d
: If IDO or FIDO mode is enabled, then this key sequence automatically opens Dired in the given directory path. Essentially, while usingC-x C-f
with IDO/FIDO mode, we can typeC-d
anytime and Dired is opened in the path entered so far. -
M-x dired RET ~/foo/bar/ RET
: Opens Dired in the given directory path. -
M-x dired RET RET
: In the previous command, the default input is the path of the current directory (default-directory
), so this key sequence conveniently opens Dired in the current directory. -
C-x d
: Same as above. -
C-x 4 d
: Like before but open Dired in another window.
Dired: Navigation
The following keys work in a Dired buffer:
-
RET
: Visit the file or directory on the current line. -
^
: Go up by one directory. If the parent directory is found in an existing buffer, then switch to that buffer. Otherwise create a new buffer to show the parent directory in Dired. -
q
: Quit Dired window. The buffer remains intact, i.e., the buffer is only buried, not killed. -
C-u q
: Quit Dired window and kill the buffer. -
p
orC-p
: Move to the previous line and position the point on the filename. -
n
orC-n
: Move to the next line and position the point on the filename.
Note that when we go from one Dired buffer to another (say, by
typing RET
to enter a subdirectory from a parent
directory), then typing q
or C-u q
buries
or kills (respectively) the current buffer and takes us back to the
last Dired buffer.
Dired: Marking and Unmarking
The following list describes marking and unmarking commands of Dired:
-
m
: Mark the file or directory at point. If the region is active, mark all files or directories in the region. Note that at least one character of the filename or directory name must lie within the region for a file to be marked. -
u
: Unmark the file or directory at point. If the region is active, unmark all files or directories in the region. Note that this also removes the flag for deletion (introduced later in this list). -
U
: Unmark everything. Note that this also removes flags for deletion. -
d
: Flag the file or directory for deletion. If the region is active, flag all files or directories in the region for deletion.
The following key sequences describe the effects of prefix arguments with marking, unmarking, and flagging commands:
-
C-5 m
: Mark 5 files from the current line to 4 more lines below. -
C-5 u
: Unmark 5 files from the current line for deletion.. -
C-5 d
: Flag 5 files from the current line for deletion. -
C-- C-1 m
: Mark the file on the previous line. -
C-- C-1 u
: Unmark the file on the previous line. -
C-- C-1 d
: Flag the file on the previous line for deletion. -
C-- C-5 m
: Mark files in the 5 previous lines. -
C-- C-5 u
: Unmark files in the 5 previous lines. -
C-- C-5 d
: Flag files in the 5 previous lines for deletion.
Additionally, the chapter mentions the following commands in a separate table but on Emacs 28.2, they seem to have the same effect as one of the commands discussed earlier:
-
* m
: Behaves the same asm
and marks files. -
* u
: Behaves the same asu
and unmarks files.
However the following commands (also introduced briefly in the same table but illustrated with complete key sequences below) provide additional marking and unmarking facilities:
-
* % f.. RET
: Mark files with names that match the regular expressionf..
. If the region is active, then only the files in the region that match the pattern are marked. The directories.
and..
are never marked. -
% m f.. RET
: Same as above. -
C-u * % f.. RET
: Unmark files with names that match the regular expressionf..
. If the region is active, then only the files in the region that match the pattern are unmarked. The directories.
and..
are never unmarked. -
C-u % m f.. RET
: Same as above. -
t
or* t
: Toggle marks. The marked files become unmarked and vice versa. If the region is active, toggle the marks of only the files in the region. The directories.
and..
are never toggled. Flagged files are not toggled. -
* c * D
: Change all files marked with*
to be now marked withD
(i.e., flagged for deletion). Note that unlike the other commands, this command ignores the active region. It performs the change in the whole buffer. -
* c D SPC
: Change all files marked withD
to be now unmarked.
The chapter also mentions a key sequence * .
to mark
files by extension but this requires dired-x
, so this
is discussed in a later section of this page.
Dired: Operations
This section explains some operations we can perform in Dired. If there are one or more items marked in the Dired buffer, then the operations work on the marked items. Otherwise, the operations work on the item under the cursor.
-
C
: Copy marked files, or copy the current file. If one file is being copied, this command prompts for the target file path. If multiple files are being copied, this command prompts for the target directory path. -
R
: Rename marked files, or the current file. If one file is being renamed, this command prompts for the target file path. If multiple file are being renamed, this command prompts for the target directory path. -
O
: Change owner of the marked files or the current file. A complete key sequence may look likeO root RET
. -
G
: Change group of the marked files or the current file. A complete sequence may look likeG wheel RET
. -
M
: Change the mode of the marked files or the current file. A complete key sequence may look likeM u+x RET
orM 600 RET
. Both symbolic modes likeu+x
and numeric modes like600
are supported. -
D
: Delete marked files, i.e., the files that are marked with*
on the leftmost column of the Dired buffer. -
x
: Delete the files flagged for deletion, i.e., the files that are marked withD
on the leftmost column of the Dired buffer. -
c
: Compress marked files or current file into an archive. The archive file name is prompted. The format of the archive is automatically deduced from the extension of the file name entered at the prompt. A complete key sequence may look likec foo.tar.gz RET
orc foo.zip RET
.
Note the difference between D
and x
. The
key D
deletes marked files but the key x
deletes flagged files. Therefore there are two ways of deleting
files:
-
Mark files with
m
and delete them withD
. -
Flag files with
d
and delete them withx
.
I normally prefer the second way of deleting files. Since deleting
file is a destructive operation which is possibly risky, I like to
flag them first with d
before deleting them
with x
. In other words, I flag files for deletions and
mark files for everything else. Since I do not use
the D
key, I can be confident that my marked files are
always safe and there is no risk of inadvertently deleting them.
Dired: Copying or Renaming Between Buffers
The following steps explain how we can copy or move files from one Dired buffer to another. First we will see the default behaviour and then we will customise Dired to copy or move files to a particular Dired directory.
-
Type
C-x d /usr/ RET
. -
Type
C-x 2
. -
Type
C-x d /tmp/ RET
. -
Type
C-x 2
agian. -
Type
C-x d /etc/ RET
. -
Move the cursor on some file in
/etc/
and then typeC
orR
and we will see that the default directory to copy/move the file to is/etc/
. -
Now type
(setq dired-dwim-target t)
. -
Now type
C
orR
again while the cursor is on some file in/etc/
. We will see that the default directory to copy/move the file to is/tmp/
now. Sincedired-dwim-target
is set to non-nil, Dired picks the directory from the next window with a Dired buffer and uses that as the target buffer.
Dired: More Keys
Here are some examples of Dired keys that do not act on marked files but does other interesting work:
-
g
: Refresh the Dired buffer. -
+
: Create directory. A complete key sequence may look like+ bar RET
. -
s
: Toggle sorting by date. By default, the items in the Dired buffer are sorted by file/directory names. -
<
: Jump to the next directory. -
>
: Jump to the previous directory. -
j
: Jump to a file by name. A complete sequence may look likej hosts RET
. Note that this only moves the cursor to the line in Dired buffer with the provided filename. It does not visit the file. -
M-s a C-s
: Perform multi-file incremental search through all marked files, or the current file. Marked directories are ignored. Action region is also ignored. It performs the search across all marked files. A complete key sequence may look likeM-s a C-s foo
and then repeatC-s
over and over again to jump through all the matches. When the search reaches the end of one file, the nextC-s
automatically jumps to the match in the next file. -
Q
: Perform multi-file regex-based search-and-replace operation through all marked files, or the current file. For any marked directories, the search-and-replace operation is performed in all its files recursively. The active region is ignored. A complete key sequence may look likeQ f.. RET \&\& RET
which searches for strings matching the patternf..
and duplicates that string. The key sequences supported byC-M-%
(query-replace-regexp
) likey
,n
, etc. work here. See section Search and Replace for an account of the supported key sequences. The search results are also displayed in a separate*xref*
-
A
: Find matches for a regular expression pattern in all marked files, or the current file. For any marked directories, all its files are searched recursively. The active region is ignored. A complete key sequence may look likeA f.. RET
. Note that this does not perform incremental search. Instead the search results are displayed in*xref*
buffer. -
!
: Run a shell command on each marked file or directory (or the current file or directory if nothing is marked). The command is executed synchronously. The active region is ignored, or the current file or directory. The command works on all marked files and directories. The output is displayed in a separate buffer. If*
is present in the command, then each*
is replaced with the entire file list and the command runs only once (not multiple times, once for each file). If?
is present in the command, then the command runs multiple times, once for each marked file, with each?
replaced with the name of the file being operated on. It is an error to specify both*
and?
. If neither is present, then the command runs multiple times, once for each marked file. -
&
: Like the previous command but runs the command asynchronously.
To understand the usefulness of g
, while Dired is open
create a new file in the current directory with, say, C-x C-f
foo.txt RET
and save it with C-x s
. Then kill
the buffer for the file with C-x k
and return to the
Dired buffer. The Dired buffer does not show the new
file foo.txt
. Now type g
to refresh the
Dired buffer. As soon as g
is typed, the buffer gets
updated to display the new file.
To understand the difference between !
and &
mark five files and then type the key
sequence ! sleep 1; echo
. Emacs blocks (i.e., does not
react to our keystrokes) for 5 seconds while it runs the given
command for each file. When the echo
output for all
files is obtained after 5 seconds, the output appears and Emacs
unblocks again. Now type & sleep 1; echo
. Now
Emacs remains unblocked while the output of each echo
command appears at one second intervals in the output buffer.
Dired-X
Dired-X provides extra Dired functionality. It is not enabled by default. To enable it, add the following line to the Emacs initialisation file:
(require 'dired-x)
The following key sequences are supported by Dired-X:
-
F
: Visit the marked files or the current file. When multiple files are visited, they are opened in split windows distributed as evenly as possible. -
C-u F
: Visit the marked files or the current file but open them in background, i.e., do not show them on any window. -
* .
: Mark files with a certain extension. If the region is active, then mark only the files in the region that have the given extension. A complete key sequence may look like* . txt
. -
!
and&
: These commands still work the way they were described in the previous section. However with Dired-X enabled, when!
or&
is invoked on a single file (either a single marked file or no marked file in which case it operates on the current file), it automatically determines the command to execute for the current file type and offers that as the default input.
Dired: Working Across Directories
The following key sequences offer some support for working across multiple directories in the same Dired buffer:
-
i
: While the cursor is on a line for a directory, it expands the directory listing for that directory in the same Dired buffer. Now we could use the mark, unmark, etc. commands to select files that belong to multiple directories and operate on them from the same Dired buffer. -
$
: Collapse or expand the current directory listing. If there are multiple directory listings (such as the ones created withi
), then move to the next directory listing after collapsing or expanding the current one.
Using i
to insert the directory listing of a
subdirectory into the current Dired buffer could feel tedious if we
want to recursively work on multiple directories. The commands
(illustrated with complete key sequences below) may be more suitable
for such operations:
-
M-x find-dired RET RET -name SPC "f*.txt" RET
: Find all files and directories in the current directory and its subdirectories recursively with name matching the patternf*.txt
and show the results in the buffer named*Find*
with Dired mode enabled in it. Emacs runs the following command to get the results:find . \( -name "f*.txt" \) -ls
-
M-x find-name-dired RET RET f*.txt RET
: Same as above. Emacs runs the following command to get the results:find . \( -name f\*.txt \) -l
Further on a system with case-insensitive filenames, Emacs is clever enough to use the
-iname
argument instead of-name
so that case-insensitive search is performed. -
M-x find-grep-dired RET RET f.. RET
: Find all files in the current directory and its subdirectories recursively and list the files where lines matching the regular expression..
is found. The result is shown in a the buffer named*Find
with Dired mode enabled in it. Emacs runs the following command to get the results:find . \( -type f -exec grep -q -e f.. \{\} \; \) -ls
-
M-x find-lisp-find-dired RET RET f.. RET
: Find all files in the current directory and subdirectories recursively and list the files with names that match the regular expression pattern..
. Note that this is different from bothfind-name-dired
andfind-grep-dired
. The former relies on the Unixfind
command to match filenames using glob patterns. The latter uses bothfind
andgrep
to list files that contain a line with a matching regular expression pattern. However this command lists files with names that match a regular expression pattern (not glob pattern). Further this command is implemented purely in Elisp and does not have any external dependencies on tools likefind
andgrep
.
Shell Commands
The following complete key sequences demonstrate how we can invoke shell commands from Emacs.
-
M-! uname RET
: Execute shell command and show output. -
C-u M-! uname RET
: Like above but insert the output into the buffer wherever the cursor is. The cursor remains at the same place. The mark is set to the character just after the last character of the output. Therefore, typingC-x C-x
(exchange-point-and-mark
) is a quick way to highlight the output just inserted as an active region. -
M-! ping SPC -c SPC 4 SPC localhost RET
: Execute a slightly long running shell command that takes about 4 seconds to complete. Emacs blocks while the command is running because the command is executed synchronously. -
C-u M-! ping SPC -c SPC 4 SPC localhost RET
: Like before but the output is inserted into the buffer. Again, Emacs blocks while the command is executed. The output appears in the buffer only after the command completes execution. -
M-& ping SPC -c SPC 4 SPC localhost RET
: LikeM-!
but execute shell command asynchronously. Emacs remains unblocked and the output appears in the output buffer as soon as the output is printed by the command. -
M-| wc RET
: Pipe region to shell command and show output. -
C-u M-| wc RET
: Pipe region to shell command and replace the region with the output.
The book also mentions that C-u M-&
is supposed to
work like C-u M-!
but asynchronously but I did not find
this to be true. For example, C-u M-& uname RET
led to
the following error Wrong type argument: stringp, (4)
.
This may be a bug in Emacs 28.2.
Compiling in Emacs
The following complete key sequences demonstrate this feature:
-
M-x compile RET
: Runsmake -f
by default. The default command is offered as a minibuffer input before we typeRET
. Therefore we can edit the command to any arbitrary command before typingRET
. -
M-x recompile RET
: Runs the last compile command again. -
C-x p c
: Compile in the current project. See section Project Management for more details.
The compile commands display the output in
the *compilation*
buffer where the following key
sequences work:
-
M-g M-n
: Jump to the next error. The cursor jumps to the next error line in the*compilation*
and the source of the matching error line is opened in a separated window. -
M-g M-p
: Jump to the previous error. -
g
: Recompile, i.e., run the last compile command again.
Shells in Emacs
M-x shell
The key sequence M-x shell RET
starts a shell with
input/output done via a buffer. Some important points to keep in
mind while using this:
-
The TAB-completion mechanism of the underlying shell (e.g., Bash,
Zsh, etc.) does not work. In fact,
TAB
invokes Emacs's own completion mechanism. -
Programs like
top
andman
that need to control the terminal do not work. Only programs that perform input/output via standard input, standard output, and standard error, etc. work well. - Since the shell buffer is made completely of text, all text editing commands of Emacs work seamlessly on the buffer.
-
We can take the cursor to absolutely anywhere in the buffer and
type
RET
to execute whatever is on that line as a shell command. Shell prompt on the line is automatically excluded from the command to be executed.
Here are some key bindings that work in the shell buffer:
-
M-p
: Cycle backwards through input history. -
M-n
: Cycle forwards through input history. -
C-<up>
: Same asM-p
. May not work if the desktop environment gobbles up this keystroke. -
C-<down>
: Same asM-n
. May not work if the desktop environment gobbles up this keystroke. -
M-r f..
: Search history backwards for all commands that match the patternf..
. Within the search, we can use incremental search key bindings likeC-r
,C-s
, etc. to search backward, forward, etc. respectively. -
C-c C-p
: Move to the previous prompt. The cursor moves to the place just after the prompt. -
C-c C-n
: Move to the next prompt. -
C-c C-s out.txt RET
: Write output since the last input to a file. Any prompt at the end of the output is not written. Note that by default the output on shell contains the input command as well. The input command is echoed back, so our input command appears twice in the buffer: once where we typed it and once more echoed just before the beginning of the output. This echoed input command is also saved to the file. -
C-c C-o
: Delete all output since the last input. Any prompt is of course left intact. -
C-u C-c C-o
: Delete all output since the last input and save it to the kill ring. -
C-c C-l
: Show the list of recent inputs in the*Input History*
buffer. -
C-d
: If the cursor is at the end of the buffer and there is no input, send EOF. Otherwise delete a character forward. -
C-c C-z
: Suspend the current job. This performs the same function asC-z
in the underlying shell. We can then use job control commands likebg
orfg
to resume the job as a background process or foreground process. -
TAB
: Perform completion at point.
M-x ansi-term
The key sequence M-x ansi-term RET RET
launches an
ANSI-capable terminal emulator. It can run sophisticated programs
like top
, man
, etc. that require terminal
capabilities fine. The following key sequences are useful in this
terminal emulator:
-
C-c C-j
: Switch to line ("cooked") sub-mode. Emacs editing key sequences work normally in this mode, exceptRET
which sends the current line as a command to the underlying shell. -
C-c C-k
: Switch to char ("raw") sub-mode. By default, the terminal starts in this mode. Each character we type in this sub-mode is sent directly to the shell, except for the escape characterC-c
which is used as the prefix keys for the key sequences described in this list. -
C-c C-c
: Interrupt the current subjob.
M-x eshell
The key sequence M-x eshell RET
creates an interactive
Eshell buffer if none exists, or switches to an existing one.
Eshell is implemented in Elisp. It provides Elisp implementation of
Unix commands like ls
, cp
, etc.
The list below provides examples of some commands we can enter directly into Eshell:
-
which ls
: The output should show thatls
is an Elisp function. -
which which
: The output should show thatwhich
itself is an Elisp function. -
which top
: The output should show the file path of the external programtop
. -
ls -l
: Run Eshell's implementation ofls
written in Elisp. -
find-file /etc/hosts
: Run the Elisp function namedfind-file
with the argument/etc/hosts
thus opening the file in a buffer. -
/bin/ls -l
: Run the external commandls
available provided by the operating system utilities. -
python3 --version
: Run the external programpython3
. -
top
: Start the programtop
in a separate buffer withterm-mode
as the major mode.
In the last point we see that for programs like top
which need terminal capabilities to show output in a visual fashion
(as opposed to just printing output to standard output or standard
error), Eshell automatically runs the program in
a term-mode
buffer, so that the output of the visual
program can be handled and displayed correctly. Eshell looks at the
list in the variable eshell-visual-commands
to
determine if a command needs terminal support or not. By default,
commands like vi
, screen
,
tmux
, top
, etc. belong to this list.