1 ;;; This is code was taken from lisppaste2 and is a quick hack
2 ;;; to colorize lisp examples in the html generated by Texinfo.
3 ;;; It is not general-purpose utility, though it could easily be
6 ;;;; colorize-package.lisp
10 (:export
:scan-string
:format-scan
:html-colorization
11 :find-coloring-type
:autodetect-coloring-type
12 :coloring-types
:scan
:scan-any
:advance
:call-parent-formatter
13 :*coloring-css
* :make-background-css
:*css-background-class
*
14 :colorize-file
:colorize-file-to-stream
:*version-token
*))
16 ;;;; coloring-css.lisp
18 (in-package :colorize
)
20 (defparameter *coloring-css
*
21 ".symbol { color: #770055; background-color: transparent; border: 0px; margin: 0px;}
22 a.symbol:link { color: #229955; background-color : transparent; text-decoration: none; border: 0px; margin: 0px; }
23 a.symbol:active { color : #229955; background-color : transparent; text-decoration: none; border: 0px; margin: 0px; }
24 a.symbol:visited { color : #229955; background-color : transparent; text-decoration: none; border: 0px; margin: 0px; }
25 a.symbol:hover { color : #229955; background-color : transparent; text-decoration: none; border: 0px; margin: 0px; }
26 .special { color : #FF5000; background-color : inherit; }
27 .keyword { color : #770000; background-color : inherit; }
28 .comment { color : #007777; background-color : inherit; }
29 .string { color : #777777; background-color : inherit; }
30 .character { color : #0055AA; background-color : inherit; }
31 .syntaxerror { color : #FF0000; background-color : inherit; }
32 span.paren1:hover { color : inherit; background-color : #BAFFFF; }
33 span.paren2:hover { color : inherit; background-color : #FFCACA; }
34 span.paren3:hover { color : inherit; background-color : #FFFFBA; }
35 span.paren4:hover { color : inherit; background-color : #CACAFF; }
36 span.paren5:hover { color : inherit; background-color : #CAFFCA; }
37 span.paren6:hover { color : inherit; background-color : #FFBAFF; }
40 (defvar *css-background-class
* "lisp-bg")
42 (defun for-css (thing)
43 (if (symbolp thing
) (string-downcase (symbol-name thing
))
46 (defun make-background-css (color &key
(class *css-background-class
*) (extra nil
))
47 (format nil
".~A { background-color: ~A; color: black; ~{~A; ~}}~:*~:*~:*
48 .~A:hover { background-color: ~A; color: black; ~{~A; ~}}~%"
50 (mapcar #'(lambda (extra)
51 (format nil
"~A : ~{~A ~}"
52 (for-css (first extra
))
53 (mapcar #'for-css
(cdr extra
))))
58 ;(in-package :colorize)
60 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
61 (defparameter *coloring-types
* nil
)
62 (defparameter *version-token
* (gensym)))
64 (defclass coloring-type
()
65 ((modes :initarg
:modes
:accessor coloring-type-modes
)
66 (default-mode :initarg
:default-mode
:accessor coloring-type-default-mode
)
67 (transition-functions :initarg
:transition-functions
:accessor coloring-type-transition-functions
)
68 (fancy-name :initarg
:fancy-name
:accessor coloring-type-fancy-name
)
69 (term-formatter :initarg
:term-formatter
:accessor coloring-type-term-formatter
)
70 (formatter-initial-values :initarg
:formatter-initial-values
:accessor coloring-type-formatter-initial-values
:initform nil
)
71 (formatter-after-hook :initarg
:formatter-after-hook
:accessor coloring-type-formatter-after-hook
:initform
(constantly ""))
72 (autodetect-function :initarg
:autodetect-function
:accessor coloring-type-autodetect-function
73 :initform
(constantly nil
))
74 (parent-type :initarg
:parent-type
:accessor coloring-type-parent-type
76 (visible :initarg
:visible
:accessor coloring-type-visible
79 (defun find-coloring-type (type)
80 (if (typep type
'coloring-type
)
82 (cdr (assoc (symbol-name type
) *coloring-types
* :test
#'string-equal
:key
#'symbol-name
))))
84 (defun autodetect-coloring-type (name)
86 (find name
*coloring-types
*
88 :test
#'(lambda (name type
)
89 (and (coloring-type-visible type
)
90 (funcall (coloring-type-autodetect-function type
) name
))))))
92 (defun coloring-types ()
93 (loop for type-pair in
*coloring-types
*
94 if
(coloring-type-visible (cdr type-pair
))
95 collect
(cons (car type-pair
)
96 (coloring-type-fancy-name (cdr type-pair
)))))
98 (defun (setf find-coloring-type
) (new-value type
)
100 (let ((found (assoc type
*coloring-types
*)))
102 (setf (cdr found
) new-value
)
103 (setf *coloring-types
*
104 (nconc *coloring-types
*
105 (list (cons type new-value
))))))
106 (setf *coloring-types
* (remove type
*coloring-types
* :key
#'car
))))
108 (defvar *scan-calls
* 0)
110 (defvar *reset-position
* nil
)
112 (defmacro with-gensyms
((&rest names
) &body body
)
113 `(let ,(mapcar #'(lambda (name)
114 (list name
`(make-symbol ,(symbol-name name
)))) names
)
117 (defmacro with-scanning-functions
(string-param position-place mode-place mode-wait-place
&body body
)
118 (with-gensyms (num items position not-preceded-by string item new-mode until advancing
)
119 `(labels ((advance (,num
)
120 (setf ,position-place
(+ ,position-place
,num
))
122 (peek-any (,items
&key
,not-preceded-by
)
124 (let* ((,items
(if (stringp ,items
)
125 (coerce ,items
'list
) ,items
))
126 (,not-preceded-by
(if (characterp ,not-preceded-by
)
127 (string ,not-preceded-by
) ,not-preceded-by
))
128 (,position
,position-place
)
129 (,string
,string-param
))
131 (< ,position
(length ,string
))
133 :test
#'(lambda (,string
,item
)
135 (format t
"looking for ~S in ~S starting at ~S~%"
136 ,item
,string
,position
)
137 (if (characterp ,item
)
138 (char= (elt ,string
,position
)
140 (search ,item
,string
:start2
,position
141 :end2
(min (length ,string
)
142 (+ ,position
(length ,item
))))))))))
143 (if (characterp ,item
)
144 (setf ,item
(string ,item
)))
148 (if (>= (- ,position
(length ,not-preceded-by
)) 0)
149 (not (string= (subseq ,string
150 (- ,position
(length ,not-preceded-by
))
158 (and *reset-position
*
159 (setf ,position-place
*reset-position
*))
161 (scan-any (,items
&key
,not-preceded-by
)
162 (let ((,item
(peek-any ,items
:not-preceded-by
,not-preceded-by
)))
163 (and ,item
(advance (length ,item
)))))
164 (peek (,item
&key
,not-preceded-by
)
165 (peek-any (list ,item
) :not-preceded-by
,not-preceded-by
))
166 (scan (,item
&key
,not-preceded-by
)
167 (scan-any (list ,item
) :not-preceded-by
,not-preceded-by
)))
168 (macrolet ((set-mode (,new-mode
&key
,until
(,advancing t
))
170 (list 'setf
',mode-place
,new-mode
)
171 (list 'setf
',mode-wait-place
172 (list 'lambda
(list ',position
)
173 (list 'let
(list (list '*reset-position
* ',position
))
174 (list 'values
,until
,advancing
)))))))
177 (defvar *formatter-local-variables
*)
179 (defmacro define-coloring-type
(name fancy-name
&key modes default-mode transitions formatters
180 autodetect parent formatter-variables
(formatter-after-hook '(constantly ""))
182 (with-gensyms (parent-type term type string current-mode position position-foobage mode-wait new-position advance
)
183 `(let ((,parent-type
(or (find-coloring-type ,parent
)
185 (error "No such coloring type: ~S" ,parent
)))))
186 (setf (find-coloring-type ,name
)
187 (make-instance 'coloring-type
188 :fancy-name
',fancy-name
189 :modes
(append ',modes
(if ,parent-type
(coloring-type-modes ,parent-type
)))
190 :default-mode
(or ',default-mode
191 (if ,parent-type
(coloring-type-default-mode ,parent-type
)))
193 `(:autodetect-function
,autodetect
))
194 :parent-type
,parent-type
195 :visible
(not ,invisible
)
196 :formatter-initial-values
(lambda nil
197 (list* ,@(mapcar #'(lambda (e)
198 `(cons ',(car e
) ,(second e
)))
201 (funcall (coloring-type-formatter-initial-values ,parent-type
))
203 :formatter-after-hook
(lambda nil
204 (symbol-macrolet ,(mapcar #'(lambda (e)
205 `(,(car e
) (cdr (assoc ',(car e
) *formatter-local-variables
*))))
208 (funcall ,formatter-after-hook
)
210 (funcall (coloring-type-formatter-after-hook ,parent-type
))
213 (symbol-macrolet ,(mapcar #'(lambda (e)
214 `(,(car e
) (cdr (assoc ',(car e
) *formatter-local-variables
*))))
217 (labels ((call-parent-formatter (&optional
(,type
(car ,term
))
218 (,string
(cdr ,term
)))
220 (funcall (coloring-type-term-formatter ,parent-type
)
221 (cons ,type
,string
))))
222 (call-formatter (&optional
(,type
(car ,term
))
223 (,string
(cdr ,term
)))
227 (t (lambda (,type text
)
228 (call-parent-formatter ,type text
))))
231 :transition-functions
233 ,@(loop for transition in transitions
234 collect
(destructuring-bind (mode &rest table
) transition
236 (lambda (,current-mode
,string
,position
)
237 (let ((,mode-wait
(constantly nil
))
238 (,position-foobage
,position
))
239 (with-scanning-functions ,string
,position-foobage
240 ,current-mode
,mode-wait
241 (let ((*reset-position
* ,position
))
243 (values ,position-foobage
,current-mode
244 (lambda (,new-position
)
245 (setf ,position-foobage
,new-position
)
246 (let ((,advance
(nth-value 1 (funcall ,mode-wait
,position-foobage
))))
247 (values ,position-foobage
,advance
)))))
250 (defun full-transition-table (coloring-type-object)
251 (let ((parent (coloring-type-parent-type coloring-type-object
)))
253 (append (coloring-type-transition-functions coloring-type-object
)
254 (full-transition-table parent
))
255 (coloring-type-transition-functions coloring-type-object
))))
257 (defun scan-string (coloring-type string
)
258 (let* ((coloring-type-object (or (find-coloring-type coloring-type
)
259 (error "No such coloring type: ~S" coloring-type
)))
260 (transitions (full-transition-table coloring-type-object
))
263 (current-mode (coloring-type-default-mode coloring-type-object
))
265 (current-wait (constantly nil
))
269 (flet ((finish-current (new-position new-mode new-wait
&key
(extend t
) push pop
)
270 (let ((to (if extend new-position current-position
)))
272 (setf result
(nconc result
273 (list (cons (cons current-mode mode-stack
)
274 (subseq string low-bound
281 (push current-mode mode-stack
)
282 (push current-wait wait-stack
))
283 (setf current-mode new-mode
284 current-position new-position
285 current-wait new-wait
))))
287 (if (> current-position
(length string
))
288 (return-from scan-string
290 (format *trace-output
* "Scan was called ~S times.~%"
292 (finish-current (length string
) nil
(constantly nil
))
295 (loop for transition in
297 (remove current-mode transitions
299 :test-not
#'(lambda (a b
)
306 (new-position new-mode new-wait
)
307 (funcall transition current-mode string current-position
)
308 (when (> new-position current-position
)
309 (finish-current new-position new-mode new-wait
:extend nil
:push t
)
314 (funcall current-wait current-position
)
316 (format t
"current-wait returns ~S ~S (mode is ~S, pos is ~S)~%" pos advance current-mode current-position
)
318 (when (> pos current-position
)
319 (finish-current (if advance
328 (incf current-position
)))
331 (defun format-scan (coloring-type scan
)
332 (let* ((coloring-type-object (or (find-coloring-type coloring-type
)
333 (error "No such coloring type: ~S" coloring-type
)))
334 (color-formatter (coloring-type-term-formatter coloring-type-object
))
335 (*formatter-local-variables
* (funcall (coloring-type-formatter-initial-values coloring-type-object
))))
336 (format nil
"~{~A~}~A"
337 (mapcar color-formatter scan
)
338 (funcall (coloring-type-formatter-after-hook coloring-type-object
)))))
340 (defun encode-for-pre (string)
341 (declare (simple-string string
))
342 (let ((output (make-array (truncate (length string
) 2/3)
343 :element-type
'character
346 (with-output-to-string (out output
)
347 (loop for char across string
349 ((#\
&) (write-string "&" out
))
350 ((#\
<) (write-string "<" out
))
351 ((#\
>) (write-string ">" out
))
352 ((#\") (write-string """ out
))
353 ((#\RIGHTWARDS_DOUBLE_ARROW
) (write-string "⇒" out
))
354 (t (write-char char out
)))))
355 (coerce output
'simple-string
)))
357 (defun string-substitute (string substring replacement-string
)
358 "String substitute by Larry Hunter. Obtained from Google"
359 (let ((substring-length (length substring
))
363 (search substring string
)
364 (search substring string
:start2 last-end
)))
366 (concatenate 'string new-string
(subseq string last-end
)))
370 (subseq string last-end next-start
)
372 (setq last-end
(+ next-start substring-length
)))))
374 (defun decode-from-tt (string)
379 (string-substitute string
"&" "&")
382 "⇒" (string #\RIGHTWARDS_DOUBLE_ARROW
))
385 (defun html-colorization (coloring-type string
)
386 (format-scan coloring-type
387 (mapcar #'(lambda (p)
389 (let ((tt (encode-for-pre (cdr p
))))
390 (if (and (> (length tt
) 0)
391 (char= (elt tt
(1- (length tt
))) #\
>))
392 (format nil
"~A~%" tt
) tt
))))
393 (scan-string coloring-type string
))))
395 (defun colorize-file-to-stream (coloring-type input-file-name s2
&key
(wrap t
) (css-background "default"))
396 (let* ((input-file (if (pathname-type (merge-pathnames input-file-name
))
397 (merge-pathnames input-file-name
)
398 (make-pathname :type
"lisp"
399 :defaults
(merge-pathnames input-file-name
))))
400 (*css-background-class
* css-background
))
401 (with-open-file (s input-file
:direction
:input
)
405 (loop (let ((line (read-line s nil nil
)))
408 (return-from done
)))))
409 (setf string
(format nil
"~{~A~%~}"
413 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">
414 <html><head><style type=\"text/css\">~A~%~A</style><body>
415 <table width=\"100%\"><tr><td class=\"~A\">
417 </tr></td></table></body></html>"
419 (make-background-css "white")
420 *css-background-class
*
421 (html-colorization coloring-type string
))
422 (write-string (html-colorization coloring-type string
) s2
))))))
424 (defun colorize-file (coloring-type input-file-name
&optional output-file-name
)
425 (let* ((input-file (if (pathname-type (merge-pathnames input-file-name
))
426 (merge-pathnames input-file-name
)
427 (make-pathname :type
"lisp"
428 :defaults
(merge-pathnames input-file-name
))))
429 (output-file (or output-file-name
430 (make-pathname :type
"html"
431 :defaults input-file
))))
432 (with-open-file (s2 output-file
:direction
:output
:if-exists
:supersede
)
433 (colorize-file-to-stream coloring-type input-file-name s2
))))
435 ;; coloring-types.lisp
437 ;(in-package :colorize)
439 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
440 (defparameter *version-token
* (gensym)))
442 (defparameter *symbol-characters
*
443 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*!%$&+-1234567890")
445 (defparameter *non-constituent
*
446 '(#\space
#\tab
#\newline
#\linefeed
#\page
#\return
447 #\" #\' #\
( #\
) #\
, #\
; #\` #\[ #\]))
449 (defparameter *special-forms
*
450 '("let" "load-time-value" "quote" "macrolet" "progn" "progv" "go" "flet" "the"
451 "if" "throw" "eval-when" "multiple-value-prog1" "unwind-protect" "let*"
452 "labels" "function" "symbol-macrolet" "block" "tagbody" "catch" "locally"
453 "return-from" "setq" "multiple-value-call"))
455 (defparameter *common-macros
*
456 '("loop" "cond" "lambda"))
458 (defparameter *open-parens
* '(#\
())
459 (defparameter *close-parens
* '(#\
)))
461 (define-coloring-type :lisp
"Basic Lisp"
462 :modes
(:first-char-on-line
:normal
:symbol
:escaped-symbol
:keyword
:string
:comment
463 :multiline
:character
464 :single-escaped
:in-list
:syntax-error
)
465 :default-mode
:first-char-on-line
469 (scan-any *symbol-characters
*)
470 (and (scan #\.
) (scan-any *symbol-characters
*))
471 (and (scan #\\) (advance 1)))
473 :until
(scan-any *non-constituent
*)
475 ((or (scan #\
:) (scan "#:"))
477 :until
(scan-any *non-constituent
*)
485 (scan-any *non-constituent
*)))
492 :until
(scan #\newline
)))
499 ((:normal
:first-char-on-line
)
506 :until
(scan #\newline
)))
512 :until
(scan #\newline
))))
516 :until
(scan "|#"))))
517 ((:symbol
:keyword
:escaped-symbol
:string
)
520 (set-mode :single-escaped
525 :formatter-variables
((paren-counter 0))
526 :formatter-after-hook
(lambda nil
528 (loop for i from paren-counter downto
1
529 collect
"</span></span>")))
531 (((:normal
:first-char-on-line
)
533 (declare (ignore type
))
537 (declare (ignore type
))
538 (labels ((color-parens (s)
539 (let ((paren-pos (find-if-not #'null
540 (mapcar #'(lambda (c)
542 (append *open-parens
*
545 (let ((before-paren (subseq s
0 paren-pos
))
546 (after-paren (subseq s
(1+ paren-pos
)))
547 (paren (elt s paren-pos
))
550 (when (member paren
*open-parens
* :test
#'char
=)
551 (setf count
(mod paren-counter
6))
554 (when (member paren
*close-parens
* :test
#'char
=)
555 (decf paren-counter
))
557 (format nil
"~A<span class=\"paren~A\">~C<span class=\"~A\">~A"
560 paren
*css-background-class
*
561 (color-parens after-paren
))
562 (format nil
"~A</span>~C</span>~A"
564 paren
(color-parens after-paren
))))
567 ((:symbol
:escaped-symbol
)
569 (declare (ignore type
))
570 (let* ((colon (position #\
: s
:from-end t
))
571 (new-s (or (and colon
(subseq s
(1+ colon
))) s
)))
574 (member new-s
*common-macros
* :test
#'string-equal
)
575 (member new-s
*special-forms
* :test
#'string-equal
)
577 (and (> (length new-s
) (length e
))
578 (string-equal e
(subseq new-s
0 (length e
)))))
580 (format nil
"<i><span class=\"symbol\">~A</span></i>" s
))
581 ((and (> (length new-s
) 2)
582 (char= (elt new-s
0) #\
*)
583 (char= (elt new-s
(1- (length new-s
))) #\
*))
584 (format nil
"<span class=\"special\">~A</span>" s
))
586 (:keyword
(lambda (type s
)
587 (declare (ignore type
))
588 (format nil
"<span class=\"keyword\">~A</span>"
590 ((:comment
:multiline
)
592 (declare (ignore type
))
593 (format nil
"<span class=\"comment\">~A</span>"
597 (declare (ignore type
))
598 (format nil
"<span class=\"character\">~A</span>"
602 (declare (ignore type
))
603 (format nil
"<span class=\"string\">~A</span>"
607 (call-formatter (cdr type
) s
)))
610 (declare (ignore type
))
611 (format nil
"<span class=\"syntaxerror\">~A</span>"
614 (define-coloring-type :scheme
"Scheme"
615 :autodetect
(lambda (text)
617 (search "scheme" text
:test
#'char-equal
)
618 (search "chicken" text
:test
#'char-equal
)))
624 :until
(scan-any *non-constituent
*)
628 :until
(scan #\
])))))
632 (declare (ignore type s
))
633 (let ((*open-parens
* (cons #\
[ *open-parens
*))
634 (*close-parens
* (cons #\
] *close-parens
*)))
635 (call-parent-formatter))))
636 ((:symbol
:escaped-symbol
)
638 (declare (ignore type
))
639 (let ((result (if (find-package :r5rs-lookup
)
640 (funcall (symbol-function (intern "SYMBOL-LOOKUP" :r5rs-lookup
))
643 (format nil
"<a href=\"~A\" class=\"symbol\">~A</a>"
644 result
(call-parent-formatter))
645 (call-parent-formatter)))))))
647 (define-coloring-type :elisp
"Emacs Lisp"
648 :autodetect
(lambda (name)
649 (member name
'("emacs")
650 :test
#'(lambda (name ext
)
651 (search ext name
:test
#'char-equal
))))
654 (((:symbol
:escaped-symbol
)
656 (declare (ignore type
))
657 (let ((result (if (find-package :elisp-lookup
)
658 (funcall (symbol-function (intern "SYMBOL-LOOKUP" :elisp-lookup
))
661 (format nil
"<a href=\"~A\" class=\"symbol\">~A</a>"
662 result
(call-parent-formatter))
663 (call-parent-formatter)))))))
665 (define-coloring-type :common-lisp
"Common Lisp"
666 :autodetect
(lambda (text)
667 (search "lisp" text
:test
#'char-equal
))
672 (set-mode :escaped-symbol
673 :until
(scan #\|
)))))
675 (((:symbol
:escaped-symbol
)
677 (declare (ignore type
))
678 (let* ((colon (position #\
: s
:from-end t
:test
#'char
=))
679 (to-lookup (if colon
(subseq s
(1+ colon
)) s
))
680 (result (if (find-package :clhs-lookup
)
681 (funcall (symbol-function (intern "SYMBOL-LOOKUP" :clhs-lookup
))
684 (format nil
"<a href=\"~A\" class=\"symbol\">~A</a>"
685 result
(call-parent-formatter))
686 (call-parent-formatter)))))))
688 (define-coloring-type :common-lisp-file
"Common Lisp File"
690 :default-mode
:in-list
693 (defvar *c-open-parens
* "([{")
694 (defvar *c-close-parens
* ")]}")
696 (defvar *c-reserved-words
*
697 '("auto" "break" "case" "char" "const"
698 "continue" "default" "do" "double" "else"
699 "enum" "extern" "float" "for" "goto"
700 "if" "int" "long" "register" "return"
701 "short" "signed" "sizeof" "static" "struct"
702 "switch" "typedef" "union" "unsigned" "void"
703 "volatile" "while" "__restrict" "_Bool"))
705 (defparameter *c-begin-word
* "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789")
706 (defparameter *c-terminators
* '(#\space
#\return
#\tab
#\newline
#\.
#\
/ #\-
#\
* #\
+ #\
{ #\
} #\
( #\
) #\' #\" #\
[ #\
] #\
< #\
> #\
#))
708 (define-coloring-type :basic-c
"Basic C"
709 :modes
(:normal
:comment
:word-ish
:paren-ish
:string
:char
:single-escape
:preprocessor
)
710 :default-mode
:normal
714 ((scan-any *c-begin-word
*)
716 :until
(scan-any *c-terminators
*)
722 (scan-any *c-open-parens
*)
723 (scan-any *c-close-parens
*))
733 :until
(advance 2))))
736 (set-mode :single-escape
737 :until
(advance 1)))))
740 :formatter-after-hook
(lambda nil
742 (loop for i from paren-counter downto
1
743 collect
"</span></span>")))
747 (declare (ignore type
))
751 (declare (ignore type
))
752 (format nil
"<span class=\"comment\">~A</span>"
756 (declare (ignore type
))
757 (format nil
"<span class=\"string\">~A</span>"
761 (declare (ignore type
))
762 (format nil
"<span class=\"character\">~A</span>"
766 (call-formatter (cdr type
) s
)))
769 (declare (ignore type
))
772 (if (eql (length s
) 1)
774 (when (member (elt s
0) (coerce *c-open-parens
* 'list
))
776 (setf count
(mod paren-counter
6))
777 (incf paren-counter
))
778 (when (member (elt s
0) (coerce *c-close-parens
* 'list
))
781 (setf count
(mod paren-counter
6)))
783 (format nil
"<span class=\"paren~A\">~A<span class=\"~A\">"
784 (1+ count
) s
*css-background-class
*)
785 (format nil
"</span>~A</span>"
790 (declare (ignore type
))
791 (if (member s
*c-reserved-words
* :test
#'string
=)
792 (format nil
"<span class=\"symbol\">~A</span>" s
)
796 (define-coloring-type :c
"C"
801 (set-mode :preprocessor
802 :until
(scan-any '(#\return
#\newline
))))))
806 (declare (ignore type
))
807 (format nil
"<span class=\"special\">~A</span>" s
)))))
809 (defvar *c
++-reserved-words
*
810 '("asm" "auto" "bool" "break" "case"
811 "catch" "char" "class" "const" "const_cast"
812 "continue" "default" "delete" "do" "double"
813 "dynamic_cast" "else" "enum" "explicit" "export"
814 "extern" "false" "float" "for" "friend"
815 "goto" "if" "inline" "int" "long"
816 "mutable" "namespace" "new" "operator" "private"
817 "protected" "public" "register" "reinterpret_cast" "return"
818 "short" "signed" "sizeof" "static" "static_cast"
819 "struct" "switch" "template" "this" "throw"
820 "true" "try" "typedef" "typeid" "typename"
821 "union" "unsigned" "using" "virtual" "void"
822 "volatile" "wchar_t" "while"))
824 (define-coloring-type :c
++ "C++"
830 :until
(scan-any '(#\return
#\newline
))))))
834 (declare (ignore type
))
835 (if (member s
*c
++-reserved-words
* :test
#'string
=)
836 (format nil
"<span class=\"symbol\">~A</span>"
840 (defvar *java-reserved-words
*
841 '("abstract" "boolean" "break" "byte" "case"
842 "catch" "char" "class" "const" "continue"
843 "default" "do" "double" "else" "extends"
844 "final" "finally" "float" "for" "goto"
845 "if" "implements" "import" "instanceof" "int"
846 "interface" "long" "native" "new" "package"
847 "private" "protected" "public" "return" "short"
848 "static" "strictfp" "super" "switch" "synchronized"
849 "this" "throw" "throws" "transient" "try"
850 "void" "volatile" "while"))
852 (define-coloring-type :java
"Java"
857 (declare (ignore type
))
858 (if (member s
*java-reserved-words
* :test
#'string
=)
859 (format nil
"<span class=\"symbol\">~A</span>"
863 (let ((terminate-next nil
))
864 (define-coloring-type :objective-c
"Objective C"
865 :autodetect
(lambda (text) (search "mac" text
:test
#'char
=))
866 :modes
(:begin-message-send
:end-message-send
)
870 (set-mode :begin-message-send
874 (set-mode :end-message-send
877 ((scan-any *c-begin-word
*)
880 (and (peek-any '(#\
:))
881 (setf terminate-next t
))
882 (and terminate-next
(progn
883 (setf terminate-next nil
)
885 (scan-any *c-terminators
*))
891 (set-mode :word-ish
:until
(advance 1) :advancing nil
)
892 (setf terminate-next t
))))
894 :formatter-variables
((is-keyword nil
) (in-message-send nil
))
896 ((:begin-message-send
898 (setf is-keyword nil
)
899 (setf in-message-send t
)
900 (call-formatter (cons :paren-ish type
) s
)))
903 (setf is-keyword nil
)
904 (setf in-message-send nil
)
905 (call-formatter (cons :paren-ish type
) s
)))
908 (declare (ignore type
))
910 (let ((result (if (find-package :cocoa-lookup
)
911 (funcall (symbol-function (intern "SYMBOL-LOOKUP" :cocoa-lookup
))
914 (format nil
"<a href=\"~A\" class=\"symbol\">~A</a>"
916 (if (member s
*c-reserved-words
* :test
#'string
=)
917 (format nil
"<span class=\"symbol\">~A</span>" s
)
920 (format nil
"<span class=\"keyword\">~A</span>" s
)
923 (setf is-keyword
(not is-keyword
))))))))
929 ;(asdf:oos 'asdf:load-op :colorize)
931 (defmacro with-each-stream-line
((var stream
) &body body
)
935 `(let ((,strm
,stream
)
937 (do ((,var
(read-line ,strm nil
,eof
) (read-line ,strm nil
,eof
)))
941 (defun system (control-string &rest args
)
942 "Interpolate ARGS into CONTROL-STRING as if by FORMAT, and
943 synchronously execute the result using a Bourne-compatible shell, with
944 output to *verbose-out*. Returns the shell's exit code."
945 (let ((command (apply #'format nil control-string args
)))
946 (format t
"; $ ~A~%" command
)
948 (sb-impl::process-exit-code
952 :input nil
:output
*standard-output
*))
954 (ext:process-exit-code
958 :input nil
:output
*verbose-out
*))
959 #+clisp
;XXX not exactly *verbose-out*, I know
960 (ext:run-shell-command command
:output
:terminal
:wait t
)
963 (defun strcat (&rest strings
)
964 (apply #'concatenate
'string strings
))
966 (defun string-starts-with (start str
)
967 (and (>= (length str
) (length start
))
968 (string-equal start str
:end2
(length start
))))
970 (defmacro string-append
(outputstr &rest args
)
971 `(setq ,outputstr
(concatenate 'string
,outputstr
,@args
)))
973 (defconstant +indent
+ 0
974 "Indentation used in the examples.")
976 (defun texinfo->raw-lisp
(code)
977 "Answer CODE with spurious Texinfo output removed. For use in
978 preprocessing output in a @lisp block before passing to colorize."
980 (with-output-to-string (output)
981 (do* ((last-position 0)
983 #0=(search #1="<span class=\"roman\">" code
984 :start2 last-position
:test
#'char-equal
)
986 ((eq nil next-position
)
987 (write-string code output
:start last-position
))
988 (write-string code output
:start last-position
:end next-position
)
989 (let ((end (search #2="</span>" code
990 :start2
(+ next-position
(length #1#))
991 :test
#'char-equal
)))
992 (assert (integerp end
) ()
993 "Missing ~A tag in HTML for @lisp block~%~
994 HTML contents of block:~%~A" #2# code
)
995 (write-string code output
996 :start
(+ next-position
(length #1#))
998 (setf last-position
(+ end
(length #2#))))))))
1000 (defun process-file (from to
)
1001 (with-open-file (output to
:direction
:output
:if-exists
:error
)
1002 (with-open-file (input from
:direction
:input
)
1003 (let ((line-processor nil
)
1004 (piece-of-code '()))
1006 ((process-line-inside-pre (line)
1007 (cond ((string-starts-with "</pre>" line
)
1008 (with-input-from-string
1009 (stream (colorize:html-colorization
1012 (apply #'concatenate
'string
1013 (nreverse piece-of-code
)))))
1014 (with-each-stream-line (cline stream
)
1015 (format output
" ~A~%" cline
)))
1016 (write-line line output
)
1017 (setq piece-of-code
'()
1018 line-processor
#'process-regular-line
))
1019 (t (let ((to-append (subseq line
+indent
+)))
1020 (push (if (string= "" to-append
)
1022 to-append
) piece-of-code
)
1023 (push (string #\Newline
) piece-of-code
)))))
1024 (process-regular-line (line)
1025 (let ((len (some (lambda (test-string)
1026 (when (string-starts-with test-string line
)
1027 (length test-string
)))
1028 '("<pre class=\"lisp\">"
1029 "<pre class=\"smalllisp\">"))))
1031 (setq line-processor
#'process-line-inside-pre
)
1032 (write-string "<pre class=\"lisp\">" output
)
1033 (push (subseq line
(+ len
+indent
+)) piece-of-code
)
1034 (push (string #\Newline
) piece-of-code
))
1035 (t (write-line line output
))))))
1036 (setf line-processor
#'process-regular-line
)
1037 (with-each-stream-line (line input
)
1038 (funcall line-processor line
)))))))
1040 (defun process-dir (dir)
1041 (dolist (html-file (directory dir
))
1042 (let* ((name (namestring html-file
))
1043 (temp-name (strcat name
".temp")))
1044 (process-file name temp-name
)
1045 (system "mv ~A ~A" temp-name name
))))
1047 ;; (go "/tmp/doc/manual/html_node/*.html")
1051 (assert (first ext
:*args
*))
1052 (process-dir (first ext
:*args
*)))
1056 (assert (second sb-ext
:*posix-argv
*))
1057 (process-dir (second sb-ext
:*posix-argv
*))