How I shortlist add-ons for my Emacs: Introducing `tablist`

In this article , you will learn about package tablist 1.

What is tablist?

tablist describes itself as an

Extended tabulated-list-mode

This package adds marks and filters to tabulated-list-mode. It also puts a dired face on tabulated list buffers.

It can be used by deriving from tablist-mode, or with more limited features by enabling tablist-minor-mode inside a tabulated-list-mode buffer.

If you are new to Emacs, the above description will make very little sense.  But the good thing is you need not understand any of this jargon to make use of tablist.  By the end of this article, you would know how to put tablist to best use.

Purpose of this article

In this article, you will learn how to use tablist, in the context of Emacs Package Manager 1.  Specifically, you will use tablist-minor-mode to  shortlist a few custom light themes of your liking.  And in the process, you will learn the most useful features of tablist-minor-mode.

Step 1:  Download and Install tablist

Download and install the package tablist(1). This package is available at MELPA,(1) the Milkypostman’s Emacs Lisp Archive. If you are new to installing packages, see my earlier article (1).

Step 2: Create a menu for tablist

Copy the Emacs Lisp snippet(1)  below to your .emacs and restart your Emacs.

This snippet

  1.  adds tablist-minor-mode to  tabulated-list-mode-hook.  This way all buffers that usetabulated-list-mode, including the package-menu-mode buffers, can exploit additional features available from tablist-minor-mode.
  2. adds the following menus to the menu-bar:
    • Tablist Column
    • Tablist Filter
    • Tablist Mark
    • Tablist Misc
(add-hook 'tabulated-list-mode-hook 'tablist-minor-mode)

