(or emacs irrelevant)

Ivy 0.13.0 is out

Intro

Ivy is a completion method that's similar to Ido, but with emphasis on simplicity and customizability.

Overview

The current release constitutes of 183 commits and 3 months of progress since 0.12.0. Many issues ranging from #2153 to #2278 were fixed. The number of people who contributed code as grown to form 148 to 160. Thanks, everyone!

Details on changes

Changelog.org has been a part of the repository since 0.6.0, you can get the details of the current and past changes:

Highlights

Many improvements are incremental and don't require any extra code to enable. I'll go over a few selected features that require a bit of information to make a good use of them.

New bindings

  • counsel-find-file
    • ~~ to move to the local home directory from remote or /sudo::.
    • / RET ~ achieves the same thing, but is longer.
    • M-o R calls find-file-read-only.
  • counsel-git-grep
    • C-x C-d to switch the current directory.
  • swiper-isearch
    • M-o w to copy the current line and go back to where you started.

New features

counsel-package

The idea of counsel-package is to install and remove packages with a single binding:

(global-set-key (kbd "C-c P") 'counsel-package)

But if the package contents weren't up to date, a separate M-x package-refresh-contents had to be triggered, which was an annoying overhead. Now counsel-package will look at the time stamps of the appropriate archive-contents files, and call package-refresh-contents if the timestamp is outdated by more than 4 hours.

counsel-M-x

Some commands are intended to be called only via their key binding. Make them disappear from counsel-M-x like this:

(put 'counsel-find-symbol 'no-counsel-M-x t)

counsel-rg

The default setting of ivy-case-fold-search-default is 'auto, which means:

  • the input "emacs" matches "emacs", "EMACS", and "Emacs"
  • the input "Emacs" matches only "Emacs"

This now also applies to counsel-rg: Ivy will pass the -i flag to ripgrep appropriately, based on ivy-case-fold-search-default. You should remove the -S flag from counsel-rg-base-command if you customized it.

ivy-update-candidates

This is a new API for asynchronous calls. To use it, pass to ivy-read: :dynamic-collection t, and a collection function that takes a user input string, starts some asynchronous process based on that input, and returns 0. The 0 return result tells Ivy that no candidates were returned; instead, ivy-update-candidates is used in the async callback.

See counsel-google for a reference implementation.

ivy-use-virtual-buffers

You can now choose between: recent files, or bookmarks, or both, or none. Don't forget that counsel-set-variable makes it very easy to set customization options.

New Commands

I have put these separately so they don't get lost in the crowd. Be sure to try them out.

  • counsel-buffer-or-recentf - list buffers visiting files (highlighted) then the recentf file list.
  • counsel-fonts - show a list of all supported font families for a particular frame.
  • counsel-google - asynchronously query the Google predictive search API.
  • counsel-major - switch major-mode.
  • counsel-slime-repl-history - browse SLIME REPL history.

Outro

Again, thanks to all the contributors. Happy hacking!

PS. Thanks to everyone who supports me on Liberapay and Patreon!

I am now also on Github sponsors, which is an interesting new effort by Github. The cool thing is that's more integrated with Github, there are less transaction fees, and Github matches every donation for up to $5000 for a whole year. Please consider joining there, since every $1 per month that you donate is doubled by Github.

Ivy 0.12.0 is out

Intro

Ivy is a completion method that's similar to Ido, but with emphasis on simplicity and customizability.

Overview

The current release constitutes of 398 commits and 6 months of progress since 0.11.0. Many issues ranging from #1904 to #2151 were fixed. The number of people who contributed code as grown to 148. Thanks, everyone!

Details on changes

Changelog.org has been a part of the repository since 0.6.0, you can get the details of the current and past changes:

Highlights

Many improvements are incremental and don't require any extra code to enable. I'll go over a few selected features that require a bit of information to make a good use of them.

New bindings

  • counsel-descbinds
    • M-o x execute action.
  • counsel-file-jump
    • M-o d dired.
  • counsel-find-file
    • M-o c copy file.
    • ` bookmarks: efficiently jump between recent directories.
    • $ directories stored in environment variables.
    • C-DEL go up directory. Customize: counsel-up-directory-level.
    • RET open file. Customize: counsel-find-file-extern-extensions.
    • // when on remote, cd to remote root.
    • / C-j select local root.
    • ~ when on remote, cd to remote home.
    • / C-j ~ cd to local home from remote.
  • counsel-git-log
    • M-o v open the current commit in magit.
  • counsel-rg
    • C-x C-d change the current directory for grep.
  • ivy-avy
    • C-v to scroll down.
    • M-v to scroll up.
  • ivy-read C-o
    • m mark and move down.
    • u unmark and move down.
    • DEL move up and unmark.
    • t toggle marks.
    • d perform the action on all marked elements.
  • ivy-switch-buffer
    • C-k kill buffer.
    • M-o x open buffer file externally.
  • ivy-reverse-i-search
    • C-k remove item from the history.

New Commands extensions

These commands are new variants and adaptations of existing commands.

Thing at point variants:

  • swiper-all-thing-at-point.
  • swiper-isearch-thing-at-point.
  • swiper-thing-at-point.

Search variants that go backwards:

  • swiper-backward.
  • counsel-grep-or-swiper-backward.
  • swiper-isearch-backward.

A variant of ivy-switch-buffer with live preview:

  • counsel-switch-buffer.
  • counsel-switch-buffer-other-window.

And finally:

  • counsel-dired - like counsel-find-file, but open dired.
  • swiper-isearch-toggle - toggle between swiper and isearch.

New Commands

I have put these separately so they don't get lost in the crowd. Be sure to try them out.

  • counsel-compile - completion for compile.
  • counsel-register - completion for registers.
  • counsel-minor - completion for minor modes.
  • swiper-isearch - a faster swiper that's not line-based.

Outro

Again, thanks to all the contributors. Happy hacking!

Ivy reverse-i-search

Introduction

I'm sure many are aware of the C-r functionality in bash (a whole lot of Emacs bindings are valid in bash and do the same thing). I also like the quirky Emacs-style prompt, that uses a backquote to open and a straight quote to close a your quoted input:

bash-reverse-i-search.png

So when you want to cd to somewhere where you were before you do C-r cd. And then the C-r "roulette" begins: you keep pressing C-r over and over, in the hopes to find what you were looking for.

Getting better history completion with Ivy

Ivy improves the "roulette" situation in two ways:

  • You get an overview of the matching candidates and their count,
  • You can quickly narrow down the candidates with fuzzy matching.

Here's the basic setup to enable C-r completion using ivy:

(define-key minibuffer-local-map
    (kbd "C-r") 'counsel-minibuffer-history)
(define-key shell-mode-map
    (kbd "C-r") 'counsel-shell-history)

The first key binding is also part of counsel-mode, while the second needs to be set up separately, after shell-mode was loaded.

And here's how counsel-shell-history looks like:

counsel-shell-history.png

The cool thing is that ivy-reverse-i-search applies to any Ivy command, not just for shell command completion. I find it especially useful for:

  • counsel-find-file
  • eval-expression

Recent improvement: delete history items

While searching with regexes is great, it's not so great when the old stuff that we won't ever need gets in the way. So now you can delete it with C-k. Since C-k also has to serve as ivy-kill-line, the history deleting behavior will only come into effect when the point is at the end of the line (so that ivy-kill-line does not make sense anyway).

ivy-reverse-i-search-kill.png

This way, your typos don't stay around to haunt you.

Outro

I hope you'll find ivy-reverse-i-search a useful boost to your completion needs. Happy hacking!

Ivy usability improvements when dealing with directories

Introduction

When Ivy just started out as a completion framework, the functionality was supposed to be simple: select one string from a list of strings. The UI is simple enough:

  • Show the list of strings that match the entered text,
  • Use C-n and C-p to navigate them,
  • Use C-m or C-j to submit.

Emacs has three key bindings that mean "Enter": RET, C-m, and C-j. But in terminal mode, emacs -nw, RET and C-m are the same binding: Emacs can't distinguish them. So we have at most two bindings. Fortunately, the world of completion is simple at the moment, and we only need one binding.

File name completion

Enter file name completion. When you're completing file names, you are selecting not one string, but many strings in succession while moving from one directory to the next. So we need at least two key bindings:

  • Use C-m (ivy-done) to select the current candidate and exit completion.
  • Use C-j (ivy-alt-done) to change the current directory to the current candidate without exiting completion.

What to do when C-j is used on a file and not on a directory? Might as well open the file: same action as C-m. OK, we had two key bindings, and we have used them. Hopefully nothing else comes up.

Enter creating a new file, i.e. selecting something that's not on the list of strings. Suppose I call find-file, enter "do", and the only match is a directory named "doc":

  • Pressing C-m will end completion with the "doc" directory selected.
  • Pressing C-j will continue completion inside the "doc" directory.

So creating a file named "do" is the third action. Our two "Enter" keybindings are already taken by the first two different useful actions. So we need a third key binding. The one I chose is C-M-j (ivy-immediate-done). It means: I don't care that the current input is not on the list of candidate strings, submit it anyway.

Directory creation

Enter directory creation: dired-create-directory and make-directory. These built-in Emacs commands request file name completion, but what they tell Ivy is no different from what find-file tells: "I want to select a file". However, for these commands, the C-M-j action is the one that makes most sense. Here it would be nice for Ivy to take the back seat and just act like an interactive ls, since the user will enter a completely new string that's not on the list of candidates.

For a long time, you still had to use C-M-j with those commands, to much frustration of new but also existing users, including myself. But a few days ago, I looked at the prompt that dired-create-directory uses: "Create directory: ". That prompt is passed to Ivy. Using the prompt to detect the intention of the command is a bit of a hack, but I think in this case it's justifiable. So now Ivy will recognize that the intention commands that request file name completion and pass the "Create directory: " prompt is to create a directory, and all key bindings will do just that: C-m, C-j, and C-M-j will behave the same in this case.

An alternative key binding scheme

Note that C-m and C-j behave differently only for directories. But thanks to the fact that "." is always the first candidate, C-m for directories is equivalent to C-j C-j. So we can get away with just using ivy-alt-done, and bind C-m to ivy-immediate-done. Or swap the two meanings:

(define-key ivy-minibuffer-map (kbd "C-j") 'ivy-immediate-done)
(define-key ivy-minibuffer-map (kbd "C-m") 'ivy-alt-done)

The price to pay here is the extra context switch when we simply want to select a directory. We could the bind ivy-done to C-M-j and avoid the context switch, but then we're back to three bindings once more. Still, I thought that swapping the bindings is an interesting idea worth sharing.

Canceling dired-dwim-target

Setting dired-dwim-target is a nice productivity boost. It allows to use Emacs in a similar way to a two-pane file explorer, like mc(1). But it was really annoying when I was in dir-1 with the intention to copy a file to a different name in dir-1 (e.g. create a backup, or copy a template), but the current directory was set to dir-2 because of a random dired window I had open. In that case, I had to call delete-other-windows, perform the copy, and then restore the window configuration with winner-undo.

I did the above many times over many years, until I finally dug into the code of dired.el to see how dired-dwim-target worked. Turns out it was storing dir-1 in the minibuffer-defaults variable. So now Ivy will use that variable when I press M-n. All in all, it was a five minute fix. But rather than regret that I didn't do it years ago, I'm glad I did it now. It only remains to build some muscle memory to press M-n in that situation.

I'm guesstimating that dired-dwim-target works to my advantage 90% of the time when I press C in dired. For the other 10% of the times, I can now press M-n.

Outro

I hope you find the new functionality useful. I'm always open to new ideas and pull requests. Happy hacking!

hydra 0.15.0 is out

This release consists of 45 commits done over the course of the last 2 years. With this version, I have introduced a Changelog.org, similar to what ivy and avy have.

hydra

Highlights

Display hints using posframe

A new defcustom hydra-hint-display-type was introduced that can be either lv (the default), message, or posframe.

Posframe is a package that leverages a new feature in Emacs 26.1: the ability to display child frames. The advantage of using child frames is that you can easily position them anywhere within your frame area. For example, the default setting is to put it in the center of the current window, which is closer to where your eyes are focused than the minibuffer. Child frames don't interfere with the content of the buffers which they overlap. Finally, you can select a different font for the child frame.

hydra-posframe

Less boilerplate in defhydra

You no longer have to add :hint nil, and you can skip the docstring as well:

(defhydra hydra-clock (:exit t)
  ("q" nil "quit" :column "Clock")
  ("c" org-clock-cancel "cancel" :column "Do" :exit nil)
  ("d" org-clock-display "display")
  ("e" org-clock-modify-effort-estimate "effort")
  ("i" org-clock-in "in")
  ("j" org-clock-goto "jump")
  ("o" org-clock-out "out")
  ("r" org-clock-report "report"))

Add heads to an existing hydra

You can now add heads to an existing hydra like this:

(defhydra hydra-extendable ()
  "extendable"
  ("j" next-line "down"))

(defhydra+ hydra-extendable ()
  ("k" previous-line "up"))

The new macro defhydra+ takes the same arguments as defhydra, so it's quite easy to split up or join your hydras.

The use case of defhydra+ is when you have many packages that want to add heads to an existing hydra. Some of them may be optional or loaded lazily.

You can now have a base defhydra, and then use defhydra+ to add heads to it when a new package is loaded. Example:

(defhydra hydra-toggle ()
  ("q" nil "quit" :column "Exit")
  ("w" whitespace-mode
       (format "whitespace-mode: %S" whitespace-mode)
       :column "Toggles"))

(use-package org
    :config
  (defhydra+ hydra-toggle ()
    ("l" org-toggle-link-display
         (format "org link display: %S" org-descriptive-links))))

Outro

Big thanks to all contributors, and I hope you enjoy the new release. Happy hacking!

PS. Thanks to everyone who supports me on Liberapay and Patreon!