J. K. Cunningham
2010-03-28 20:10:53 UTC
I've been playing around with a way to partially automate writing
outline-based pages and run into something I don't know how to do. I'm
hoping someone can perhaps offer a solution or point me in the right
direction. I've reduced the scope to a fairly simple situation which
might seem unmotivated in this form. But if I can find a way to do this,
the rest of what I'm doing will fall into place.
I'd like to be able to write code that looks like this (example):
(let ((hform "A Title"))
(with-html-output (*standard-output* nil :indent 0)
(section (hform)
(:p "A paragraph can go here. ")
(section ("A Subtitle")
"Subsection text goes here."))
(section ("Second Title")
"Any cl-who syntax input here:"
(:ol (:li "Item 1")
(:li "Item 2")))))
where SECTION would be a macro so that it can take CL-WHO syntax
arguments. The idea is that the SECTION macro would expand so that I
ended up effectively with this:
(let ((form "A Title"))
(with-html-output (*standard-output* nil :indent 0)
(:h1 (str form))
(:p "A paragraph can go here. ")
(:h2 "A Subtitle")
"Subsection text goes here."
(:h1 "Second Title")
"Any cl-who syntax input here:"
(:ol (:li "Item 1")
(:li "Item 2"))))
I came up with a helper macro like this to handle the levels as a
variable:
(defmacro hn (level &body body)
``(,(intern (format nil "H~d" ,level) :keyword)
,,@body))
(let ((lvl 2)
(title "A Title"))
(with-html-output (*standard-output*)
(str (hn lvl (:b (str title))))))
;; => <h2><b>A Title</b></h2>
This enables me to write code that looks like this:
(defmacro section ((n &rest heading) &body body)
`(str (with-html-output-to-string (s nil :indent 0)
(str (hn ,n ,@heading))
(str (with-html ,@body)))))
(let ((lvl 1)
(form "A Title"))
(with-html-output (*standard-output* nil :indent 0)
(section (lvl form)
(:p "A paragraph can go here. ")
(section ((1+ lvl) "A Subtitle")
"Subsection text goes here."))
(section (lvl "Second Title")
"Any cl-who syntax input here:"
(:ol (:li "Item 1")
(:li "Item 2")))))
But this leaves me with having to manage the levels manually. What I
can't figure out how to do is write the SECTION macro so it doesn't
require the LVL arguments, incrementing them recursively.
If it could be written as a function, I could use a closure that started
at LVL = 1 and incremented at each level, but I'm not good enough with
macros to see how to do this.
I'm probably looking at this the wrong way. Does anyone have any ideas how to go about this?
Regards,
Jeff Cunningham
outline-based pages and run into something I don't know how to do. I'm
hoping someone can perhaps offer a solution or point me in the right
direction. I've reduced the scope to a fairly simple situation which
might seem unmotivated in this form. But if I can find a way to do this,
the rest of what I'm doing will fall into place.
I'd like to be able to write code that looks like this (example):
(let ((hform "A Title"))
(with-html-output (*standard-output* nil :indent 0)
(section (hform)
(:p "A paragraph can go here. ")
(section ("A Subtitle")
"Subsection text goes here."))
(section ("Second Title")
"Any cl-who syntax input here:"
(:ol (:li "Item 1")
(:li "Item 2")))))
where SECTION would be a macro so that it can take CL-WHO syntax
arguments. The idea is that the SECTION macro would expand so that I
ended up effectively with this:
(let ((form "A Title"))
(with-html-output (*standard-output* nil :indent 0)
(:h1 (str form))
(:p "A paragraph can go here. ")
(:h2 "A Subtitle")
"Subsection text goes here."
(:h1 "Second Title")
"Any cl-who syntax input here:"
(:ol (:li "Item 1")
(:li "Item 2"))))
I came up with a helper macro like this to handle the levels as a
variable:
(defmacro hn (level &body body)
``(,(intern (format nil "H~d" ,level) :keyword)
,,@body))
(let ((lvl 2)
(title "A Title"))
(with-html-output (*standard-output*)
(str (hn lvl (:b (str title))))))
;; => <h2><b>A Title</b></h2>
This enables me to write code that looks like this:
(defmacro section ((n &rest heading) &body body)
`(str (with-html-output-to-string (s nil :indent 0)
(str (hn ,n ,@heading))
(str (with-html ,@body)))))
(let ((lvl 1)
(form "A Title"))
(with-html-output (*standard-output* nil :indent 0)
(section (lvl form)
(:p "A paragraph can go here. ")
(section ((1+ lvl) "A Subtitle")
"Subsection text goes here."))
(section (lvl "Second Title")
"Any cl-who syntax input here:"
(:ol (:li "Item 1")
(:li "Item 2")))))
But this leaves me with having to manage the levels manually. What I
can't figure out how to do is write the SECTION macro so it doesn't
require the LVL arguments, incrementing them recursively.
If it could be written as a function, I could use a closure that started
at LVL = 1 and incremented at each level, but I'm not good enough with
macros to see how to do this.
I'm probably looking at this the wrong way. Does anyone have any ideas how to go about this?
Regards,
Jeff Cunningham