diff --git a/packages.lisp b/packages.lisp index e5656d7..bde2826 100644 --- a/packages.lisp +++ b/packages.lisp @@ -42,6 +42,7 @@ :*html-no-indent-tags* :*html-empty-tags* :*html-empty-tag-aware-p* + :*short-leaf-content-length* :conc :convert-attributes :convert-tag-to-string-list diff --git a/specials.lisp b/specials.lisp index c55c3e0..3a35625 100644 --- a/specials.lisp +++ b/specials.lisp @@ -120,6 +120,9 @@ in *HTML-EMPTY-TAGS* as \(XHTML mode) or \(SGML mode and HTML5 mode). For all other tags, it will always generate .") +(defvar *short-leaf-content-length* 72 + "Below this threshold leaf tags won't be indented.") + (defconstant +newline+ (make-string 1 :initial-element #\Newline) "Used for indentation.") diff --git a/who.lisp b/who.lisp index 6315612..a0e780c 100644 --- a/who.lisp +++ b/who.lisp @@ -59,30 +59,34 @@ XHTML and :HTML5 for HTML5 (HTML syntax)." "Returns a string list corresponding to the `HTML' \(in CL-WHO syntax) in SEXP. Uses the generic function CONVERT-TO-STRING-LIST internally. Utility function used by TREE-TO-TEMPLATE." - (let (tag attr-list body) - (cond - ((keywordp sexp) - (setq tag sexp)) - ((atom (first sexp)) - (setq tag (first sexp)) - ;; collect attribute/value pairs into ATTR-LIST and tag body (if - ;; any) into BODY - (loop for rest on (cdr sexp) by #'cddr - if (keywordp (first rest)) - collect (cons (first rest) (second rest)) into attr - else - do (progn (setq attr-list attr) - (setq body rest) - (return)) - finally (setq attr-list attr))) - ((listp (first sexp)) - (setq tag (first (first sexp))) - (loop for rest on (cdr (first sexp)) by #'cddr - if (keywordp (first rest)) - collect (cons (first rest) (second rest)) into attr - finally (setq attr-list attr)) - (setq body (cdr sexp)))) - (convert-tag-to-string-list tag attr-list body body-fn))) + (flet ((short-leaf-p (s) + (and (loop for e in (rest s) never (and (listp e) (keywordp (first e)))) + (< (loop for e in (rest s) when (stringp e) sum (length e)) + *short-leaf-content-length*)))) + (let (tag attr-list body) + (cond + ((keywordp sexp) + (setq tag sexp)) + ((atom (first sexp)) + (setq tag (first sexp)) + ;; collect attribute/value pairs into ATTR-LIST and tag body (if + ;; any) into BODY + (loop for rest on (cdr sexp) by #'cddr + if (keywordp (first rest)) + collect (cons (first rest) (second rest)) into attr + else + do (progn (setq attr-list attr) + (setq body rest) + (return)) + finally (setq attr-list attr))) + ((listp (first sexp)) + (setq tag (first (first sexp))) + (loop for rest on (cdr (first sexp)) by #'cddr + if (keywordp (first rest)) + collect (cons (first rest) (second rest)) into attr + finally (setq attr-list attr)) + (setq body (cdr sexp)))) + (convert-tag-to-string-list tag attr-list body body-fn (short-leaf-p sexp))))) (defun convert-attributes (attr-list) "Helper function for CONVERT-TAG-TO-STRING-LIST which converts the @@ -132,15 +136,17 @@ forms." ,=var= *attribute-quote-char*))))))) -(defgeneric convert-tag-to-string-list (tag attr-list body body-fn) +(defgeneric convert-tag-to-string-list (tag attr-list body body-fn leaf-p) (:documentation "Used by PROCESS-TAG to convert `HTML' into a list of strings. TAG is a keyword symbol naming the outer tag, ATTR-LIST is an alist of its attributes \(the car is the attribute's name as a keyword, the cdr is its value), BODY is the tag's body, and BODY-FN is a function which should be applied to BODY. The function must return -a list of strings or Lisp forms.")) +a list of strings or Lisp forms. SHORT-LEAF-P is t when the TAG is a +leaf and its content is shorter than *SHORT-LEAF-CONTENT-LENGTH* then +it is not indented.")) -(defmethod convert-tag-to-string-list (tag attr-list body body-fn) +(defmethod convert-tag-to-string-list (tag attr-list body body-fn short-leaf-p) "The standard method which is not specialized. The idea is that you can use EQL specializers on the first argument." (declare (optimize speed space)) @@ -164,7 +170,7 @@ can use EQL specializers on the first argument." ;; now hand over the tag's body to TREE-TO-TEMPLATE (let ((*indent* body-indent)) (funcall body-fn body)) - (when body-indent + (when (and body-indent (not short-leaf-p)) ;; indentation (list +newline+ (n-spaces *indent*))) ;; closing tag