(or emacs irrelevant)

New in Emacs 25 - convenient compression/decompression in Dired

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:

  1. I get TAB completion for the directory of the created archive.
  2. * 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:

  1. 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.

  2. 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.

A simple multiple-cursors extension to swiper

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.

Swiper and visual-line-mode

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.

swiper-visual-line-mode.png

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.

More tweaks to Ivy minibuffer faces

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:

counsel-M-x.png

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)

counsel-ag

If you're interested in how the face backgrounds are combined, you can read my older article on color blending in Elisp.

Fancy minibuffer faces for Ivy completion

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:

ivy-display-style-1.png

And counsel-M-x will look like this:

ivy-display-style-2.png

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.