Skip to content

publicimageltd/lister

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Lister - Yet another List Printer

https://melpa.org/packages/lister-badge.svg

This is the documentation for Lister version 0.9.6

Lister= is a library for creating interactive lists of any kind. In contrast to similar packages like hierarchy.el or tablist.el, it aims at not simply mapping a data structure to a navigatable list. Rather, it treats the list buffer like Emacs treats text buffers: It is an empty space to which you successively add stuff. So Lister should actually be called Listed.

One advantage of this approach is that you don’t have to know in advance the structure of your data. You just “insert” a new slice on the fly when you need it. Another advantage is that you do not need to keep a separate copy of the list and worry about syncing: The buffer is the whole source of truth. Thus Lister recommends itself in all cases where it makes sense to collect, modify, thin out, graft, sort or otherwise edit lists from various sources.

Contents

Project status

Current release is 0.9.6

Feature overview

This is an overview of features done or planned. A feature is considered stable if it is used and tested by the auther. If it is rarely used, but seems to work, it just works.

FeatureStateAutomated tests?
build simple or large listsstableyes
build nested listsstableyes
retrieve data, with hierarchiesstableyes
loop over the liststableyes
marking or unmarking itemsstableyes
filter itemsstableyes
hide and show sublists outline-stylepartially buggynot enough
move items and sublistsworksyes
navigate within the hierarchyworksyes

Example

This piece of code creates a new buffer which displays lists of strings.