(with-eval-after-load 'tablist
  (easy-menu-define my-tablist-minor-mode-map-misc-menu tablist-minor-mode-map "Menu for Tablist Minor Mode Map."
    '("Tablist Misc"
      ["Sort" tablist-sort :help "(tablist-sort &optional COLUMN)\n\nSort the tabulated-list by COLUMN.\n\nCOLUMN may be either a name or an index.  The default compare\nfunction is given by the `tabulated-list-format', which see.\n\nThis function saves the current sort column and the inverse\nsort-direction in the variable `tabulated-list-sort-key', which\nalso determines the default COLUMN and direction.\n\nThe main difference to `tabulated-list-sort' is, that this\nfunction sorts the buffer in-place and it ignores a nil sort\nentry in `tabulated-list-format' and sorts on the column\nanyway (why not ?)."]
      ["Do Kill Lines" tablist-do-kill-lines :help "(tablist-do-kill-lines &optional ARG INTERACTIVE)\n\nRemove ARG lines from the display."]
      ["Export Csv" tablist-export-csv :help "(tablist-export-csv &optional SEPARATOR ALWAYS-QUOTE-P INVISIBLE-P OUT-BUFFER DISPLAY-P)\n\nExport a tabulated list to a CSV format.\n\nUse SEPARATOR (or ;) and quote if necessary (or always if\nALWAYS-QUOTE-P is non-nil).  Only consider non-filtered entries,\nunless invisible-p is non-nil.  Create a buffer for the output or\ninsert it after point in OUT-BUFFER.  Finally if DISPLAY-P is\nnon-nil, display this buffer.\n\nReturn the output buffer."]
      ["Previous Line" tablist-previous-line :help "(tablist-previous-line &optional N)"]
      ["Next Line" tablist-next-line :help "(tablist-next-line &optional N)"]
      ["Revert" tablist-revert :help "(tablist-revert)\n\nRevert the list with marks preserved, position kept."]
      ["Quit" tablist-quit :help "(tablist-quit)"]))

  (easy-menu-define my-tablist-minor-mode-map-mark-menu tablist-minor-mode-map "Menu for Tablist Minor Mode Map."
    '("Tablist Mark"
      ["Mark Items Regexp" tablist-mark-items-regexp :help "(tablist-mark-items-regexp COLUMN-NAME REGEXP)\n\nMark entries matching REGEXP in column COLUMN-NAME."]
      ["Mark Items Numeric" tablist-mark-items-numeric :help "(tablist-mark-items-numeric BINOP COLUMN-NAME OPERAND)\n\nMark items fulfilling BINOP with arg OPERAND in column COLUMN-NAME.\n\nFirst the column's value is coerced to a number N.  Then the test\nproceeds as (BINOP N OPERAND)."]
      ["Mark Forward" tablist-mark-forward :help "(tablist-mark-forward &optional ARG INTERACTIVE)\n\nMark ARG entries forward.\n\nARG is interpreted as a prefix-arg.  If interactive is non-nil,\nmaybe use the active region instead of ARG.\n\nSee `tablist-put-mark' for how entries are marked."]
      ["Unmark Forward" tablist-unmark-forward :help "(tablist-unmark-forward &optional ARG INTERACTIVE)\n\nUnmark ARG entries forward.\n\nSee `tablist-mark-forward'."]
      ["Unmark Backward" tablist-unmark-backward :help "(tablist-unmark-backward &optional ARG INTERACTIVE)\n\nUnmark ARG entries backward.\n\nSee `tablist-mark-forward'."]
      ["Change Marks" tablist-change-marks :help "(tablist-change-marks OLD NEW)\n\nChange all OLD marks to NEW marks.\n\nOLD and NEW are both characters used to mark files."]
      ["Toggle Marks" tablist-toggle-marks :help "(tablist-toggle-marks)\n\nUnmark all marked and mark all unmarked entries.\n\nSee `tablist-put-mark'."]
      ["Unmark All Marks" tablist-unmark-all-marks :help "(tablist-unmark-all-marks &optional MARKS INTERACTIVE)\n\nRemove alls marks in MARKS.\n\nMARKS should be a string of mark characters to match and defaults\nto all marks.  Interactively, remove all marks, unless a prefix\narg was given, in which case ask about which ones to remove.\nGive a message, if interactive is non-nil.\n\nReturns the number of unmarked marks."]))

  (easy-menu-define my-tablist-minor-mode-map-filter-menu tablist-minor-mode-map "Menu for Tablist Minor Mode Map."
    '("Tablist Filter"
      ["Push Regexp Filter" tablist-push-regexp-filter :help "(tablist-push-regexp-filter COLUMN-NAME REGEXP)\n\nAdd a new filter matching REGEXP in COLUMN-NAME.\n\nThe filter is and'ed with the current filter.  Use\n`tablist-toggle-first-filter-logic' to change this."]
      ["Push Equal Filter" tablist-push-equal-filter :help "(tablist-push-equal-filter COLUMN-NAME STRING)\n\nAdd a new filter whre string equals COLUMN-NAME's value.\n\nThe filter is and'ed with the current filter.  Use\n`tablist-toggle-first-filter-logic' to change this."]
      ["Push Numeric Filter" tablist-push-numeric-filter :help "(tablist-push-numeric-filter OP COLUMN-NAME 2ND-ARG)\n\nAdd a new filter matching a numeric predicate.\n\nThe filter is and'ed with the current filter.  Use\n`tablist-toggle-first-filter-logic' to change this."]
      ["Pop Filter" tablist-pop-filter :help "(tablist-pop-filter &optional N INTERACTIVE)\n\nRemove the first N filter components."]
      ["Negate Filter" tablist-negate-filter :help "(tablist-negate-filter &optional INTERACTIVE)\n\nNegate the current filter."]
      ["Suspend Filter" tablist-suspend-filter :style toggle :selected tablist-filter-suspended :help "(tablist-suspend-filter &optional FLAG)\n\nTemporarily disable filtering according to FLAG.\n\nInteractively, this command toggles filtering."]
      ["Clear Filter" tablist-clear-filter :help "(tablist-clear-filter)"]
      ["Toggle First Filter Logic" tablist-toggle-first-filter-logic :help "(tablist-toggle-first-filter-logic)\n\nToggle between and/or for the first filter operand."]
      ["Display Filter" tablist-display-filter :style toggle :selected (assq 'tablist-display-filter-mode-line-tag mode-line-format) :help "(tablist-display-filter &optional FLAG)\n\nDisplay the current filter according to FLAG.\n\nIf FLAG has the value 'toggle, toggle it's visibility.\nIf FLAG has the 'state, then do nothing but return the current\nvisibility."]
      ["Edit Filter" tablist-edit-filter :help "(tablist-edit-filter)"]
      ["Name Current Filter" tablist-name-current-filter :help "(tablist-name-current-filter NAME)"]
      ["Push Named Filter" tablist-push-named-filter :help "(tablist-push-named-filter NAME)\n\nAdd a named filter called NAME.\n\nNamed filter are saved in the variable `tablist-named-filter'."]
      ["Delete Named Filter" tablist-delete-named-filter :help "(tablist-delete-named-filter NAME &optional MODE)"]
      ["Deconstruct Named Filter" tablist-deconstruct-named-filter :help "(tablist-deconstruct-named-filter)"]))

  (easy-menu-define my-tablist-minor-mode-map-column-menu tablist-minor-mode-map "Menu for Tablist Minor Mode Map."
    '("Tablist Column"
      ["Forward Column" tablist-forward-column :help "(tablist-forward-column N)\n\nMove n columns forward, while wrapping around."]
      ["Backward Column" tablist-backward-column :help "(tablist-backward-column N)\n\nMove n columns backward, while wrapping around."]
      ["Move To Major Column" tablist-move-to-major-column :help "(tablist-move-to-major-column &optional FIRST-SKIP-INVISIBLE-P)\n\nMove to the first major column."]
      ["Shrink Column" tablist-shrink-column :help "(tablist-shrink-column &optional COLUMN WIDTH)"]
      ["Enlarge Column" tablist-enlarge-column :help "(tablist-enlarge-column &optional COLUMN WIDTH)\n\nEnlarge column COLUMN by WIDTH.\n\nThis function is lazy and therfore pretty slow."])))

