23 Oct 2015
Today I'll describe my past and current workflows for compressing
files and directories in Dired. In my opinion, Dired is one of the
best features of Emacs - a great abstraction of cd
+ls
that lets
you get things done much faster. The default binding for dired
is
C-x d (I bind it to C-;-d though, see my
xmodmap post).
My previous workflow
To compress several files in Dired, first I compile a list of files to
work on by marking them with m (dired-mark
), navigating
to ones that you want with n (dired-next-line
) and
p (dired-previous-line
).
Once a list is ready, I press & (dired-do-async-shell-command
), which allows me to run an arbitrary shell command.
I enter:
tar -czf ~/tmp/path/foo.tar.gz *
into the minibuffer, press RET and I'm done. It's a
standard shell command with 2 advantages:
- I get TAB completion for the directory of the created archive.
*
means the selected file list, so I don't enter them by hand.
My current workflow
Since I often forget the command for tar
, and I really don't want to
remember the commands for zip
etc, I've implemented a more convenient approach:
(define-key dired-mode-map "c" 'dired-do-compress-to)
This new command dired-do-compress-to
, bound to c, will
prompt me for a file name of the output archive. So now it's easier to
type in that file name, if you use ido-mode
/ ivy-mode
/
helm-mode
. What's more, the command will be automatically determined
from the archive extension and executed. Here's the corresponding
customization variable:
(defvar dired-compress-files-alist
'(("\\.tar\\.gz\\'" . "tar -c %i | gzip -c9 > %o")
("\\.zip\\'" . "zip %o -r --filesync %i"))
"Control the compression shell command for `dired-do-compress-to'.
Each element is (REGEXP . CMD), where REGEXP is the name of the
archive to which you want to compress, and CMD the the
corresponding command.
Within CMD, %i denotes the input file(s), and %o denotes the
output file. %i path(s) are relative, while %o is absolute.")
This thing is pretty self-explanatory. It currently only supports
*.tar.gz
and *.zip
, use M-x report-emacs-bug
if you
want to add more options.
Other improvements in compression/decompression
I improved the good-old Z (dired-do-compress
) as
well. Now it can compress directories to *.tar.gz
, as well as
decompress *.tar.gz
and *.zip
to directories. It's all automatic,
you only have to press Z, either on an archive to
decompress, or on a directory to compress.
Easy way to have a bleeding edge Emacs
If you want to get these improvements right now and are on a Debian
type system (I use Ubuntu), you can use:
sudo apt-add-repository ppa:ubuntu-elisp/ppa
sudo apt-get update
sudo apt-get install emacs-snapshot
Then just use emacs-snapshot
executable. It updates every few days.
Myself, I track the Emacs master from
git. But emacs-snapshot
is
very useful for CI tests, and can also be used by people who don't
want to build the executable from git.
How to get your improvements into Emacs
If you'd like to contribute code to the Emacs core yourself, it takes
two steps:
Sign the Copyright Assignment
(CA).
This gives the Copyright for your changes to Emacs to the Free
Software Foundation. This is useful so that the FSF can defend your
rights in court, in case the GPL regarding your contribution is broken
by someone.
M-x report-emacs-bug
and attach a patch.
It seems that some people could have a moral objection to the CA. I
see no reason for it whatsoever. Since Elisp libraries make calls to
GPL code and are GPL themselves, you have to publish Elisp code under
GPL, there's no choice there. GPL means basically that, while you're
still acknowledged as the author, everyone else has about as much
right to your code as you do. No one can hide or restrict access to
it, but neither can you. The CA is a further step, which makes the FSF
own the Copyright to your changes to Emacs. You submit these changes
yourself, and the Copyright over these changes isn't really that
useful: they're only changes - they do nothing on their own, outside
of Emacs. Besides, with the FSF owning the Copyright, the range of
things that you can do to your code stays exactly the same as if you
owned the Copyright, as long as you publish under GPL.
To illustrate, the FSF CA is very polite and benign, compared to the
CA that I have to give to Elsevier when I publish an article. That CA
means that a multi-billion dollar corporation owns the right to my
paper until the end of time, and can charge people to view it
(including myself and my peers) as much as they see fit (currently,
$30). Of course, I don't receive a dime of that money, but hey - I get
published, and at least I can share my article for free for the
first 50 days of the publish date. And if that one doesn't seem
draconian enough for you, just think of the NDAs in commercial
companies: out there, you can't even publish or mention anything
related to your work. So please, if you're hating on the FSF, do
reconsider, they're the good guys in my book.
Eventually, after a few submitted patches, you'll be granted commit
access. This is a great way to implement small improvements faster.
However, the larger issues that aren't simple improvements still need
to be discussed with other developers, either on debbugs or on
emacs-devel. For example, initially I went with the tar -czf
command. But it turns out that it can't be used on Solaris 10 or AIX
7.1. Whatever those things are, people still use Emacs on them, and
it's important that the core features are usable on all supported
systems.
14 Oct 2015
When using Emacs, it happens sometimes that I accumulate too many
buffers. The usual next action is to close the buffers for the project
that I'm not currently working on. Previously, I marked those buffers
in *Buffer List*
by hand with d and
C-n. Today, I'll show a faster way.
It's very easy to select these buffers in *Buffer List*
with
swiper: just type a part the
shared directory name. Another example is to select all dired
buffers: a "dired by" input will usually match all of them, since they
all have Dired by name
in their line.
Afterwards, I want to open
multiple-cursors for
each matched line. I've bound this action to C-7. Here's
the very simple code:
(defun swiper-mc ()
(interactive)
(unless (require 'multiple-cursors nil t)
(error "multiple-cursors isn't installed"))
(let ((cands (nreverse ivy--old-cands)))
(unless (string= ivy-text "")
(ivy-set-action
(lambda (_)
(let (cand)
(while (setq cand (pop cands))
(swiper--action cand)
(when cands
(mc/create-fake-cursor-at-point))))
(mc/maybe-multiple-cursors-mode)))
(setq ivy-exit 'done)
(exit-minibuffer))))
After C-7, here's the sequence to delete the selected buffers:
- d (
Buffer-menu-delete
) to mark each item for deletion.
- C-g (
keyboard-quit
) to exit multiple-cursors
.
- x (
Buffer-menu-execute
) to execute the deletions.
And that's it: all selected buffers are now deleted. To summarize,
C-s dired by
C-7 d C-g x will close all
dired
buffers from your *Buffer List*
.
Other interesting applications are also possible, like mass renames in
wdired
, or un-commenting everything in a function. For example,
suppose that you have this code:
(progn
;; (check-1)
(foo)
;; (check-2)
(bar)
;; (check-3)
(baz))
If it's a part of a larger buffer, you can narrow with C-x nd (narrow-to-defun
)
or C-x nn (narrow-to-region
). Then C-s ;; C-7 DEL DEL C-d C-g to
remove all comments.
I have to say that the functionality intersects a bit with
mc/mark-all-like-this
. Except you know the result ahead of time
(number and position of matches), and you can use a regex instead of a
literal string.
02 Oct 2015
In case you encounter files with very long lines, the built-in
M-x visual-line-mode
might come in handy. Although 1MB
long one-line files are a disaster for Emacs, there's no problem
handling smaller files with long lines that result from bad markdown
renderers (notably Github). They way visual-line-mode
works, is it
inserts virtual newlines in appropriate positions, so that no line is
truncated. The advantage is that these newlines aren't written to the
file when the buffer is saved (otherwise, a simple M-q
(fill-paragraph
) would work too).
Today I've added visual-line-mode
support to
swiper, so handling these files
should be even easier now. The change was surprisingly simple: just
two checks for visual-line-mode
variable and these basic
replacements:
forward-line
-> line-move
,
line-beginning-position
-> beginning-of-visual-line
,
line-end-position
-> end-of-visual-line
.
By the way, visual-line-mode
is one of the small number of commands
that I call by name instead of by key chord. But thanks to
counsel-M-x
and smex
calling this command by name is as short as
C-t v RET. To explain a bit more, here's my setup:
;; make sure to install smex
(global-set-key (kbd "C-t") 'counsel-M-x)
The default command bound to C-t is transpose-chars
- a
highly situational and ultimately counter-productive command
(M-DEL and re-typing the word is faster than surgically
navigating to the transpose point and calling transpose-chars
, plus
it trains the hands to type the word correctly next time). Anyway,
C-t is a prime binding for launching interactive commands.
And since smex
is installed it remembers that my most used command
that starts with "v" is visual-line-mode
- so it's the first one
that gets selected after C-t v. This means that I can just
press RET and be done with it.
Finally, related to visual-line-mode
, here's a command I use to
negate M-q (fill-paragraph
) (source):
(global-set-key (kbd "C-M-q") 'ora-unfill-paragraph)
(defun ora-unfill-paragraph ()
"Transform a paragraph into a single line."
(interactive)
(let ((fill-column (point-max)))
(fill-paragraph nil t)))
Thanks to @joostkremers for the
suggestion in #227.
29 Sep 2015
This is a continuation of the thought that I started in the
last post a few
weeks ago. I don't fancy myself a graphical designer, but I kind of
have a feeling of what I like - I certainly know it when I see it.
I wasn't quite happy with the color of the current selection in the
minibuffer. Then it hit me that I like the way the Firefox address
bar does it: invert the selected text foreground to white and add a
flashy background. After that, it was only a matter of going though a
few random color permutations in the GIMP color selector to arrive to
a nice state:
I did add something similar for dark background themes, although I
rarely use them myself, since they contrast too much with Firefox,
with most websites having a light background:
(defface ivy-current-match
'((((class color) (background light))
:background "#1a4b77" :foreground "white")
(((class color) (background dark))
:background "#65a7e2" :foreground "black"))
"Face used by Ivy for highlighting first match.")
Of course, the standard recommendation follows to use
rainbow-mode in
buffers that deal with colors - it's great.
Finally, counsel-git-grep
and counsel-ag
now also add the proper
minibuffer coloring if you have it turned on:
(setq ivy-display-style 'fancy)
If you're interested in how the face backgrounds are combined, you can
read my older article on
color blending in Elisp.
04 Sep 2015
Today, I'll describe a recent improvement to the display of Ivy completion.
To use it, add this code to your configuration:
(setq ivy-display-style 'fancy)
After this, swiper will look like this:
And counsel-M-x
will look like this:
If you haven't used it before, counsel-M-x
is part the counsel
package on MELPA, or part of swiper package if you're installing from
GNU ELPA. Basically, it's a M-x replacement (that I like to
bind to C-t for efficiency reasons), that doubles as
find-function
(just press C-. instead of RET
to find the function instead of calling it). If you're using
counsel-M-x
I highly recommend to also install smex
, since then
counsel-M-x
will use smex
for sorting the matched commands.
The update will propertize the minibuffer contents with a new set of faces:
(defcustom swiper-minibuffer-faces
'(swiper-minibuffer-match-face-1
swiper-minibuffer-match-face-2
swiper-minibuffer-match-face-3
swiper-minibuffer-match-face-4)
"List of `swiper' faces for minibuffer group matches.")
Initially, when responding to
#212, I used the
original swiper faces in the minibuffer as well. But after some use,
their brightness became a bit annoying. So I introduced a new set of
faces that can be customized separately.
Here are the settings that I'm currently using:
(custom-set-faces
'(swiper-minibuffer-match-face-1
((t :background "#dddddd")))
'(swiper-minibuffer-match-face-2
((t :background "#bbbbbb" :weight bold)))
'(swiper-minibuffer-match-face-3
((t :background "#bbbbff" :weight bold)))
'(swiper-minibuffer-match-face-4
((t :background "#ffbbff" :weight bold))))
It's similar to what the Firefox address bar uses: gray background and
bold font. Additionally, the matching parts are highlighted with pale
gray, blue and magenta colors. If you like the color scheme, it's part
of eclipse-theme. Another
choice, for even less distraction, could be to remove the background
from these faces, only leaving the bold part on the matches.
Thanks to @Wilfred for nudging me to
finally implement this feature. It's been on my list for a long time,
but I've been putting it off.