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:
cmd
cmd, cb
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.
Chain multiple commands on conn.