;; (provide 'my-tablist-minor-mode-menu)

Step 3: Ensure that you have set up the above snippet correctly

Once you restart you Emacs,  launch the package manager.

When viewing ​​*Packages*, your menu-bar should see entries for Tablist in the menu-bar.   See the GIF below for details.  If you aren’t seeing these in the menu, repeat the earlier steps.


tablist-minor-mode-overview 2019-04-16


Spend some time reviewing the above menus.   The items there give a good overview of the key features available in tablist-minor-mode.

Step 4: Use tablist to filter out packages that interest you

As mentioned above, you will use tablist to filter a few recently released light themes.

The steps are

  1. Launch the package manager.  Assuming that you have added MELPA as one of your package archives, you will see thousands of packages.  In my specific run, I saw around 4500 packages.
  2. Filter for packages whose `name’ mentions the word `theme’.  Once that is done, your list will narrow down from few thousands to few hundreds.  In my specific run, I saw close to 250 themes.
  3. Filter for packages whose `description’ mentions the word `light’.  Now the list  will narrow down from few hundreds to few tens.  I see around Around 40 lighter themes.
  4. Mark  packages that has word `2019′ in it’s `version‘.  tablist marks packages  with * as marker.  But for the purpose of installation, package-menu expects I as marker.
  5. Change the markers from * to I
  6. Install the packages

In my specific run, I ran in to a bug at step 6.  I take this adversity as an opportunity to demonstrate the following

  1. Create a named filter for light themes
  2. Re-apply this filter later on a fresh package list, and verify the status of packages installed in the the previous run

See the GIF below for details.


tablist-minor-mode 2019-04-16


Concluding Words (on tablist)

The Emacs’ official way of shortlisting of packages is via Package Keywords.  I find the use of keywords not only very pedantic, but very limiting.  The limitation of keywords becomes particularly glaring when one deals with repositories like MELPA.  Such repositories have a very lax review process, and the packages keywords may neither be complete or reliable.   In that case, I find tablist a very useful tool to have in my kit.

That said, let you not come to the conclusion that tablist is useful only with Package Manager.  It is useful in any buffer that uses tabulated-list-mode.

Note that we have explored only a subset of features offered by the tablist in it’s minor-mode avatar.  The tablist-mode,  the major mode, offers much more useful features like editing  of columns etc.  This major mode is used by the very wonderful pdf-tools(1), (2) package for managing annotations(1) and for displaying search hits(1)

Some suggestions for improving tablist

In an earlier article (1), I have discussed the same use-case—shortlist add-ons—as this article, but relied on package loccur.  In that article, I use loccur to filter not only based on the Package column but also on the marker column.   While preparing the above demonstration, I have found that tablist does NOT allow filtering based on the values of markers.   The loccur article gives a concrete use-case on the usefulness of filtering based on marker values.

Also, don’t forget the bug that I encountered duringthe demonstration.

Categories gnu

1 thought on “How I shortlist add-ons for my Emacs: Introducing `tablist`

  1. That snippet looks great. Do you think you can package it and put it up on melpa? When enabling it in package mode I get a problem with S-U. Normally it is bound to package-menu-mark-upgrades, but after evaluating it, S-U seem to be bound to tablist-unmark-all-marks.


Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this:
search previous next tag category expand menu location phone mail time cart zoom edit close