Massive patch to compile with modern versions of the libraries. This is only 1/2...
[clinton/lisp-on-lines.git] / src / defdisplay.lisp
... / ...
CommitLineData
1(in-package :lisp-on-lines)
2
3(define-layered-function display-using-description (description object component)
4 (:method-combination wrapping-standard)
5 (:documentation
6 "Render the object in component,
7 using DESCRIPTION, which is an occurence, an attribute, or something else entirely."))
8
9(define-layered-method
10 display-using-description (d o c)
11 (<:as-html "default :" o))
12
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
25 (dletf (((description-type description) type)
26 ((attributes description) (or
27 (attributes description)
28 (list-attributes description))))
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)))))
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)
46 &rest properties)
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."
57 (funcall (apply 'make-display-function component object properties)
58 'display-using-description))
59
60;;;;; Macros
61
62
63(defun funcall-with-description (description properties function &rest args)
64
65 (if description
66 (dletf* (((description-type description) (or
67 (getf properties :type)
68 (description-type description)))
69
70 ((description-layers description) (append
71 (description-layers description)
72 (getf properties :layers)))
73 ((description-properties description) (append (description-properties description) properties)))
74 (funcall-with-layers
75 (description-layers description)
76 #'(lambda ()
77 (contextl::funcall-with-special-initargs
78 (list (cons description properties))
79 #'(lambda ()
80 (apply function args))))))
81 (apply function args)))
82
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
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)
103 (with-unique-names (att properties type)
104 `(dolist* (,att ,attributes)
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))))))
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))
121 (display-attribute (attribute obj &rest
122 props)
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
141 (destructuring-bind (description &optional object component) (car tail)
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
148
149 ,@(unless object
150 (setf object description)
151 (setf description d)
152 nil)
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)
170 `(,c t))))
171 (with-component (,c)
172 ,@(cdr tail)))))))))
173
174