I'm currently writing a major mode (for interacting with a remote Grid Engine) which involves fetching data, parsing it into an alist, formating the alist into a string and then inserting the formatted string into a buffer. This is done for many rows of data.
Now I want to add a way for users to interact with the data in the buffer, e.g. to tab from one field to the next, or to press RET on a field to invoke a function on it.
It seems silly to me to "lose" the underlying data structure after rendering it to the buffer. Parsing the line at point (e.g. with (thing-at-point 'word)
) to partially recover the data structure just seems like a bad idea.
Here's an example of one of these alists:
((job-id . 123)
(priority . 0.844)
(name . "some job name")
(owner . "rekado")
(state . "r")
(time . "2014-10-24")
(queue . "standard")
(slots . 12))
This may be rendered with a format string like this:
(defun format-job-record (job)
(format ""%-10s %-10s %-15s %-10s\n"
(cdr (assoc 'job-id job))
(cdr (assoc 'priority job))
(cdr (assoc 'owner job))
(cdr (assoc 'state job))))
Is there an alternative way (an idiom perhaps), that allows me to specify a way to display this alist while keeping the underlying data intact? I would like to be able to retrieve the whole alist when point is on the row, and any given field when point is on the rendered text for the field.
I think this might be done by storing the alist as special properties on the generated string, and by storing the field keys along with each individual field string, but I'm not sure if this is the best way to do it.
My goal is to separate representation in the buffer from the underlying data and only work on data structures instead of text.
What is the most "natural" approach to achieve this?
EDIT:
Is there a better more "disciplined" approach than what is outlined in my answer below, or are custom text properties the idiomatic way to go?