.. post:: 2016-12-23 :tags: Emacs :author: Rudi Grinberg Pretty Printing a Table in Emacs ================================ Recently, I needed to output some relatively small tabular data in Emacs and ``message`` was starting to be a bit long in the tooth. Finally, I've decided to try my hand at upgrading the visuals for myself. I realize that there's probably dozens of different ways of pretty-printing tables in Emacs, but I was already partial to the tabular output used by functions such as ``list-processes`` and plugins such as `prodigy `__ (Using org mode's tables also comes to mind for example). So I've decided to recreate this experience for my own tables. The result has been convenient and aesthetically pleasing enough to share. The Code -------- Since this is just a little snippet, I'll start with running the code and using it. Some brief explanations and customization options will follow. To run the code you will need `dash `__, `popwin `__. If you use spacemacs, these batteries will already be included. If not, then it should be trivial to replace these. Here's the code: .. code-block:: elisp (defun make-tabulated-headers (column-names rows) "column width are calculated by picking the max width of every cell under that column + the column name" (let ((widths (-reduce-from (lambda (acc x) (-zip-with (lambda (l r) (max l (length r))) acc (append x '()))) (-map #'length columns-names) rows))) (cl-map #'vector #'identity (-zip-with (lambda (col size) (list col size nil)) columns-names widths)))) (defun display-table-in-buffer (columns-names rows) (let ((headers (make-tabulated-headers columns-names rows)) (bname "*display table*")) (with-current-buffer (get-buffer-create bname) (tabulated-list-mode) (setq tabulated-list-format headers) (setq tabulated-list-padding 2) (tabulated-list-init-header) (setq tabulated-list-entries (-zip-with (lambda (i x) (list i x)) (-iterate '1+ 0 (length rows)) rows)) (tabulated-list-print t) (popwin:popup-buffer bname)))) And here's a little demo to show how it works: .. code-block:: elisp (display-table-in-buffer '("Header 1" "Header 2" "Header 3" "#") '(["" "foo" "bar" "123"] ["abc" "def" "hij" "900"])) Notes & Customizations ---------------------- First of all, the whole thing is based off [tabulated-list-mode](https://www.gnu.org/software/emacs/manual/html_node/elisp/Tabulated-List-Mode.html) - a mode which is capable of a lot more than just pretty printing simple tables. Any serious customization should start by looking at what's available there. My wrapper of this mode adds some conveniences, but also limitations. For example, I automatically calculate the column widths based on the widest cell in a column. This is convenient for the kind of data that I deal with, but will not work for all cases. Also note the rows argument requires a list of strings vectors (no nulls!). A vector per row is required by ``tabulated-list-mode`` itself, so I felt little need to change that. Finally, I reuse the same ``*display table*`` buffer to output my tables. This works great for throwaway output, but not so well when you want to display 2 different tables for examples.