[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

docs for ewoc.el, rev 3

From: Thien-Thi Nguyen
Subject: docs for ewoc.el, rev 3
Date: Sun, 21 May 2006 11:10:13 +0200

based on feedback from various people (many thanks!), i have revised the
proposed docs for ewoc.el.  there are now two sub-nodes under the intro
text, which has been largely rewritten.

note that `ewoc-filter' docs reflect not-yet-checked-in functionality.
see "ewoc--node-delete" thread.


@node Abstract Display
@section Abstract Display
@cindex ewoc
@cindex display, abstract
@cindex display, arbitrary objects
@cindex model/view/controller
@cindex view part, model/view/controller

  The ewoc package constructs buffer text that represents a structure of
Lisp objects, and updates the text to follow changes in that structure.
This facility can be considered the ``view'' part of a program written
in the ``model/view/controller'' style.

  An @dfn{ewoc} is a structure that organizes information required to
construct the buffer text, which has three parts, in order: the
@dfn{header} text, a series of zero or more textual representations of
Lisp objects, and the @dfn{footer} text.  Specifically, an ewoc contains
information on:

@item the buffer which contains this text

@item the text's start position

@item the header and the footer

@item the ordered set of @dfn{nodes}, each of which contains:

@item the @dfn{data element}, a single Lisp object

@item information on the node's @dfn{neighbors}, i.e., references to the
immediately preceding and following node in the set
@end itemize

@item the @dfn{pretty-printer}, a function that is responsible for
constructing and inserting a textual representation of a data element
into the buffer (using @code{insert})
@end itemize

  Typically, you define an ewoc with @code{ewoc-create}, and then pass
the resulting structure around to the other functions in the package to
add nodes (in arbitrary order), determine the correspondance between
point and node, move point from one node's textual representation to
another, and so forth.  @xref{Abstract Display Functions}.

  A node @dfn{encapsulates} a data element much like a variable holds a
value.  Normally, encapsulation occurs as a part of adding a node to
the ewoc.  You can use @code{ewoc-data} to both retrieve the data
element and to place a new element in its place, like so:

(ewoc-data NODE)
@result{} value

(setf (ewoc-data NODE) NEW-DATA)
@result{} NEW-DATA
@end lisp

If you do not wish to use @code{setf}, consider arranging for the data
to be either a container (list or vector), or an index into some other
structure.  The example (@pxref{Abstract Display Example}) uses the
latter approach.  Both approaches have the same consequence: you can
modify the container's elements directly and completely avoid using
@code{(setf (ewoc-data @dots{}) @dots{})}.

  When the data changes, you can arrange to call the specified
pretty-printer to @dfn{update} the buffer text with @code{ewoc-refresh}
(all nodes), @code{ewoc-invalidate} (specified nodes), or
@code{ewoc-map} (nodes satisfying a predicate).  Alternatively, you can
delete the affected nodes with @code{ewoc-filter} and add new ones in
their place.

* Abstract Display Functions::
* Abstract Display Example::
@end menu

@node Abstract Display Functions
@subsection Abstract Display Functions

  In this subsection, @var{ewoc} and @var{node} stand for the structures
described above (@pxref{Abstract Display}), while @var{data} and
@dfn{data element} stand for an arbitray Lisp object.

@defun ewoc-create pretty-printer &optional header footer
This constructs and returns a new ewoc, with no data elements.
@var{pretty-printer} should be a function that takes one argument,
a data element, and inserts at point its textual representation,
using @code{insert} (and not @code{insert-before-markers}).
@end defun

@defun ewoc-buffer ewoc
This returns the buffer where @var{ewoc} was created.
@end defun

@defun ewoc-get-hf ewoc
This returns a cons cell @code{(@var{header} . @var{footer})}
made from @var{ewoc}'s header and footer.
@end defun

@defun ewoc-set-hf ewoc header footer
This sets the header and footer of @var{ewoc} to the strings
@var{header} and @var{footer}, respectively.
@end defun

@defun ewoc-enter-first ewoc data
@defunx ewoc-enter-last ewoc data
These construct a new node encapsulating @var{data}, adding it to
@var{ewoc} at the beginning or end, respectively, of the set of ordered
@end defun

@defun ewoc-enter-before ewoc node data
@defunx ewoc-enter-after ewoc node data
These construct a new node encapsulating @var{data}, adding it to
@var{ewoc} before or after @var{node}, respectively.
@end defun

@defun ewoc-prev ewoc node
@defunx ewoc-next ewoc node
These return the previous and next node, respectively, of @var{node}
in @var{ewoc}.
@end defun

@defun ewoc-nth ewoc n
This returns the node in @var{ewoc} found at zero-based index @var{n}.
A negative @var{n} means count from the end.  @code{ewoc-nth} returns
@code{nil} if there are less than @var{n} elements.
@end defun

@defun ewoc-data node
This extracts the data encapsulated by @var{node} and returns it.
@end defun

@defun ewoc-locate ewoc &optional pos guess
This determines the node in @var{ewoc} which contains point (or
@var{pos} if specified), and returns that node.  If @var{ewoc} is empty,
it returns @code{nil}.  If @var{pos} is before the first node or after
the last node, it returns that node.  Optional third arg @var{guess}
should be a node that is likely to be near @var{pos}.
@end defun

@defun ewoc-location node
This returns the start position of @var{node}.
@end defun

@defun ewoc-goto-prev ewoc arg
@defunx ewoc-goto-next ewoc arg
These move point to the previous or next, respectively, @var{arg}th node
in @var{ewoc}.  @code{ewoc-goto-prev} does not move if it is already at
the first node or if @var{ewoc} is empty, whereas @code{ewoc-goto-next}
moves past the last node, returning @code{nil}.  Excepting this special
case, these functions return the node moved to.
@end defun

@defun ewoc-goto-node ewoc node
This moves point to the start of @var{node} in @var{ewoc}.
@end defun

@defun ewoc-refresh ewoc
This deletes the region bounded by the header end and the footer
beginning in @var{ewoc}, i.e., all the data elements' representations,
and then calls the pretty-printer function for each node, in order.
@end defun

@defun ewoc-invalidate ewoc &rest nodes
This is similar to @code{ewoc-refresh}, except that only @var{nodes} in
@var{ewoc} are updated instead of the entire set.
@end defun

@defun ewoc-filter ewoc predicate &rest args
This calls @var{predicate} for each data element in @var{ewoc} and
removes those nodes for which @var{predicate} returns @code{nil}.  Any
@var{args} are passed to @var{predicate}.  As a special case, if
@var{predicate} is @code{t}, @var{args} specifies nodes to be deleted
@end defun

@defun ewoc-collect ewoc predicate &rest args
This calls @var{predicate} for each data element in @var{ewoc}
and returns a list of those elements for which @var{predicate}
returns address@hidden  The elements in the list are ordered
as in the buffer.  Any @var{args} are passed to @var{predicate}.
@end defun

@defun ewoc-map map-function ewoc &rest args
This calls @var{map-function} for each data element in @var{ewoc} and
updates those nodes for which @var{map-function} returns address@hidden
Any @var{args} are passed to @var{map-function}.
@end defun

@node Abstract Display Example
@subsection Abstract Display Example

  Here is a simple example using functions of the ewoc package to
implement a ``color components display'', an area in a buffer that
represents a vector of three integers (itself representing a 24-bit RGB
value) in various ways.

(defvar colorcomp-ewoc nil)
(defvar colorcomp-data nil)

(defvar colorcomp-labels ["Red" "Green" "Blue"])

(defvar colorcomp-mode-map nil)

(defun colorcomp-pp (data)
  (if data
      (let ((comp (aref colorcomp-data data)))
        (insert (aref colorcomp-labels data) "\t: #x"
                (format "%02X" comp) " "
                (make-string (ash comp -2) ?#) "\n"))
    (let ((cstr (format "#%02X%02X%02X"
                        (aref colorcomp-data 0)
                        (aref colorcomp-data 1)
                        (aref colorcomp-data 2)))
          (samp " (sample text) "))
      (insert "Color\t: "
              (propertize samp 'face `(foreground-color . ,cstr))
              (propertize samp 'face `(background-color . ,cstr))

(defun colorcomp (color)
  "Allow fiddling with COLOR in a new buffer.
The buffer is in Color Components mode."
  (interactive "sColor (name or #RGB or #RRGGBB): ")
  (when (string= "" color)
    (setq color "green"))
  (unless (color-values color)
    (error "No such color: %S" color))
   (generate-new-buffer (format "originally: %s" color)))
  (setq major-mode 'colorcomp-mode
        mode-name "Color Components")
  (use-local-map colorcomp-mode-map)
  (let ((data (apply 'vector (mapcar (lambda (n) (ash n -8))
                                     (color-values color))))
        (ewoc (ewoc-create 'colorcomp-pp
                           "\nColor Components\n\n"
    (set (make-local-variable 'colorcomp-data) data)
    (set (make-local-variable 'colorcomp-ewoc) ewoc)
    (ewoc-enter-last ewoc 0)
    (ewoc-enter-last ewoc 1)
    (ewoc-enter-last ewoc 2)
    (ewoc-enter-last ewoc nil)))
@end example

  This example can be extended to be a ``color selection widget'' by
defining commands to modify @code{colorcomp-data} and to ``finish'' the
selection process, and a keymap to tie it all together conveniently.

(defun colorcomp-mod (index limit delta)
    (let ((cur (aref colorcomp-data index))
          (ewoc colorcomp-ewoc))
      (unless (= limit cur)
        (aset colorcomp-data index (+ cur delta)))
       (ewoc-nth ewoc index)
       (ewoc-nth ewoc -1)))))

(defun colorcomp-R-more () (interactive) (colorcomp-mod 0 255 1))
(defun colorcomp-G-more () (interactive) (colorcomp-mod 1 255 1))
(defun colorcomp-B-more () (interactive) (colorcomp-mod 2 255 1))
(defun colorcomp-R-less () (interactive) (colorcomp-mod 0 0 -1))
(defun colorcomp-G-less () (interactive) (colorcomp-mod 1 0 -1))
(defun colorcomp-B-less () (interactive) (colorcomp-mod 2 0 -1))

(defun colorcomp-copy-as-kill-and-exit ()
  "Copy the color components into the kill ring and kill the buffer.
The string is formatted #RRGGBB (hash followed by six hex digits)."
  (goto-char (point-min))
  (insert "#"
          (format "%02X" (aref colorcomp-data 0))
          (format "%02X" (aref colorcomp-data 1))
          (format "%02X" (aref colorcomp-data 2)))
  (copy-region-as-kill (point-min) (point))
  (kill-buffer nil))

(unless colorcomp-mode-map
  (setq colorcomp-mode-map
        (let ((m (make-sparse-keymap)))
          (suppress-keymap m)
          (define-key m "i" 'colorcomp-R-less)
          (define-key m "o" 'colorcomp-R-more)
          (define-key m "k" 'colorcomp-G-less)
          (define-key m "l" 'colorcomp-G-more)
          (define-key m "," 'colorcomp-B-less)
          (define-key m "." 'colorcomp-B-more)
          (define-key m " " 'colorcomp-copy-as-kill-and-exit)
@end example

Note that we never modify the data in each node, which is fixed when the
ewoc is created to be either @code{nil} or an index into the vector
@code{colorcomp-data}, the actual color components.

@c (end of text)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]