Подстветка кода с помощью colorize
Для подсветки кода на Common Lisp я люблю использовать colorize, потому что она добавляет в разметку ссылки на Hyperspec. А вот структура разметки получается та ещё, я хочу другую, более современную. Но исходники colorize ужасны и копаться в них я не хочу. Поэтому я написал функцию, которую берёт оригинальную разметку, генерируемую colorize и превращает её в нечто более интересное (для меня):
- (defparameter *span-classes*
- '("symbol" "special" "keyword" "comment" "string" "character"))
- (defun update-code-markup (markup)
- (labels
- ((bad-span-p (node)
- (and (string-equal (xtree:local-name node) "span")
- (not (member (xtree:attribute-value node "class") *span-classes*
- :test #'string-equal))))
- ;;---------------------------------------
- (comment-p (node)
- (and (string-equal (xtree:local-name node) "span")
- (string-equal (xtree:attribute-value node "class") "comment")))
- ;;---------------------------------------
- (br-p (node)
- (string-equal (xtree:local-name node) "br"))
- ;;---------------------------------------
- (flatten-spans (node)
- (iter (for el in (xtree:all-childs node))
- (flatten-spans el))
- ;;---------------------------------------
- (when (comment-p node)
- (setf (xtree:text-content node)
- (xtree:text-content node))
- (xtree:insert-child-after (xtree:make-element "br") node))
- ;;---------------------------------------
- (when (bad-span-p node)
- (iter (for el in (xtree:all-childs node))
- (xtree:insert-child-before (xtree:detach el) node))
- (xtree:remove-child node))))
- ;;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- (html:with-parse-html (doc (format nil "<div>~A</div>" markup))
- (let ((div (xtree:first-child (xtree:first-child (xtree:root doc)))))
- (flatten-spans div)
- (xtree:with-object (fragment (xtree:make-document-fragment doc))
- ;;---------------------------------------
- (let* ((pre (xtree:make-child-element fragment "div"))
- (ol (xtree:make-child-element pre "ol")))
- (setf (xtree:attribute-value pre "class")
- "prettyprint linenums")
- (setf (xtree:attribute-value ol "class")
- "linenums")
- ;;---------------------------------------
- (iter (for line in (split-sequence:split-sequence-if #'br-p (xtree:all-childs div)))
- (for i from 0)
- (let ((li (xtree:make-child-element ol "li")))
- (setf (xtree:attribute-value li "class")
- (format nil "L~s" i))
- ;;---------------------------------------
- (iter (for el in line)
- (xtree:append-child li (xtree:detach el))))))
- ;;---------------------------------------
- (html:serialize-html fragment :to-string))))))
Здесь можно видеть не только код, но и непосредственный результат.
Кстати, функция довольно большая. Читать "сплошное месиво кода" на CL бывает не очень приятно. В других языках код обычно "разряжают" с помощью пустых строк. Но в CL это эстетически смотрится как-то не очень. Так что я решил попробовать использовать линии в качестве разделителей. Пока мне кажется, что получается неплохо.