3.3.3 The elmpd-chain Macro

It sometimes happens that one would like to issue a command depending on the results of a prior command, for instance the following snippet will raise the volume to fifty if it’s not already at least that high already:

(let ((conn (elmpd-connect :host "localhost")))
  (elmpd-send 
   conn
   "getvol"
   (lambda (_conn ok rsp)
     (if ok
         (let ((vol (string-to-number (substring rsp 7 -1))))
           (if (< vol 50)
               (elmpd-send
                conn
                "setvol 50"
                (lambda (_conn ok rsp)
                  (if ok
                      (message "Increased volume from %d to 50." vol)
                    (message "Failed to increase volume: %s" rsp))))))
       (error "Failed to get volume: %s" rsp)))))

This quickly becomes inconvenient & difficult to read. In any such non-trivial case, the elmpd-chain macro can make this easier:

(let ((conn (elmpd-connect :host "localhost"))
      (vol 0))
  (elmpd-chain
   conn
   ("getvol"
    (lambda (_conn rsp)
      (setq vol (string-to-number (substring rsp 7 -1)))))
   :or-else
   (lambda (_conn rsp) (error "Failed to get volume: %s" rsp))
   :and-then
   ((format "setvol %d" (max 50 vol))
    (lambda (_ _) (message "Set volume to %d." vol)))
   :or-else
   (message "Failed to increase volume: %s" rsp)))

The general format is:

(elmpd-chain
 conn
 CMD
 [:or-else ELSE-HANDLER]
 [:and-then
   [CMD OR-ELSE? AND-THEN...])

where CMD may be any of:

  1. A single value cmd
  2. a list with two elements cmd, cb
  3. a list with three elements cmd, cb, style

In any case, cmd may be either a string (for a simple command), or a list of strings (for a command list). In case 3, if cmd is a string, then style must be 'default. Note that the callback will be invoked with just two arguments (the connection and the response), since it will only be invoked on success (you can place failure logic in an :or-else clause). Similarly, :or-else handlers are also invoked with just two arguments, since it will only be invoked on failure.

Macro: elmpd-chain conn args

Chain multiple commands on conn.