Add forgotten defdescription form.
[clinton/lisp-on-lines.git] / src / defdisplay.lisp
CommitLineData
fdeed55d
DC
1(in-package :lisp-on-lines)
2
2b0fd9c8 3(define-layered-function display-using-description (description object component)
f9b11956 4 (:method-combination wrapping-standard)
2b0fd9c8
DC
5 (:documentation
6 "Render the object in component,
7 using DESCRIPTION, which is an occurence, an attribute, or something else entirely."))
fdeed55d 8
2b0fd9c8
DC
9(define-layered-method
10 display-using-description (d o c)
11 (<:as-html "default :" o))
12
fb04c0a8 13(defun make-display-function (component object
14 &rest properties
15 &key type (line #'line-in)
16 &allow-other-keys)
17 "returns a function that expects a 3 argument function as its argument
18
19The function (which is usually display-using-description) will be called with the proper environment for display all set up nice n pretty like."
20
21 (lambda (function)
22 (let* ((description (find-occurence object)))
23
24 (if description
1cc831d4 25 (dletf (((description-type description) type)
fb04c0a8 26 ((attributes description) (or
27 (attributes description)
1cc831d4 28 (list-attributes description))))
fb04c0a8 29 ;; apply the default line to the description
30 (funcall-with-description
31 description
32 (funcall line object)
33 ;; apply the passed in arguments and call display-using-description
34 #'(lambda ()
35 (funcall-with-description
36 description
37 properties
38 function description object component))))
39 (error "no description for ~A" object)))))
2b0fd9c8
DC
40
41(define-layered-function display (component object &rest args)
42 (:documentation
43 "Displays OBJECT in COMPONENT."))
44
45(define-layered-method display ((component t) (object t)
1cc831d4 46 &rest properties)
0386c736 47 " The default display dispatch method
48
49 DISPLAY takes two required arguments,
50 COMPONENT : The component to display FROM (not neccesarily 'in')
51 OBJECT : The 'thing' we want to display... in this case it's the component
52
53 DISPLAY also takes keywords arguments which modify the DESCRIPTION,
54 that is to say the parameters that come together to create the output.
55
56The default display calls out via FUNCALL-WITH-LAYERS to tche DISPLAY-USING-DESCRIPTION method."
1cc831d4 57 (funcall (apply 'make-display-function component object properties)
58 'display-using-description))
fdeed55d
DC
59
60;;;;; Macros
a4e6154d 61
2b0fd9c8
DC
62
63(defun funcall-with-description (description properties function &rest args)
0386c736 64
2b0fd9c8 65 (if description
1cc831d4 66 (dletf* (((description-type description) (or
2b0fd9c8 67 (getf properties :type)
1cc831d4 68 (description-type description)))
2b0fd9c8 69
1cc831d4 70 ((description-layers description) (append
71 (description-layers description)
2b0fd9c8 72 (getf properties :layers)))
1cc831d4 73 ((description-properties description) (append (description-properties description) properties)))
2b0fd9c8 74 (funcall-with-layers
1cc831d4 75 (description-layers description)
2b0fd9c8 76 #'(lambda ()
a4e6154d
DC
77 (contextl::funcall-with-special-initargs
78 (list (cons description properties))
2b0fd9c8
DC
79 #'(lambda ()
80 (apply function args))))))
81 (apply function args)))
82
2b0fd9c8
DC
83(defmacro with-description ((description &rest properties) &body body)
84 `(funcall-with-description ,description (if ',(cdr properties)
85 (list ,@properties)
86 ,(car properties))
87 #'(lambda ()
88 ,@body)))
89
f9b11956 90(define-layered-function find-do-attributes (desc))
91
92(define-layered-method find-do-attributes ((description description))
93
94 (loop
95 :for att
96 :in (attributes description)
97 :collect (let ((default (find (car (ensure-list att))
98 (default-attributes description)
99 :key #'car)))
100 (or default att))))
101
102(defmacro do-attributes ((var description &optional (attributes `(find-do-attributes ,description))) &body body)
fdeed55d 103 (with-unique-names (att properties type)
2b0fd9c8 104 `(dolist* (,att ,attributes)
f9b11956 105 (let* ((,att (ensure-list ,att))
106 (,properties (rest ,att))
107 (,type (getf ,properties :type))
108 (,var (let ((a (find-attribute ,description (first ,att))))
109 (if ,type
110 (apply #'make-attribute :name (first ,att) :type ,type ,properties)
111 (if a a (make-attribute :name (first ,att) :slot-name (first ,att)))))))
112 (funcall-with-description ,var ,properties
113 #'(lambda ()
114 ,@body))))))
2b0fd9c8
DC
115
116(defmacro with-component ((component) &body body)
117 `(let ((self ,component))
118 (declare (ignorable self))
119 (flet ((display* (thing &rest args)
120 (apply #'display ,component thing args))
1cc831d4 121 (display-attribute (attribute obj &rest
122 props)
2b0fd9c8
DC
123 (if props
124 (funcall-with-description
125 attribute props
126 #'display-using-description attribute obj ,component)
127 (display-using-description attribute obj ,component))))
128 (declare (ignorable #'display* #'display-attribute))
129 ,@body)))
130
131(defmacro defdisplay (&body body)
132 (loop with in-layerp = (eq (car body) :in-layer)
133 with layer = (if in-layerp (cadr body) 't)
134 for tail on (if in-layerp (cddr body) body)
135 until (listp (car tail))
136 collect (car tail) into qualifiers
137 finally
138 (when (member :in-layer qualifiers)
139 (error "Incorrect occurrence of :in-layer in defdisplay. Must occur before qualifiers."))
140 (return
0386c736 141 (destructuring-bind (description &optional object component) (car tail)
2b0fd9c8
DC
142 (with-unique-names (d c)
143 (let (standard-description-p)
144 `(define-layered-method
145 display-using-description
146 :in-layer ,layer
147 ,@qualifiers
0386c736 148
149 ,@(unless object
150 (setf object description)
151 (setf description d)
152 nil)
2b0fd9c8
DC
153 (,(cond
154 ((listp description)
155 (setf d (car description))
156 description)
157 (t
158 (setf d description)
159 (setf standard-description-p t)
160 `(,d description)))
161 ,object
162 ,(cond
163 ((null component)
164 `(,c component))
165 ((listp component)
166 (setf c (car component))
167 component)
168 (t
169 (setf c component)
1cc831d4 170 `(,c t))))
2b0fd9c8
DC
171 (with-component (,c)
172 ,@(cdr tail)))))))))
173
174