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