Skip to content

larkery/ido-grid-mode.el

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

87 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ido Grid Mode

This is an enhancement to ido mode which displays the ido prospects in a grid in the minibuffer. I find this makes them easier to read. It can also amend ido’s key-bindings so that you can navigate around the grid, rather than scrolling all the completions. I find this also makes it easier to read.

Here are a some examples of how it can work:

In ido-find-file ./pictures/files-example.gif

In smex: ./pictures/smex-example.gif

Using ido-describe-prefix-bindings for C-x ./pictures/vertical-example.gif

Installation

It is a single-file emacs package, so you can use M-x package-install-file on it. To switch it on, invoke (ido-grid-mode 1). To switch it off, invoke (ido-grid-mode -1)

Configuration

Most things are configurable through M-x customize-group ido-grid-mode. The important things are ido-grid-mode-max-rows and ido-grid-mode-min-rows, which determine the size of the thing, and perhaps ido-grid-mode-order.

Size and formatting

The grid is laid out to fit into the minibuffer’s available width, assuming a fixed-width font. Layout is either done left-right then top-bottom or top-bottom then left-right, depending on whether ido-grid-mode-order is nil for rows or t for columns. I prefer columns, which is similar to what zsh does.

No more than ido-grid-mode-max-rows rows should be produced. If the layout can be achieved with fewer rows, then fewer rows will appear, limited by ido-grid-mode-min-rows. By default these are the same, which keeps the minibuffer a constant height. If you want the minibuffer to grow and shrink appropriately reduce the min rows.

If you want the minibuffer to typically be small, but display a large grid on demand, you can use ido-grid-mode-start-collapsed. This will limit it to a single row until you press <tab>, so long as there are things which would be offscreen. I find this a good setting, as it means that things don’t move around on the screen until you want them to.

The little arrow -> displayed on the left is customisable with ido-grid-mode-prefix, and you can make it follow the highlighted item with ido-grid-mode-prefix-scrolls.

Making a vertical list sometimes

If you want a particular bit of code to use a vertical list (or some other known layout) you can let the appropriate variables around it.

(let ((ido-grid-mode-max-columns 1)
      (ido-grid-mode-max-rows 30))
  (completing-read ...))

You might want to do this in an advice, e.g.:

;; make projectile-find-file vertical list

(defun ido-vertical-please (o &rest args)
  (let ((ido-grid-mode-max-columns 1)
        (ido-grid-mode-max-rows 15) ;; bigger list than usual
        (ido-grid-mode-min-rows 1) ;; let it shrink
        (ido-grid-mode-start-collapsed nil) ;; pop up tall at the start
        ;; why not have a different prefix as well?
        (ido-grid-mode-prefix ":: "))
    (apply o args)))

(advice-add 'projectile-find-file :around #'ido-vertical-please)

Scrolling

By default, the arrow keys and tab/backtab will move around in the grid. You have some choices about what happens when you reach the edges of the grid, if there are too many things to display:

  • ido-grid-mode-scroll-wrap sets what happens when you move the cursor out-of-bounds. If it is t, the cursor will always wrap except at the top left and bottom right corners. If it is nil, the cursor will wrap only in the non-major dimension; what this means is that if you have ido-grid-mode-order set column-first, going out of bounds vertically will wrap, but horizontally will scroll. If ido-grid-mode-order is rows-first, the reverse is true
  • ido-grid-mode-scroll-up and ido-grid-mode-scroll-down control what happens when the cursor is moved out of bounds and is not wrapped. You can use ido-grid-mode-<next/previous>-page to move as many items are displayed, so the whole page of items changes, or you can use ido-grid-mode-<next/previous>-row which is slightly confusingly named but scrolls one row if the layout is row-wise or one column if it is column-wise.

You can use these in combination to get different behaviours, for example:

(setq ido-grid-mode-max-columns 1
      ido-grid-mode-max-rows 8
      ido-grid-mode-prefix-scrolls t
      ido-grid-mode-scroll-down #'ido-grid-mode-next-row
      ido-grid-mode-scroll-up #'ido-grid-mode-previous-row
      ido-grid-mode-order nil
      ido-grid-mode-start-collapsed t)

will start small, popup when you press tab, and let you scroll up and down in a vertical list a row at a time when you hit the edges:

./pictures/vertical-scroll.gif

Keys

By default, ido-grid-mode will mangle your key-bindings for <up>, <down>, <left>, <right>, <tab>, <backtab>, C-n and C-p when in the minibuffer. These are bound to move around the grid and page up / down when there are many items. You can change this by customizing ido-grid-mode-keys; set it to nil to leave the keys alone. The movement commands are igm-<up,down,left,right>, igm-previous, igm-next, igm-previous-page, and igm-next-page.

Faces

At the moment, ido-use-faces is ignored, and faces are always added. This is partly because you need a face to see the highlighted item. The faces used are:

  • ido-grid-mode-match, which is used to highlight matching substrings
  • ido-first-match, which is used to highlight the selected prospect
  • ido-only-match, which is used when there is only one prospect
  • ido-subdir, which is used to colour in directories in ido-find-file
  • ido-grid-mode-prefix, which is used for the common prefix string
  • ido-incomplete-regexp, which is used when there is an incomplete regexp.

Top line

The top line shows some information after point; this is configurable with ido-grid-mode-first-line.

Things to do

Improve row/column specific code

There are two code paths for different layouts in a lot of places, which is lame and might be fixable

Improve scrolling

At the moment scrolling the grid a row at a time sometimes makes the cursor jump around when the dimensions of the next layout are different. Similarly, you can scroll right 1 column and just reduce the number of columns if the ‘next’ column wouldn’t fit.

Efficiency improvements

It works OK on my laptop, but it is irksome that the grid is created so frequently. Most of the time it should be possible to reuse the string and just move the faces around.

The merged indicator breaks wrapping

See also

  • ido-vertical-mode.el, which this was based on. I rewrote it when it looked like I was starting to break existing behaviour too much.
  • ido-match-modes.el, which lets you toggle different ido matching methods (flx, regex, substring etc.) and uses ido-grid-mode-first-line to display the current method.
  • emacs-zlc, which does something similar to this, but in the completions buffer rather than the minibuffer.