diff options
| author | Thien-Thi Nguyen | 2006-05-27 17:58:26 +0000 |
|---|---|---|
| committer | Thien-Thi Nguyen | 2006-05-27 17:58:26 +0000 |
| commit | f3dffabb22006885c815cb496215b642cb8131e0 (patch) | |
| tree | c64b8cc0a6b5d115f57e1d0d271b10ee55dd0e68 | |
| parent | 047ad6f5a2bedb0dab47ee0cbb25b82ef058ed08 (diff) | |
| download | emacs-f3dffabb22006885c815cb496215b642cb8131e0.tar.gz emacs-f3dffabb22006885c815cb496215b642cb8131e0.zip | |
(Display): Add "Abstract Display" to menu.
(Abstract Display, Abstract Display Functions)
(Abstract Display Example): New nodes.
| -rw-r--r-- | lispref/display.texi | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/lispref/display.texi b/lispref/display.texi index a77c895276e..3a8b8c1b7c0 100644 --- a/lispref/display.texi +++ b/lispref/display.texi | |||
| @@ -29,6 +29,7 @@ that Emacs presents to the user. | |||
| 29 | * Display Property:: Enabling special display features. | 29 | * Display Property:: Enabling special display features. |
| 30 | * Images:: Displaying images in Emacs buffers. | 30 | * Images:: Displaying images in Emacs buffers. |
| 31 | * Buttons:: Adding clickable buttons to Emacs buffers. | 31 | * Buttons:: Adding clickable buttons to Emacs buffers. |
| 32 | * Abstract Display:: Emacs' Widget for Object Collections. | ||
| 32 | * Blinking:: How Emacs shows the matching open parenthesis. | 33 | * Blinking:: How Emacs shows the matching open parenthesis. |
| 33 | * Usual Display:: The usual conventions for displaying nonprinting chars. | 34 | * Usual Display:: The usual conventions for displaying nonprinting chars. |
| 34 | * Display Tables:: How to specify other conventions. | 35 | * Display Tables:: How to specify other conventions. |
| @@ -4621,6 +4622,339 @@ buffer. If @var{count-current} is non-@code{nil}, count any button at | |||
| 4621 | @var{pos} in the search, instead of starting at the next button. | 4622 | @var{pos} in the search, instead of starting at the next button. |
| 4622 | @end defun | 4623 | @end defun |
| 4623 | 4624 | ||
| 4625 | @node Abstract Display | ||
| 4626 | @section Abstract Display | ||
| 4627 | @cindex ewoc | ||
| 4628 | @cindex display, abstract | ||
| 4629 | @cindex display, arbitrary objects | ||
| 4630 | @cindex model/view/controller | ||
| 4631 | @cindex view part, model/view/controller | ||
| 4632 | |||
| 4633 | The Ewoc package constructs buffer text that represents a structure | ||
| 4634 | of Lisp objects, and updates the text to follow changes in that | ||
| 4635 | structure. This is like the ``view'' component in the the | ||
| 4636 | ``model/view/controller'' design paradigm. | ||
| 4637 | |||
| 4638 | An @dfn{ewoc} is a structure that organizes information required to | ||
| 4639 | construct buffer text that represents certain Lisp data. The buffer | ||
| 4640 | text of the ewoc has three parts, in order: first, fixed @dfn{header} | ||
| 4641 | text; next, textual descriptions of a series of data elements (Lisp | ||
| 4642 | objects that you specify); and last, fixed @dfn{footer} text. | ||
| 4643 | Specifically, an ewoc contains information on: | ||
| 4644 | |||
| 4645 | @itemize @bullet | ||
| 4646 | @item | ||
| 4647 | The buffer which its text is generated in. | ||
| 4648 | |||
| 4649 | @item | ||
| 4650 | The text's start position in the buffer. | ||
| 4651 | |||
| 4652 | @item | ||
| 4653 | The header and footer strings. | ||
| 4654 | |||
| 4655 | @item | ||
| 4656 | A doubly-linked chain of @dfn{nodes}, each of which contains: | ||
| 4657 | |||
| 4658 | @itemize | ||
| 4659 | @item | ||
| 4660 | A @dfn{data element}, a single Lisp object. | ||
| 4661 | |||
| 4662 | @item | ||
| 4663 | Links to the preceding and following nodes in the chain. | ||
| 4664 | @end itemize | ||
| 4665 | |||
| 4666 | @item | ||
| 4667 | A @dfn{pretty-printer} function which is responsible for | ||
| 4668 | inserting the textual representation of a data | ||
| 4669 | element value into the current buffer. | ||
| 4670 | @end itemize | ||
| 4671 | |||
| 4672 | Typically, you define an ewoc with @code{ewoc-create}, and then pass | ||
| 4673 | the resulting ewoc structure to other functions in the Ewoc package to | ||
| 4674 | build nodes within it, and display it in the buffer. Once it is | ||
| 4675 | displayed in the buffer, other functions determine the correspondance | ||
| 4676 | between buffer positions and nodes, move point from one node's textual | ||
| 4677 | representation to another, and so forth. @xref{Abstract Display | ||
| 4678 | Functions}. | ||
| 4679 | |||
| 4680 | A node @dfn{encapsulates} a data element much the way a variable | ||
| 4681 | holds a value. Normally, encapsulation occurs as a part of adding a | ||
| 4682 | node to the ewoc. You can retrieve the data element value and place a | ||
| 4683 | new value in its place, like so: | ||
| 4684 | |||
| 4685 | @lisp | ||
| 4686 | (ewoc-data @var{node}) | ||
| 4687 | @result{} value | ||
| 4688 | |||
| 4689 | (ewoc-set-data @var{node} @var{new-value}) | ||
| 4690 | @result{} @var{new-value} | ||
| 4691 | @end lisp | ||
| 4692 | |||
| 4693 | @noindent | ||
| 4694 | You can also use, as the data element value, a Lisp object (list or | ||
| 4695 | vector) that is a container for the ``real'' value, or an index into | ||
| 4696 | some other structure. The example (@pxref{Abstract Display Example}) | ||
| 4697 | uses the latter approach. | ||
| 4698 | |||
| 4699 | When the data changes, you will want to update the text in the | ||
| 4700 | buffer. You can update all nodes by calling @code{ewoc-refresh}, or | ||
| 4701 | just specific nodes using @code{ewoc-invalidate}, or all nodes | ||
| 4702 | satisfying a predicate using @code{ewoc-map}. Alternatively, you can | ||
| 4703 | delete invalid nodes using @code{ewoc-delete} or @code{ewoc-filter}, | ||
| 4704 | and add new nodes in their place. Deleting a node from an ewoc deletes | ||
| 4705 | its associated textual description from buffer, as well. | ||
| 4706 | |||
| 4707 | @menu | ||
| 4708 | * Abstract Display Functions:: | ||
| 4709 | * Abstract Display Example:: | ||
| 4710 | @end menu | ||
| 4711 | |||
| 4712 | @node Abstract Display Functions | ||
| 4713 | @subsection Abstract Display Functions | ||
| 4714 | |||
| 4715 | In this subsection, @var{ewoc} and @var{node} stand for the | ||
| 4716 | structures described above (@pxref{Abstract Display}), while | ||
| 4717 | @var{data} stands for an arbitrary Lisp object used as a data element. | ||
| 4718 | |||
| 4719 | @defun ewoc-create pretty-printer &optional header footer nosep | ||
| 4720 | This constructs and returns a new ewoc, with no nodes (and thus no data | ||
| 4721 | elements). @var{pretty-printer} should be a function that takes one | ||
| 4722 | argument, a data element of the sort you plan to use in this ewoc, and | ||
| 4723 | inserts its textual description at point using @code{insert} (and never | ||
| 4724 | @code{insert-before-markers}, because that would interfere with the | ||
| 4725 | Ewoc package's internal mechanisms). | ||
| 4726 | |||
| 4727 | Normally, a newline is automatically inserted after the header, | ||
| 4728 | the footer and every node's textual description. If @var{nosep} | ||
| 4729 | is non-@code{nil}, no newline is inserted. This may be useful for | ||
| 4730 | displaying an entire ewoc on a single line, for example, or for | ||
| 4731 | making nodes ``invisible'' by arranging for @var{pretty-printer} | ||
| 4732 | to do nothing for those nodes. | ||
| 4733 | |||
| 4734 | An ewoc maintains its text in the buffer that is current when | ||
| 4735 | you create it, so switch to the intended buffer before calling | ||
| 4736 | @code{ewoc-create}. | ||
| 4737 | @end defun | ||
| 4738 | |||
| 4739 | @defun ewoc-buffer ewoc | ||
| 4740 | This returns the buffer where @var{ewoc} maintains its text. | ||
| 4741 | @end defun | ||
| 4742 | |||
| 4743 | @defun ewoc-get-hf ewoc | ||
| 4744 | This returns a cons cell @code{(@var{header} . @var{footer})} | ||
| 4745 | made from @var{ewoc}'s header and footer. | ||
| 4746 | @end defun | ||
| 4747 | |||
| 4748 | @defun ewoc-set-hf ewoc header footer | ||
| 4749 | This sets the header and footer of @var{ewoc} to the strings | ||
| 4750 | @var{header} and @var{footer}, respectively. | ||
| 4751 | @end defun | ||
| 4752 | |||
| 4753 | @defun ewoc-enter-first ewoc data | ||
| 4754 | @defunx ewoc-enter-last ewoc data | ||
| 4755 | These add a new node encapsulating @var{data}, putting it, respectively, | ||
| 4756 | at the beginning or end of @var{ewoc}'s chain of nodes. | ||
| 4757 | @end defun | ||
| 4758 | |||
| 4759 | @defun ewoc-enter-before ewoc node data | ||
| 4760 | @defunx ewoc-enter-after ewoc node data | ||
| 4761 | These add a new node encapsulating @var{data}, adding it to | ||
| 4762 | @var{ewoc} before or after @var{node}, respectively. | ||
| 4763 | @end defun | ||
| 4764 | |||
| 4765 | @defun ewoc-prev ewoc node | ||
| 4766 | @defunx ewoc-next ewoc node | ||
| 4767 | These return, respectively, the previous node and the next node of @var{node} | ||
| 4768 | in @var{ewoc}. | ||
| 4769 | @end defun | ||
| 4770 | |||
| 4771 | @defun ewoc-nth ewoc n | ||
| 4772 | This returns the node in @var{ewoc} found at zero-based index @var{n}. | ||
| 4773 | A negative @var{n} means count from the end. @code{ewoc-nth} returns | ||
| 4774 | @code{nil} if @var{n} is out of range. | ||
| 4775 | @end defun | ||
| 4776 | |||
| 4777 | @defun ewoc-data node | ||
| 4778 | This extracts the data encapsulated by @var{node} and returns it. | ||
| 4779 | @end defun | ||
| 4780 | |||
| 4781 | @defun ewoc-set-data node data | ||
| 4782 | This sets the data encapsulated by @var{node} to @var{data}. | ||
| 4783 | @end defun | ||
| 4784 | |||
| 4785 | @defun ewoc-locate ewoc &optional pos guess | ||
| 4786 | This determines the node in @var{ewoc} which contains point (or | ||
| 4787 | @var{pos} if specified), and returns that node. If @var{ewoc} has no | ||
| 4788 | nodes, it returns @code{nil}. If @var{pos} is before the first node, | ||
| 4789 | it returns the first node; if @var{pos} is after the last node, it returns | ||
| 4790 | the last node. The optional third arg @var{guess} | ||
| 4791 | should be a node that is likely to be near @var{pos}; this doesn't | ||
| 4792 | alter the result, but makes the function run faster. | ||
| 4793 | @end defun | ||
| 4794 | |||
| 4795 | @defun ewoc-location node | ||
| 4796 | This returns the start position of @var{node}. | ||
| 4797 | @end defun | ||
| 4798 | |||
| 4799 | @defun ewoc-goto-prev ewoc arg | ||
| 4800 | @defunx ewoc-goto-next ewoc arg | ||
| 4801 | These move point to the previous or next, respectively, @var{arg}th node | ||
| 4802 | in @var{ewoc}. @code{ewoc-goto-prev} does not move if it is already at | ||
| 4803 | the first node or if @var{ewoc} is empty, whereas @code{ewoc-goto-next} | ||
| 4804 | moves past the last node, returning @code{nil}. Excepting this special | ||
| 4805 | case, these functions return the node moved to. | ||
| 4806 | @end defun | ||
| 4807 | |||
| 4808 | @defun ewoc-goto-node ewoc node | ||
| 4809 | This moves point to the start of @var{node} in @var{ewoc}. | ||
| 4810 | @end defun | ||
| 4811 | |||
| 4812 | @defun ewoc-refresh ewoc | ||
| 4813 | This function regenerates the text of @var{ewoc}. It works by | ||
| 4814 | deleting the text between the header and the footer, i.e., all the | ||
| 4815 | data elements' representations, and then calling the pretty-printer | ||
| 4816 | function for each node, one by one, in order. | ||
| 4817 | @end defun | ||
| 4818 | |||
| 4819 | @defun ewoc-invalidate ewoc &rest nodes | ||
| 4820 | This is similar to @code{ewoc-refresh}, except that only @var{nodes} in | ||
| 4821 | @var{ewoc} are updated instead of the entire set. | ||
| 4822 | @end defun | ||
| 4823 | |||
| 4824 | @defun ewoc-delete ewoc &rest nodes | ||
| 4825 | This deletes each node in @var{nodes} from @var{ewoc}. | ||
| 4826 | @end defun | ||
| 4827 | |||
| 4828 | @defun ewoc-filter ewoc predicate &rest args | ||
| 4829 | This calls @var{predicate} for each data element in @var{ewoc} and | ||
| 4830 | deletes those nodes for which @var{predicate} returns @code{nil}. | ||
| 4831 | Any @var{args} are passed to @var{predicate}. | ||
| 4832 | @end defun | ||
| 4833 | |||
| 4834 | @defun ewoc-collect ewoc predicate &rest args | ||
| 4835 | This calls @var{predicate} for each data element in @var{ewoc} | ||
| 4836 | and returns a list of those elements for which @var{predicate} | ||
| 4837 | returns non-@code{nil}. The elements in the list are ordered | ||
| 4838 | as in the buffer. Any @var{args} are passed to @var{predicate}. | ||
| 4839 | @end defun | ||
| 4840 | |||
| 4841 | @defun ewoc-map map-function ewoc &rest args | ||
| 4842 | This calls @var{map-function} for each data element in @var{ewoc} and | ||
| 4843 | updates those nodes for which @var{map-function} returns non-@code{nil}. | ||
| 4844 | Any @var{args} are passed to @var{map-function}. | ||
| 4845 | @end defun | ||
| 4846 | |||
| 4847 | @node Abstract Display Example | ||
| 4848 | @subsection Abstract Display Example | ||
| 4849 | |||
| 4850 | Here is a simple example using functions of the ewoc package to | ||
| 4851 | implement a ``color components display'', an area in a buffer that | ||
| 4852 | represents a vector of three integers (itself representing a 24-bit RGB | ||
| 4853 | value) in various ways. | ||
| 4854 | |||
| 4855 | @example | ||
| 4856 | (setq colorcomp-ewoc nil | ||
| 4857 | colorcomp-data nil | ||
| 4858 | colorcomp-mode-map nil | ||
| 4859 | colorcomp-labels ["Red" "Green" "Blue"]) | ||
| 4860 | |||
| 4861 | (defun colorcomp-pp (data) | ||
| 4862 | (if data | ||
| 4863 | (let ((comp (aref colorcomp-data data))) | ||
| 4864 | (insert (aref colorcomp-labels data) "\t: #x" | ||
| 4865 | (format "%02X" comp) " " | ||
| 4866 | (make-string (ash comp -2) ?#) "\n")) | ||
| 4867 | (let ((cstr (format "#%02X%02X%02X" | ||
| 4868 | (aref colorcomp-data 0) | ||
| 4869 | (aref colorcomp-data 1) | ||
| 4870 | (aref colorcomp-data 2))) | ||
| 4871 | (samp " (sample text) ")) | ||
| 4872 | (insert "Color\t: " | ||
| 4873 | (propertize samp 'face `(foreground-color . ,cstr)) | ||
| 4874 | (propertize samp 'face `(background-color . ,cstr)) | ||
| 4875 | "\n")))) | ||
| 4876 | |||
| 4877 | (defun colorcomp (color) | ||
| 4878 | "Allow fiddling with COLOR in a new buffer. | ||
| 4879 | The buffer is in Color Components mode." | ||
| 4880 | (interactive "sColor (name or #RGB or #RRGGBB): ") | ||
| 4881 | (when (string= "" color) | ||
| 4882 | (setq color "green")) | ||
| 4883 | (unless (color-values color) | ||
| 4884 | (error "No such color: %S" color)) | ||
| 4885 | (switch-to-buffer | ||
| 4886 | (generate-new-buffer (format "originally: %s" color))) | ||
| 4887 | (kill-all-local-variables) | ||
| 4888 | (setq major-mode 'colorcomp-mode | ||
| 4889 | mode-name "Color Components") | ||
| 4890 | (use-local-map colorcomp-mode-map) | ||
| 4891 | (erase-buffer) | ||
| 4892 | (buffer-disable-undo) | ||
| 4893 | (let ((data (apply 'vector (mapcar (lambda (n) (ash n -8)) | ||
| 4894 | (color-values color)))) | ||
| 4895 | (ewoc (ewoc-create 'colorcomp-pp | ||
| 4896 | "\nColor Components\n\n" | ||
| 4897 | (substitute-command-keys | ||
| 4898 | "\n\\@{colorcomp-mode-map@}")))) | ||
| 4899 | (set (make-local-variable 'colorcomp-data) data) | ||
| 4900 | (set (make-local-variable 'colorcomp-ewoc) ewoc) | ||
| 4901 | (ewoc-enter-last ewoc 0) | ||
| 4902 | (ewoc-enter-last ewoc 1) | ||
| 4903 | (ewoc-enter-last ewoc 2) | ||
| 4904 | (ewoc-enter-last ewoc nil))) | ||
| 4905 | @end example | ||
| 4906 | |||
| 4907 | @cindex controller part, model/view/controller | ||
| 4908 | This example can be extended to be a ``color selection widget'' (in | ||
| 4909 | other words, the controller part of the ``model/view/controller'' | ||
| 4910 | design paradigm) by defining commands to modify @code{colorcomp-data} | ||
| 4911 | and to ``finish'' the selection process, and a keymap to tie it all | ||
| 4912 | together conveniently. | ||
| 4913 | |||
| 4914 | @example | ||
| 4915 | (defun colorcomp-mod (index limit delta) | ||
| 4916 | (let ((cur (aref colorcomp-data index))) | ||
| 4917 | (unless (= limit cur) | ||
| 4918 | (aset colorcomp-data index (+ cur delta))) | ||
| 4919 | (ewoc-invalidate | ||
| 4920 | colorcomp-ewoc | ||
| 4921 | (ewoc-nth colorcomp-ewoc index) | ||
| 4922 | (ewoc-nth colorcomp-ewoc -1)))) | ||
| 4923 | |||
| 4924 | (defun colorcomp-R-more () (interactive) (colorcomp-mod 0 255 1)) | ||
| 4925 | (defun colorcomp-G-more () (interactive) (colorcomp-mod 1 255 1)) | ||
| 4926 | (defun colorcomp-B-more () (interactive) (colorcomp-mod 2 255 1)) | ||
| 4927 | (defun colorcomp-R-less () (interactive) (colorcomp-mod 0 0 -1)) | ||
| 4928 | (defun colorcomp-G-less () (interactive) (colorcomp-mod 1 0 -1)) | ||
| 4929 | (defun colorcomp-B-less () (interactive) (colorcomp-mod 2 0 -1)) | ||
| 4930 | |||
| 4931 | (defun colorcomp-copy-as-kill-and-exit () | ||
| 4932 | "Copy the color components into the kill ring and kill the buffer. | ||
| 4933 | The string is formatted #RRGGBB (hash followed by six hex digits)." | ||
| 4934 | (interactive) | ||
| 4935 | (kill-new (format "#%02X%02X%02X" | ||
| 4936 | (aref colorcomp-data 0) | ||
| 4937 | (aref colorcomp-data 1) | ||
| 4938 | (aref colorcomp-data 2))) | ||
| 4939 | (kill-buffer nil)) | ||
| 4940 | |||
| 4941 | (setq colorcomp-mode-map | ||
| 4942 | (let ((m (make-sparse-keymap))) | ||
| 4943 | (suppress-keymap m) | ||
| 4944 | (define-key m "i" 'colorcomp-R-less) | ||
| 4945 | (define-key m "o" 'colorcomp-R-more) | ||
| 4946 | (define-key m "k" 'colorcomp-G-less) | ||
| 4947 | (define-key m "l" 'colorcomp-G-more) | ||
| 4948 | (define-key m "," 'colorcomp-B-less) | ||
| 4949 | (define-key m "." 'colorcomp-B-more) | ||
| 4950 | (define-key m " " 'colorcomp-copy-as-kill-and-exit) | ||
| 4951 | m)) | ||
| 4952 | @end example | ||
| 4953 | |||
| 4954 | Note that we never modify the data in each node, which is fixed when the | ||
| 4955 | ewoc is created to be either @code{nil} or an index into the vector | ||
| 4956 | @code{colorcomp-data}, the actual color components. | ||
| 4957 | |||
| 4624 | @node Blinking | 4958 | @node Blinking |
| 4625 | @section Blinking Parentheses | 4959 | @section Blinking Parentheses |
| 4626 | @cindex parenthesis matching | 4960 | @cindex parenthesis matching |