(let ((ewoc (lister-setup "BUFFERNAME" #'list)))
  ;; insert 4 items:
  (lister-set-list ewoc '("ITEM1" "ITEM2" "ITEM3" "ITEM4"))
  ;; add further items:
  (lister-add-list ewoc '("ITEM5" "ITEM6"))
  ;; add sublist:
  (lister-insert-sublist-below ewoc :first '("SUBITEM1" "SUBITEM2"))
  ;; move point:
  (lister-goto ewoc :first)
  (lister-goto ewoc :next)
  ;; get item data:
  (lister-get-data-at ewoc :point) ;; => "SUBITEM1"
  ;; get sublist at point:
  (lister-get-sublist-at ewoc :point) ;; => ("SUBITEM1" "SUBITEM2")
  ;; prepend "X" to each item:
  (lister-dolist (ewoc data :first :last node)
    (lister-replace-at ewoc node (concat "X" data)))
  ;; alternative, more functional way:
  (lister-update-list ewoc (lambda (data) (concat "X" data)))
  ;; filter every item containing the digit 1:
  (let ((filter (apply-partially #'string-match "1")))
    (lister-set-filter ewoc filter))
  ;; only get visible items:
  (lister-get-visible-list ewoc)
  ;; => (("XXSUBITEM2") "XXITEM2" "XXITEM3" "XXITEM4" "XXITEM5" "XXITEM6")
  ;; remove filter:
  (lister-set-filter ewoc nil)
  ;; collect the list values as a flat list:
  (lister-collect-list ewoc)
  ;; => ("XXITEM1" "XXSUBITEM1" "XXSUBITEM2" "XXITEM2"....)
  ;; get the data as a nested list:
  (lister-get-list ewoc)) ;; => ("XXITEM1" ("XXSUBITEM1" "XXSUBITEM2") "XXITEM2" ....) 

Design principle

Lister is based on the internal library Ewoc.el. Have a look at its info pages. The core idea is that we keep a double linked list which is “viewed” in the buffer, so that each change in the list will be reflected in the buffer using a function which pretty prints the data (model-view-controller pattern). Lister provides convenience functions on top of this core principle of Ewoc.el (and also corrects some of its bugs). A list item thus is basically a data item which is turned into a printable representation with a mapper function.

What does Lister offer?

  • Structured API to add, insert, delete or replace lists or list items. All positions can be indicated by passing either the containing Ewoc node, a zero-counting index position, or one of the symbols :first, :last, :next, :prev, :point.
  • Functions to return the next list item matching a predicate.
  • Macros to loop over the lists, or a part of it, and to deal safely with parts of the list (“regions”). The looping macros mimic the cl-dolist syntax; e.g. you can use (lister-dolist (data :first :last) ..BODY..) to loop over the whole list.
  • Functions to collect data which matches a predicate; and functions which can be used to do something with items (“updating” them).
  • Sublist handling: Recognize, insert, delete, replace, reverse or sort a sublist.
  • Visually filter items according to a predicate; offer some of the functionality above limited to visible items only.
  • Built-in functionality to mark items.

Some core concepts:

  • Mapper function: A buffer local function which turns a data item (a non-list lisp object) into a list of strings which will then be inserted in the buffer as its representation.
  • Hierarchy by indentation: Nested list hierarchies are built by visually indenting list items. Each item with the same indentation level belongs to the same nesting level. A sublist is thus defined by having an item with an indentation level greater than the one of its predecessor.
  • Data items cannot be lists: Since nested lists are recognized by simply being lists (consp), it is not possible to store lists as data items! If you need to store more complex data, use a vector or a defstruct instead.
  • No major mode: To use a buffer with lister, call lister-setup first. It prepares the buffer by setting some variables and erasing its content. It does not, however, set a specific major mode.
  • Keep common navigation keys: Each item is printed with the text property intangible set so that the user can only move point to the very first character of the printed item. You can thus use all basic navigation commands without any further ado, including isearch. You do not need to define any navigation commands.
  • Data, items and nodes: What is visually presented as a list item has three levels of structure: The Ewoc node, the Lister specific lister--item and the actual list data. This might cause some confusion, so here’s a short explanation: First, each visual list item corresponds to an Ewoc node. This node becomes relevant for all generic list functions, such as “looping over the list” or “deleting a specific region”. Secondly, each node contains a structure called lister--item. That structure keeps track of list specific information such as the indentation level or whether the item is visible. Finally, there is the actual data which is mapped and printed. This data is also a part of that Lister item structure which is stored in each node, but is treated distinctly since accessing it is the purpose of the whole library. To avoid semantic confusion, all functions applying to the node have a “node” somewhere in their function name. All other public functions usually refer to the data. To access the lister--item, you can use (ewoc-data node).

Bumps and Wrinkles

  • Lister operations become slower when the list grows above a thousand items. I would love to optimize it more for bigger lists once this becomes a real need.

Navigation and Marking with Lister Mode (minor mode)

There is a minor mode shipped with the package which provides some basic keybindings. Here’s the keymap:

KeyFunction
mMark item at point, or active region, or sublist if prefixed
uUnmark item at point, or active region, or sublist if prefixed
UUnmark all items in the buffer
M-up, M-downMove item at point one up, or down (prefix lifts level restriction)
M-left, M-rightIndent or unindent the item at point (prefix lifts level restriction)
S-M-up, S-M-downMove sublist at point one up, down
S-M-right, S-M-leftIndent or unindent sublist at point
<TAB>Cycle outline visibility of sublist below point
C-c C-b / C-c C-fMove forward or backward to next node with same level
C-c C-uMove to the next parent node
M-< / M->Move to the beginning or end of the current sublist or list.
C-c <C-up>Move up to the next child node
C-c <C-down>Move down to the next child node

The commands to mark and unmark also recognize the region. So you can mark the whole list by pressing C-x h m.

All navigation commands push point on mark if they jump more than one step.

If the keys M-< and M-> are pressed repeatedly, move out of the sublist to the next outer level list and finally to the top or bottom item.

API

Setting up the buffer

(lister-setup buf-or-name mapper &optional header footer)

You have to initialize a buffer in order to use it with Lister. The function lister-setup will either create a buffer with the given name, or erase the contents of an existing buffer. It then prepares the buffer by adding some text properties and setting some buffer local variables.

In addition to defining the buffer and the mapper function, you can optionally define a header or a footer. That can be either a string, or a list of strings, or a zero-argument function which, called in the Ewoc buffer, returns a string or a list of strings. The strings will be inserted before or after the actual list.

Use lister-set-{header/footer} to change the header or the footer. Pass the value nil to delete them. If the header or footer is defined by a function, use lister-refresh-header-footer to force a redisplay. To access the currently installed header or footer, use the Ewoc function ewoc-get-hf.

Lister-setup returns an ewoc object, which is then used as the basic reference for all Lister operations. The ewoc object is also stored in the buffer local variable lister-local-ewoc, which can be retreived with lister-get-ewoc.

The buffer local variable can be used to access the ewoc in an interactive function, like this:

(defun do-something (ewoc pos)
  "Do something at point."
  (interactive (list lister-local-ewoc :point))
  (when-let ((node (lister-get-node-at ewoc pos)))
    (message "You want to do something with %s."
             (lister-node-get-data node))))

See also lister-mode.el for some exemplary interactive functions and for a macro which helps to define them.

The mapper function

The mapper function is called for each item. It must return a list of strings representing the item.

Per default, the strings are inserted with the property intangible. If you want to insert special fields which can also do something, e.g. editable fields, you can set the field property to t. The region marked by this continuous property will not be intangible, that is, the cursor can move to it. Since one very likely use case of that feature is to insert buttons, the same rule applies to all characters which are marked with the property button.

Example:

(defun my-get-button (label &rest properties)
  "Make a button LABEL in a temporary buffer and return it as a string.
Pass PROPERTIES to `insert-text-button', which creates the
button."
  (with-temp-buffer
    (apply #'insert-text-button label properties)
    (buffer-string)))

(defun my-action (_)
  (message "I have been clicked!"))

(let ((ewoc (lister-setup "NEW "#'list)))
  (lister-set-list ewoc (list "Intangible item"
                              "Intangible item"
                              (my-get-button "Click me!"
                                'action 'my-action)))
  (switch-to-buffer (ewoc-buffer ewoc)))

Inserting, adding, deleting or replacing single items

;; Insert a single item at POS:
(lister-insert-at ewoc pos data &optional level insert-after)
;; Add to the end of the list:
(lister-add ewoc data &optional level)
;; Replace the item at POS:
(lister-replace-at ewoc pos data)
;; Delete the item at POS:
(lister-delete-at ewoc pos)

Per default, all insert operations insert at the position indicated, moving the previous content down. This might result in unintuitive results, e.g. (lister-insert-at ewoc :last data) adds the item at the second last position. Set insert-after to a non-nil value to insert after the position indicated (or use lister-add).

The same principle applies to interactive function which insert lists. If the cursor is at the bottom of the list, the intended meaning of “insert at point” is actually “add to the end of list”. The end of list can be recognized with the function (lister-eolp), so that the following code works:

(defun insert-something-at-point ()
  (interactive)
  (lister-insert-at lister-local-ewoc
                    :point
                    some-data
                    nil
                    ;; t means: add, don't insert!
                    (lister-eolp)))

Argument POS can be either an Ewoc node, an integer position, or one of the symbols :first, :last, :next, :prev, or :point.

The integer argument level determines the indentation level and can be used to begin a new sublist. Note that Lister automatically corrects too big values in order to ensure that every new level is just one level away from the item at POS. Thus you can safely use (lister-insert-at ewoc pos data 999) in order to begin a new sublist.

Inserting, adding, deleting or replacing lists of items

;; Erase all previous content and set a new list:
(lister-set-list ewoc data-list)
;; Insert a list at POS:
(lister-insert-list ewoc pos data-list &optional level insert-after)
;; Add a list to the end of the EWOC:
(lister-add-list ewoc data-list &optional level)
;; Replace the items from BEG to END with a new (possibly longer or shorter) list:
(lister-replace-list ewoc data-list beg end &optional level)
;; Delete all items from BEG to END:
(lister-delete-list ewoc beg end)
(lister-delete-all ewoc)

Argument POS can be either an Ewoc node, an integer position, or one of the symbols :first, :last, :next, :prev, or :point.

The integer argument level determines the indentation level and can be used to begin a new sublist. Note that Lister automatically corrects too big values in order to ensure that every new level is just one level away from the item at POS. Thus you can safely use (lister-insert-list ewoc pos data-list 999) in order to insert a whole sublist.

Getting the list data

;; Return the data of a single item:
(lister-get-data-at ewoc pos)
;; Return the data as a list (with sublists as nested lists):
(lister-get-list ewoc &optional beg end start-level pred)
;; Get the sublist at or below POS:
(lister-get-sublist-at ewoc pos)
(lister-get-sublist-below ewoc pos)
;; Map the data of a list (as a tree):
;; Node that PRED-FN and FN applies to the item data
(lister-map ewoc fn &optional pred-fn beg end start-level))

All functions (except lister-get-data, of course) return a list of data. Per default, they return the whole list. If there is a sublist in the specified region, return it as a nested list, e.g. ("A" ("SUB1" "SUB2") "B")). Multiple levels of indentation lead to multiply nested lists: ("A" (("SUBSUB1" "SUBSUB2")) "B").

Arguments POS, BEG and END can be either an Ewoc node, an integer position, or one of the symbols :first, :last, :next, :prev, or :point.

All of these functions ignore any active filter.

Normalizing boundaries

Since it is often necessary to operate on a sublist or the whole list, we have a macro to normalize these boundaries:

(lister-with-boundaries ewoc beg-var end-var
  ...BODY..)

This macro binds BEG-VAR and END-VAR according to the following scheme:

If the variables are already bound, use its value to determine the position. Then these variables are interpreted as a normal position. Allowed values are an Ewoc node, an integer position, or one of the symbols :first, :last, :point, :next or :prev. If the variables are undefined, bind them to the first and the last node of the list, respectively.

In short, if you use this macro in a function with the arguments BEG and END, and you can profit from automatic parsing these arguments and also be sure that while in BODY, BEG and END always have a valid value:

(defun a-function (ewoc beg end)
  "Do something within BEG and END. Both arguments can be a node,
an integer position, or one of the symbols `:point', `:first',
`:last', `:next' or `:prev'."
  (lister-with-boundaries ewoc beg end
    (do-something-with-node beg)))

All looping macros also normalize the region in the same way (see below).

Basic sublist handling

;; Doing something with a sublist below POS:
(lister-insert-sublist-below ewoc pos l)
(lister-delete-sublist-below ewoc pos l)
(lister-replace-sublist-below ewoc pos l)
;; Doing something with the sublist at POS:
(lister-delete-sublist-at ewoc pos l)
(lister-replace-sublist-at ewoc pos l)
;; Check if there is a sublist:
(lister-sublist-below-p ewoc pos)
(lister-sublist-at-p ewoc pos)
;;; Helpful macros:
;;
;; Execute BODY with the symbols BEG-SYM and END-SYM bound to the
;; boundaries of the sublist at POS. Do nothing if there is no
;; sublist.
(lister-with-sublist-at ewoc pos beg-sym end-sym
                        ....BODY...)
;; same as above, but looking for a sublist below POS:
(lister-with-sublist-below ewoc pos beg-sym end-sym
                           ....BODY...)

Argument POS can be either an Ewoc node, an integer position, or one of the symbols :first, :last, :next, :prev, or :point.

Marking

;; All marked items are highlighted by addding the value of that variable:
lister-mark-face-or-property 
;; Check if there are marked items:
(lister-marked-at-p ewoc pos)
(lister-items-marked-p ewoc &optional beg end)
(lister-count-marked-items ewoc &optional beg end)
;; Mark or unmark the item at POS:
(lister-mark-unmark-at ewoc pos state)
;; Set a limiting predicate:
(lister-set-marking-predicate ewoc pred)
;; Mark or unmark a whole list:
(lister-mark-unmark-list ewoc beg end state)
(lister-mark-unmark-sublist-at ewoc pos state)
(lister-mark-unmark-sublist-below ewoc pos state)
;; Get data of only the marked items:
(lister-get-marked-list ewoc &optional beg end pred-fn flatten?)
;; Do something with all marked nodes or items:
(lister-walk-marked-nodes ewoc action-fn &optional beg end marker-pred-fn)
(lister-walk-marked-list ewoc action-fn &optional beg end marker-pred-fn)

If STATE is nil, mark the item or the specified list items; else unmark them. Optionally set a buffer-local marking predicate using lister-set-marking-predicate. If this predicate is set, only mark items which satisfy it. Setting a new predicate will unmark alreay marked items which will not match it.

Note that in the case of walking nodes, ACTION-FN requires two arguments: the ewoc object and the node. The reason behind this is that if you choose do to something with the node rather with the data, it is very likely you will need the ewoc object.

Arguments POS, BEG and END can be either an Ewoc node, an integer position, or one of the symbols :first, :last, :next, :prev, or :point.

Sorting

;; Reverse the list items between BEG and END, or the whole list:
(lister-reverse-list ewoc &optional beg end)
;; Sort the list according to sorting predicate PRED:
(lister-sort-list ewoc pred &optional beg end)
;; Sort the list according to mulitple predicates in a row:
(lister-sort-list ewoc (list #'comp1 #'comp2) &optional beg end)
;; The same with sublists:
(lister-sort-sublist-at ewoc pos pred)
(lister-sort-sublist-below ewoc pos pred)
;; Reorder sublists using any kind of predicate:
(lister-reorder-sublist-at ewoc pos)
(lister-reorder-sublist-below ewoc pos)
;; Note that "reordering" uses a more complicate predicate function
;; than simple sorting. See the documentation of
;; `lister--reorder-wrapped-list' for a more detailed explanation.

Sorting or reversing a list keeps the individual mark state. Arguments POS, BEG and END can be either an Ewoc node, an integer position, or one of the symbols :first, :last, :next, :prev, or :point.

You can either pass a single comparator to the sorting function (such as string> or a list of comparators, which then will be applied successively (reduction). This is useful for sorting according to multiple criteria (e.g. first the name, then within the same name, ranking by the income, etc.).

A comparator function has direct access to the list data. So if you use a more complex data structure, do not forget to operate on the actual criteria and not on the containing object. E.g.:

(defstruct list-data name income)
(defun sort-it (ewoc)
  (cl-labels ((name> (a b) (string> (list-data-name a)
                                    (list-data-name b)))
              (income> (a b) (> (list-data-income a)
                                (list-data-income b))))
    (lister-sort-list ewoc (list #'name> #'income>))))
;; if you use the library dash.el:
(defun sort-it (ewoc)
  (lister-sort-list ewoc (list (-on #'string> #'list-data-name)
                               (-on #'>       #'list-data-income))))

Filter

;; Set and activate a filter predicate:
(lister-set-filter ewoc pred)
;; Check if filter is active:
(lister-filter-active-p ewoc)
;; Predicates:
(lister-node-visible-p)
(lister-node-marked-and-visible-p)
;; Return the filtered ('visible') list:
(lister-get-visible-list ewoc &optional beg end start-level)
;; Find 'visible' nodes matching a predicate:
(lister-next-visible-matching ewoc pos pred)
(lister-prev-visible-matching ewoc pos pred)
;; Return only data currently visible:
(lister-get-visible-list ewoc &optional beg end start-level)

The filter predicate PRED is a function which receives the list item’s data as its sole argument. The item is hidden if PRED returns a non-nil value (if it “matches” PRED).

Arguments POS, BEG and END can be either an Ewoc node, an integer position, or one of the symbols :first, :last, :next, :prev, or :point.

Outline

You can hide or show sublists as an outline:

;; Hide the sublist below POS as an outline:
(lister-outline-hide-sublist-below ewoc pos)
;; Show it:
(lister-outline-show-sublist-below ewoc pos)
;; Cycle it:
(lister-outline-cycle-sublist-below ewoc pos)
;; Show all hidden outlines:
(lister-outline-show-all ewoc)

Arguments POS, BEG and END can be either an Ewoc node, an integer position, or one of the symbols :first, :last, :next, :prev, or :point.

Finding nodes

  ;; From POS, find the next or prev node where the data matches PRED:
  (lister-next-matching ewoc pos pred &optional limit)
  (lister-prev-matching ewoc pos pred &optional limit)
  ;; same as above, but only consider visible items:
  (lister-next-visible-matching pos pred &optional limit)
  (lister-prev-visible-matching pos pred &optional limit)
;; Find the first or last node of the sublist around POS:
(lister-top-sublist-node ewoc pos)
(lister-bottom-sublist-node ewoc pos)
;; Find the parent of the sublist around POS:
(lister-parent-node ewoc pos)
;; Find the first sublist node looking in DIRECTION from POS:
(lister-first-sublist-node ewoc pos direction)

Argument POS can be either an Ewoc node, an integer position, or one of the symbols :first, :last, :next, :prev, or :point.

Argument limit is a position (a node, an index value or one of the symbols :first, :last, :point, :next or :prev, which limits the search. The search stops when reaching the limit and returns nil, even if the node at limit matches pred-fn.

Note that the generic searching functions (which require a predicate function) ignore visibility status, whereas the sublist functions listed in this section don’t return invisible items. Other sublist functions, however, might not check for visibility.

Looping

Most generally, you can access nodes or data items within the body of a looping macro or using a function. Most looping facilities come in two flavors, marked by the last word of the function name. Functions ending with -list loop over the item data (that which is printed); functions ending with -nodes loop over the item node (the lister--item structure in which the data is stored). As a rule of thumb, you should use -list functions if you are just concerned with the data, and -nodes functions if you need to explicitly know if a node is marked or invisible.

Basic macros, imperative style:

;; Basic macro to loop over NODES (not items!)
(lister-dolist-nodes (ewoc var-name &optional beg end))
;; same with items:
(lister-dolist (ewoc var-name &optional beg end node-var-name))
;;; Examples:
;; Delete the whole list:
(lister-dolist-nodes (ewoc node :first :last)
  (lister-delete-at ewoc node))
;; Return t if one list item matches X:
(lister-dolist (ewoc data)
  (when (equal data x)
    (cl-return t)))

The body of the loop macros are all wrappend in an implicit cl-block. To quit the loop immediately, use (cl-return).

More specific functions, more functional style:

;; Collect and maybe map all items between BEG and END:
(lister-collect-list ewoc &optional beg end pred-fn map-fn)
;; same with nodes:
(lister-collect-nodes ewoc &optional beg end pred-fn map-fn)
;; Modifiy the data and redisplay it:
(lister-update-list ewoc action-fn &optional beg end pred-fn)
;; Do something with each node (not item):
(lister-walk-nodes ewoc action-fn &optional beg end pred-fn)
;; see also (documented somewhere else in that file):
;; - lister-walk-marked-{list/nodes} for looping over all marked items
;; - lister-map for mapping

All functions operate on the items specified by BEG and END or on the whole list. Optionally operation can be restricted to those items matching PRED-FN.

Note that in the case of lister-collect-list and lister-update-list, PRED-FN is called with the item’s data (that which is printed), while lister-collect-nodes and lister-walk-nodes operate on the complete node. In the latter case, PRED-FN is called with the complete lister--item object, the printed data being only one slot of that encompassing structure.

When collecting stuff, map-fn can be used to further transform the data item.

When updating a list, action-fn receives a data object. If it returns nil, it leaves the corresponding item unchanged, else it updates its value with the new value and redisplays the node.

Note that in the case of walking nodes, ACTION-FN requires two arguments: the ewoc object and the node. The reason behind this is that if you choose do to something with the node rather with the data, it is very likely you will need the ewoc object.

Arguments BEG and END can be either an Ewoc node, an integer position, or one of the symbols :first, :last, :next, :prev, or :point.

Interactive editing

;; Move items vertically. Per default, only move to
;; items with the same indentation level:
(lister-move-item-up ewoc pos &optional ignore-level)
(lister-move-item-down ewoc pos &optional ignore-level)
;; Move items horizontally:
(lister-move-item-right ewoc pos)
(lister-move-item-left ewoc pos)
;; Move sublists:
(lister-move-sublist-up ewoc pos)
(lister-move-sublist-down ewoc pos)

Argument POS can be either an Ewoc node, an integer position, or one of the symbols :first, :last, :next, :prev, or :point.

Modified flag

Since Lister is intended to offer editing facilities, there’s also a modified flag. It is stored in the buffer local variable lister-local-modified.

The modified flag will be set to t each time an item is deleted, inserted, or its content is changed. Since moving also internally works with deleting and inserting, it will also trigger the modified flag.

;; Buffer local modified flag
lister-local-modified
;; Get the value of the modified flag
(lister-modified-p ewoc)
;; Set the value
(lister-set-modified-p ewoc &optional flag)

It is recommended to add a variable watcher to display the modified flag (e.g. in the header of the list or in the modeline).

Miscellaneous

 ;; Check if the list is empty:
 (lister-empty-p ewoc)
 ;; Check if a node is part of the list from beg to end:
 (lister-node-in-region-p node beg end)
 ;; Move point:
 (lister-goto ewoc pos)
 ;; Manually re-set the level of an item:
 (lister-set-level-at ewoc pos)
 (lister-get-level-at ewoc pos)
 ;; Redisplay an item (e.g. if its data has changed):
 (lister-refresh-at ewoc pos)
 (lister-refresh-list ewoc beg end) 
;; Retain position when updating display: Execute BODY, then return
;; to the node at point before BODY.  Useful when updating the
;; display, and the items change (because this moves the cursor)
(lister-save-current-node BODY)

Arguments POS, BEG and END can be either an Ewoc node, an integer position, or one of the symbols :first, :last, :next, :prev, or :point.

Padding and indentation of the levels is regulated by the following variables:

;; integer: add so many whitespaces in front of each item
lister-local-left-margin
;; string: add this string in front of each item according to the item's level
;; level 0 means no padding; level 1 means one time; 2 means 2 time, etc.
lister-local-padding-string

Known Bugs and Limitations

Outline Visibility Cycling

Current visibility cycling uses the invisibility-spec and is not recognized internally by the lister commands. So while hiding an item using the filter function is mostly taken care of, hiding items using invisibility-spec might lead to inconsistent behavior when jumping around the list, or when adding or removing items.

Changelog

0.9.6

  • Fix bug in lister–outline-invisible-p

0.9.5

  • lister-mode: Silently exit view-mode on entering lister-mode, if necessary.
    • Add option “LIMIT” to lister-next-matching and lister-next-visible-matching
    • Add hierarchical navigation keys to lister-mode (move to parent, move forward or backward same level, move to beginning or end of the sublist), fixing Issue #3

0.9.4

  • Add sorting with multiple predicates / criteria.

0.9.3.

  • Add “modified” flag.

0.9.2

  • Add lister-save-current-node
  • Add marking predicate (thanks to Nathanael kinfe)
  • Add function to get the buffer local ewoc (thanks to Nathanael kinfe)
  • Add convenience functions to ‘reorder’ sublists (thanks to Nathanael kinfe)
  • Add mapping function
  • New feature: header or footer can now also be a function.
  • New feature: item strings with fields button or field set will not be intangible and can be reached with normal cursor motion, while the rest of the item remains inaccessible.
  • Add new public functions lister-items-marked-p, lister-eolp.
  • Bugfixes, internal refactoring.

0.9.1

  • Some bugfixes; add more tests.
  • Added minor-mode.
  • Added functions to move items and sublists.
  • Added outline style hiding of sublists.

0.9

  • Rewrite the whole package basing it now on Ewoc.