2

I wanted to display a list of strings in the emacs completing-read style, which displays a list of completion strings in a nicely aligned multi-column display. But I could not find an easy answer or example on the web.

For example, tracing the source of describe-function I ended up in C code. (I used ESC-x describe-function "table-" TAB TAB to show a multi-column display.

I came across this SO posting on align-regexp, which was useful, but it only spoke about keyboard macros. I needed an elisp function for use in code.

In the end I wrote my own function to do the job, after hours spent learning about align-regexp and doing experiments with various args. It always feels like I took too much time to learn something so simple, when I look at the final code. Anyhow, I post my answer here in case someone else can use it one day.

The problem I want to solve is to take a 1-column list of strings in a buffer, like this:

one
two
one
three
four
three
five
xix
boxy

and turn it into 2 or more aligned columns like this

one   two
one   three
four  three
five  xix
boxy 

or this

one    two   one
three  four  three
five   xix   boxy 

It would be nice to space out the columns to fill the buffer width better, but that's a separate problem.

Kevin
  • 1,308
  • 8
  • 20

2 Answers2

3

If you are on a UNIX-type system (Linux, BSD, OSX) you can use the paste command.

Select the region in Emacs, then call shell-command-on-region with an argument (to replace the selection with the result).

For example, to format into 3 columns, type:

  • C-u M-|
  • paste - - -
  • Enter
Juancho
  • 5,395
  • 15
  • 20
  • 1
    You can also use the `column -x` shell command; or, if you want to fill columns before rows, just plain `column`. I've only ever had ad-hoc use-cases for this kind of thing, so I've never looked beyond the external utilities. I notice that I discussed this solution in the [Q&A](http://emacs.stackexchange.com/a/7349/454) that Kevin linked to, though; so presumably it's not what he was after here... – phils May 24 '16 at 05:25
  • @phils is correct, all these keyboard macros and external unix commands are not what I was after. My code generates a list of words in a buffer, and I wanted to display it in a help-buffer in multi-column format. So I had to do the column formatting in code to produce a multi-column string I could feed to the help window/buffer. – Kevin May 28 '16 at 01:53
2

Here's my elisp function that shows how to make multiple columns out of a single column. Limitations include list elements cannot have whitespaces, and the width of the columns cannot be adjusted. My elisp code is probably not optimal either.

But at least it will be a useful start for the next person who has the problem. It would have saved me quite a few hours if I had found it at the front of my search effort... :-)

(defun buffer-list-to-columns (ncolumns)
  "Modify a 1-column stringlist in current buffer into NCOLUMNS aligned columns.
List of items must begin in buffer column 0, and must not contain
whitespaces."
  (interactive)
  (let ((cols (1- ncolumns)) result)
    (save-excursion
      (goto-char (point-min))
      (dotimes (i cols)
        (join-line 1))
      (while (= 0 (forward-line 1))
        (dotimes (i cols)
          (join-line 1)))
      ;; for N columns, the args are:
      ;; regexp align whitespace followed by any word character
      ;; group=1, spacing=nil, repeat for the whole line=t
      (align-regexp (point-min) (point-max) "\\(\\s-*\\) \\w" 1 nil t)
      (setq result (buffer-string)))
    result))
Kevin
  • 1,308
  • 8
  • 20