123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059 |
- ;;; This is code was taken from lisppaste2 and is a quick hack
- ;;; to colorize lisp examples in the html generated by Texinfo.
- ;;; It is not general-purpose utility, though it could easily be
- ;;; turned into one.
- ;;;; colorize-package.lisp
- (defpackage :colorize
- (:use :common-lisp)
- (:export :scan-string :format-scan :html-colorization
- :find-coloring-type :autodetect-coloring-type
- :coloring-types :scan :scan-any :advance :call-parent-formatter
- :*coloring-css* :make-background-css :*css-background-class*
- :colorize-file :colorize-file-to-stream :*version-token*))
- ;;;; coloring-css.lisp
- (in-package :colorize)
- (defparameter *coloring-css*
- ".symbol { color: #770055; background-color: transparent; border: 0px; margin: 0px;}
- a.symbol:link { color: #229955; background-color : transparent; text-decoration: none; border: 0px; margin: 0px; }
- a.symbol:active { color : #229955; background-color : transparent; text-decoration: none; border: 0px; margin: 0px; }
- a.symbol:visited { color : #229955; background-color : transparent; text-decoration: none; border: 0px; margin: 0px; }
- a.symbol:hover { color : #229955; background-color : transparent; text-decoration: none; border: 0px; margin: 0px; }
- .special { color : #FF5000; background-color : inherit; }
- .keyword { color : #770000; background-color : inherit; }
- .comment { color : #007777; background-color : inherit; }
- .string { color : #777777; background-color : inherit; }
- .character { color : #0055AA; background-color : inherit; }
- .syntaxerror { color : #FF0000; background-color : inherit; }
- span.paren1:hover { color : inherit; background-color : #BAFFFF; }
- span.paren2:hover { color : inherit; background-color : #FFCACA; }
- span.paren3:hover { color : inherit; background-color : #FFFFBA; }
- span.paren4:hover { color : inherit; background-color : #CACAFF; }
- span.paren5:hover { color : inherit; background-color : #CAFFCA; }
- span.paren6:hover { color : inherit; background-color : #FFBAFF; }
- ")
- (defvar *css-background-class* "lisp-bg")
- (defun for-css (thing)
- (if (symbolp thing) (string-downcase (symbol-name thing))
- thing))
- (defun make-background-css (color &key (class *css-background-class*) (extra nil))
- (format nil ".~A { background-color: ~A; color: black; ~{~A; ~}}~:*~:*~:*
- .~A:hover { background-color: ~A; color: black; ~{~A; ~}}~%"
- class color
- (mapcar #'(lambda (extra)
- (format nil "~A : ~{~A ~}"
- (for-css (first extra))
- (mapcar #'for-css (cdr extra))))
- extra)))
- ;;;; colorize.lisp
- ;(in-package :colorize)
- (eval-when (:compile-toplevel :load-toplevel :execute)
- (defparameter *coloring-types* nil)
- (defparameter *version-token* (gensym)))
- (defclass coloring-type ()
- ((modes :initarg :modes :accessor coloring-type-modes)
- (default-mode :initarg :default-mode :accessor coloring-type-default-mode)
- (transition-functions :initarg :transition-functions :accessor coloring-type-transition-functions)
- (fancy-name :initarg :fancy-name :accessor coloring-type-fancy-name)
- (term-formatter :initarg :term-formatter :accessor coloring-type-term-formatter)
- (formatter-initial-values :initarg :formatter-initial-values :accessor coloring-type-formatter-initial-values :initform nil)
- (formatter-after-hook :initarg :formatter-after-hook :accessor coloring-type-formatter-after-hook :initform (constantly ""))
- (autodetect-function :initarg :autodetect-function :accessor coloring-type-autodetect-function
- :initform (constantly nil))
- (parent-type :initarg :parent-type :accessor coloring-type-parent-type
- :initform nil)
- (visible :initarg :visible :accessor coloring-type-visible
- :initform t)))
- (defun find-coloring-type (type)
- (if (typep type 'coloring-type)
- type
- (cdr (assoc (symbol-name type) *coloring-types* :test #'string-equal :key #'symbol-name))))
- (defun autodetect-coloring-type (name)
- (car
- (find name *coloring-types*
- :key #'cdr
- :test #'(lambda (name type)
- (and (coloring-type-visible type)
- (funcall (coloring-type-autodetect-function type) name))))))
- (defun coloring-types ()
- (loop for type-pair in *coloring-types*
- if (coloring-type-visible (cdr type-pair))
- collect (cons (car type-pair)
- (coloring-type-fancy-name (cdr type-pair)))))
- (defun (setf find-coloring-type) (new-value type)
- (if new-value
- (let ((found (assoc type *coloring-types*)))
- (if found
- (setf (cdr found) new-value)
- (setf *coloring-types*
- (nconc *coloring-types*
- (list (cons type new-value))))))
- (setf *coloring-types* (remove type *coloring-types* :key #'car))))
- (defvar *scan-calls* 0)
- (defvar *reset-position* nil)
- (defmacro with-gensyms ((&rest names) &body body)
- `(let ,(mapcar #'(lambda (name)
- (list name `(make-symbol ,(symbol-name name)))) names)
- ,@body))
- (defmacro with-scanning-functions (string-param position-place mode-place mode-wait-place &body body)
- (with-gensyms (num items position not-preceded-by string item new-mode until advancing)
- `(labels ((advance (,num)
- (setf ,position-place (+ ,position-place ,num))
- t)
- (peek-any (,items &key ,not-preceded-by)
- (incf *scan-calls*)
- (let* ((,items (if (stringp ,items)
- (coerce ,items 'list) ,items))
- (,not-preceded-by (if (characterp ,not-preceded-by)
- (string ,not-preceded-by) ,not-preceded-by))
- (,position ,position-place)
- (,string ,string-param))
- (let ((,item (and
- (< ,position (length ,string))
- (find ,string ,items
- :test #'(lambda (,string ,item)
- #+nil
- (format t "looking for ~S in ~S starting at ~S~%"
- ,item ,string ,position)
- (if (characterp ,item)
- (char= (elt ,string ,position)
- ,item)
- (search ,item ,string :start2 ,position
- :end2 (min (length ,string)
- (+ ,position (length ,item))))))))))
- (if (characterp ,item)
- (setf ,item (string ,item)))
- (if
- (if ,item
- (if ,not-preceded-by
- (if (>= (- ,position (length ,not-preceded-by)) 0)
- (not (string= (subseq ,string
- (- ,position (length ,not-preceded-by))
- ,position)
- ,not-preceded-by))
- t)
- t)
- nil)
- ,item
- (progn
- (and *reset-position*
- (setf ,position-place *reset-position*))
- nil)))))
- (scan-any (,items &key ,not-preceded-by)
- (let ((,item (peek-any ,items :not-preceded-by ,not-preceded-by)))
- (and ,item (advance (length ,item)))))
- (peek (,item &key ,not-preceded-by)
- (peek-any (list ,item) :not-preceded-by ,not-preceded-by))
- (scan (,item &key ,not-preceded-by)
- (scan-any (list ,item) :not-preceded-by ,not-preceded-by)))
- (macrolet ((set-mode (,new-mode &key ,until (,advancing t))
- (list 'progn
- (list 'setf ',mode-place ,new-mode)
- (list 'setf ',mode-wait-place
- (list 'lambda (list ',position)
- (list 'let (list (list '*reset-position* ',position))
- (list 'values ,until ,advancing)))))))
- ,@body))))
- (defvar *formatter-local-variables*)
- (defmacro define-coloring-type (name fancy-name &key modes default-mode transitions formatters
- autodetect parent formatter-variables (formatter-after-hook '(constantly ""))
- invisible)
- (with-gensyms (parent-type term type string current-mode position position-foobage mode-wait new-position advance)
- `(let ((,parent-type (or (find-coloring-type ,parent)
- (and ,parent
- (error "No such coloring type: ~S" ,parent)))))
- (setf (find-coloring-type ,name)
- (make-instance 'coloring-type
- :fancy-name ',fancy-name
- :modes (append ',modes (if ,parent-type (coloring-type-modes ,parent-type)))
- :default-mode (or ',default-mode
- (if ,parent-type (coloring-type-default-mode ,parent-type)))
- ,@(if autodetect
- `(:autodetect-function ,autodetect))
- :parent-type ,parent-type
- :visible (not ,invisible)
- :formatter-initial-values (lambda nil
- (list* ,@(mapcar #'(lambda (e)
- `(cons ',(car e) ,(second e)))
- formatter-variables)
- (if ,parent-type
- (funcall (coloring-type-formatter-initial-values ,parent-type))
- nil)))
- :formatter-after-hook (lambda nil
- (symbol-macrolet ,(mapcar #'(lambda (e)
- `(,(car e) (cdr (assoc ',(car e) *formatter-local-variables*))))
- formatter-variables)
- (concatenate 'string
- (funcall ,formatter-after-hook)
- (if ,parent-type
- (funcall (coloring-type-formatter-after-hook ,parent-type))
- ""))))
- :term-formatter
- (symbol-macrolet ,(mapcar #'(lambda (e)
- `(,(car e) (cdr (assoc ',(car e) *formatter-local-variables*))))
- formatter-variables)
- (lambda (,term)
- (labels ((call-parent-formatter (&optional (,type (car ,term))
- (,string (cdr ,term)))
- (if ,parent-type
- (funcall (coloring-type-term-formatter ,parent-type)
- (cons ,type ,string))))
- (call-formatter (&optional (,type (car ,term))
- (,string (cdr ,term)))
- (funcall
- (case (first ,type)
- ,@formatters
- (t (lambda (,type text)
- (call-parent-formatter ,type text))))
- ,type ,string)))
- (call-formatter))))
- :transition-functions
- (list
- ,@(loop for transition in transitions
- collect (destructuring-bind (mode &rest table) transition
- `(cons ',mode
- (lambda (,current-mode ,string ,position)
- (let ((,mode-wait (constantly nil))
- (,position-foobage ,position))
- (with-scanning-functions ,string ,position-foobage
- ,current-mode ,mode-wait
- (let ((*reset-position* ,position))
- (cond ,@table))
- (values ,position-foobage ,current-mode
- (lambda (,new-position)
- (setf ,position-foobage ,new-position)
- (let ((,advance (nth-value 1 (funcall ,mode-wait ,position-foobage))))
- (values ,position-foobage ,advance)))))
- )))))))))))
- (defun full-transition-table (coloring-type-object)
- (let ((parent (coloring-type-parent-type coloring-type-object)))
- (if parent
- (append (coloring-type-transition-functions coloring-type-object)
- (full-transition-table parent))
- (coloring-type-transition-functions coloring-type-object))))
- (defun scan-string (coloring-type string)
- (let* ((coloring-type-object (or (find-coloring-type coloring-type)
- (error "No such coloring type: ~S" coloring-type)))
- (transitions (full-transition-table coloring-type-object))
- (result nil)
- (low-bound 0)
- (current-mode (coloring-type-default-mode coloring-type-object))
- (mode-stack nil)
- (current-wait (constantly nil))
- (wait-stack nil)
- (current-position 0)
- (*scan-calls* 0))
- (flet ((finish-current (new-position new-mode new-wait &key (extend t) push pop)
- (let ((to (if extend new-position current-position)))
- (if (> to low-bound)
- (setf result (nconc result
- (list (cons (cons current-mode mode-stack)
- (subseq string low-bound
- to))))))
- (setf low-bound to)
- (when pop
- (pop mode-stack)
- (pop wait-stack))
- (when push
- (push current-mode mode-stack)
- (push current-wait wait-stack))
- (setf current-mode new-mode
- current-position new-position
- current-wait new-wait))))
- (loop
- (if (> current-position (length string))
- (return-from scan-string
- (progn
- (format *trace-output* "Scan was called ~S times.~%"
- *scan-calls*)
- (finish-current (length string) nil (constantly nil))
- result))
- (or
- (loop for transition in
- (mapcar #'cdr
- (remove current-mode transitions
- :key #'car
- :test-not #'(lambda (a b)
- (or (eql a b)
- (if (listp b)
- (member a b))))))
- if
- (and transition
- (multiple-value-bind
- (new-position new-mode new-wait)
- (funcall transition current-mode string current-position)
- (when (> new-position current-position)
- (finish-current new-position new-mode new-wait :extend nil :push t)
- t)))
- return t)
- (multiple-value-bind
- (pos advance)
- (funcall current-wait current-position)
- #+nil
- (format t "current-wait returns ~S ~S (mode is ~S, pos is ~S)~%" pos advance current-mode current-position)
- (and pos
- (when (> pos current-position)
- (finish-current (if advance
- pos
- current-position)
- (car mode-stack)
- (car wait-stack)
- :extend advance
- :pop t)
- t)))
- (progn
- (incf current-position)))
- )))))
- (defun format-scan (coloring-type scan)
- (let* ((coloring-type-object (or (find-coloring-type coloring-type)
- (error "No such coloring type: ~S" coloring-type)))
- (color-formatter (coloring-type-term-formatter coloring-type-object))
- (*formatter-local-variables* (funcall (coloring-type-formatter-initial-values coloring-type-object))))
- (format nil "~{~A~}~A"
- (mapcar color-formatter scan)
- (funcall (coloring-type-formatter-after-hook coloring-type-object)))))
- (defun encode-for-pre (string)
- (declare (simple-string string))
- (let ((output (make-array (truncate (length string) 2/3)
- :element-type 'character
- :adjustable t
- :fill-pointer 0)))
- (with-output-to-string (out output)
- (loop for char across string
- do (case char
- ((#\&) (write-string "&" out))
- ((#\<) (write-string "<" out))
- ((#\>) (write-string ">" out))
- ((#\") (write-string """ out))
- ((#\RIGHTWARDS_DOUBLE_ARROW) (write-string "⇒" out))
- (t (write-char char out)))))
- (coerce output 'simple-string)))
- (defun string-substitute (string substring replacement-string)
- "String substitute by Larry Hunter. Obtained from Google"
- (let ((substring-length (length substring))
- (last-end 0)
- (new-string ""))
- (do ((next-start
- (search substring string)
- (search substring string :start2 last-end)))
- ((null next-start)
- (concatenate 'string new-string (subseq string last-end)))
- (setq new-string
- (concatenate 'string
- new-string
- (subseq string last-end next-start)
- replacement-string))
- (setq last-end (+ next-start substring-length)))))
- (defun decode-from-tt (string)
- (string-substitute
- (string-substitute
- (string-substitute
- (string-substitute
- (string-substitute string "&" "&")
- "<" "<")
- ">" ">")
- "⇒" (string #\RIGHTWARDS_DOUBLE_ARROW))
- """ "\""))
- (defun html-colorization (coloring-type string)
- (format-scan coloring-type
- (mapcar #'(lambda (p)
- (cons (car p)
- (let ((tt (encode-for-pre (cdr p))))
- (if (and (> (length tt) 0)
- (char= (elt tt (1- (length tt))) #\>))
- (format nil "~A~%" tt) tt))))
- (scan-string coloring-type string))))
- (defun colorize-file-to-stream (coloring-type input-file-name s2 &key (wrap t) (css-background "default"))
- (let* ((input-file (if (pathname-type (merge-pathnames input-file-name))
- (merge-pathnames input-file-name)
- (make-pathname :type "lisp"
- :defaults (merge-pathnames input-file-name))))
- (*css-background-class* css-background))
- (with-open-file (s input-file :direction :input)
- (let ((lines nil)
- (string nil))
- (block done
- (loop (let ((line (read-line s nil nil)))
- (if line
- (push line lines)
- (return-from done)))))
- (setf string (format nil "~{~A~%~}"
- (nreverse lines)))
- (if wrap
- (format s2
- "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">
- <html><head><style type=\"text/css\">~A~%~A</style><body>
- <table width=\"100%\"><tr><td class=\"~A\">
- <tt>~A</tt>
- </tr></td></table></body></html>"
- *coloring-css*
- (make-background-css "white")
- *css-background-class*
- (html-colorization coloring-type string))
- (write-string (html-colorization coloring-type string) s2))))))
- (defun colorize-file (coloring-type input-file-name &optional output-file-name)
- (let* ((input-file (if (pathname-type (merge-pathnames input-file-name))
- (merge-pathnames input-file-name)
- (make-pathname :type "lisp"
- :defaults (merge-pathnames input-file-name))))
- (output-file (or output-file-name
- (make-pathname :type "html"
- :defaults input-file))))
- (with-open-file (s2 output-file :direction :output :if-exists :supersede)
- (colorize-file-to-stream coloring-type input-file-name s2))))
- ;; coloring-types.lisp
- ;(in-package :colorize)
- (eval-when (:compile-toplevel :load-toplevel :execute)
- (defparameter *version-token* (gensym)))
- (defparameter *symbol-characters*
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*!%$&+-1234567890")
- (defparameter *non-constituent*
- '(#\space #\tab #\newline #\linefeed #\page #\return
- #\" #\' #\( #\) #\, #\; #\` #\[ #\]))
- (defparameter *special-forms*
- '("let" "load-time-value" "quote" "macrolet" "progn" "progv" "go" "flet" "the"
- "if" "throw" "eval-when" "multiple-value-prog1" "unwind-protect" "let*"
- "labels" "function" "symbol-macrolet" "block" "tagbody" "catch" "locally"
- "return-from" "setq" "multiple-value-call"))
- (defparameter *common-macros*
- '("loop" "cond" "lambda"))
- (defparameter *open-parens* '(#\())
- (defparameter *close-parens* '(#\)))
- (define-coloring-type :lisp "Basic Lisp"
- :modes (:first-char-on-line :normal :symbol :escaped-symbol :keyword :string :comment
- :multiline :character
- :single-escaped :in-list :syntax-error)
- :default-mode :first-char-on-line
- :transitions
- (((:in-list)
- ((or
- (scan-any *symbol-characters*)
- (and (scan #\.) (scan-any *symbol-characters*))
- (and (scan #\\) (advance 1)))
- (set-mode :symbol
- :until (scan-any *non-constituent*)
- :advancing nil))
- ((or (scan #\:) (scan "#:"))
- (set-mode :keyword
- :until (scan-any *non-constituent*)
- :advancing nil))
- ((scan "#\\")
- (let ((count 0))
- (set-mode :character
- :until (progn
- (incf count)
- (if (> count 1)
- (scan-any *non-constituent*)))
- :advancing nil)))
- ((scan #\")
- (set-mode :string
- :until (scan #\")))
- ((scan #\;)
- (set-mode :comment
- :until (scan #\newline)))
- ((scan "#|")
- (set-mode :multiline
- :until (scan "|#")))
- ((scan #\()
- (set-mode :in-list
- :until (scan #\)))))
- ((:normal :first-char-on-line)
- ((scan #\()
- (set-mode :in-list
- :until (scan #\)))))
- (:first-char-on-line
- ((scan #\;)
- (set-mode :comment
- :until (scan #\newline)))
- ((scan "#|")
- (set-mode :multiline
- :until (scan "|#")))
- ((advance 1)
- (set-mode :normal
- :until (scan #\newline))))
- (:multiline
- ((scan "#|")
- (set-mode :multiline
- :until (scan "|#"))))
- ((:symbol :keyword :escaped-symbol :string)
- ((scan #\\)
- (let ((count 0))
- (set-mode :single-escaped
- :until (progn
- (incf count)
- (if (< count 2)
- (advance 1))))))))
- :formatter-variables ((paren-counter 0))
- :formatter-after-hook (lambda nil
- (format nil "~{~A~}"
- (loop for i from paren-counter downto 1
- collect "</span></span>")))
- :formatters
- (((:normal :first-char-on-line)
- (lambda (type s)
- (declare (ignore type))
- s))
- ((:in-list)
- (lambda (type s)
- (declare (ignore type))
- (labels ((color-parens (s)
- (let ((paren-pos (find-if-not #'null
- (mapcar #'(lambda (c)
- (position c s))
- (append *open-parens*
- *close-parens*)))))
- (if paren-pos
- (let ((before-paren (subseq s 0 paren-pos))
- (after-paren (subseq s (1+ paren-pos)))
- (paren (elt s paren-pos))
- (open nil)
- (count 0))
- (when (member paren *open-parens* :test #'char=)
- (setf count (mod paren-counter 6))
- (incf paren-counter)
- (setf open t))
- (when (member paren *close-parens* :test #'char=)
- (decf paren-counter))
- (if open
- (format nil "~A<span class=\"paren~A\">~C<span class=\"~A\">~A"
- before-paren
- (1+ count)
- paren *css-background-class*
- (color-parens after-paren))
- (format nil "~A</span>~C</span>~A"
- before-paren
- paren (color-parens after-paren))))
- s))))
- (color-parens s))))
- ((:symbol :escaped-symbol)
- (lambda (type s)
- (declare (ignore type))
- (let* ((colon (position #\: s :from-end t))
- (new-s (or (and colon (subseq s (1+ colon))) s)))
- (cond
- ((or
- (member new-s *common-macros* :test #'string-equal)
- (member new-s *special-forms* :test #'string-equal)
- (some #'(lambda (e)
- (and (> (length new-s) (length e))
- (string-equal e (subseq new-s 0 (length e)))))
- '("WITH-" "DEF")))
- (format nil "<i><span class=\"symbol\">~A</span></i>" s))
- ((and (> (length new-s) 2)
- (char= (elt new-s 0) #\*)
- (char= (elt new-s (1- (length new-s))) #\*))
- (format nil "<span class=\"special\">~A</span>" s))
- (t s)))))
- (:keyword (lambda (type s)
- (declare (ignore type))
- (format nil "<span class=\"keyword\">~A</span>"
- s)))
- ((:comment :multiline)
- (lambda (type s)
- (declare (ignore type))
- (format nil "<span class=\"comment\">~A</span>"
- s)))
- ((:character)
- (lambda (type s)
- (declare (ignore type))
- (format nil "<span class=\"character\">~A</span>"
- s)))
- ((:string)
- (lambda (type s)
- (declare (ignore type))
- (format nil "<span class=\"string\">~A</span>"
- s)))
- ((:single-escaped)
- (lambda (type s)
- (call-formatter (cdr type) s)))
- ((:syntax-error)
- (lambda (type s)
- (declare (ignore type))
- (format nil "<span class=\"syntaxerror\">~A</span>"
- s)))))
- (define-coloring-type :scheme "Scheme"
- :autodetect (lambda (text)
- (or
- (search "scheme" text :test #'char-equal)
- (search "chicken" text :test #'char-equal)))
- :parent :lisp
- :transitions
- (((:normal :in-list)
- ((scan "...")
- (set-mode :symbol
- :until (scan-any *non-constituent*)
- :advancing nil))
- ((scan #\[)
- (set-mode :in-list
- :until (scan #\])))))
- :formatters
- (((:in-list)
- (lambda (type s)
- (declare (ignore type s))
- (let ((*open-parens* (cons #\[ *open-parens*))
- (*close-parens* (cons #\] *close-parens*)))
- (call-parent-formatter))))
- ((:symbol :escaped-symbol)
- (lambda (type s)
- (declare (ignore type))
- (let ((result (if (find-package :r5rs-lookup)
- (funcall (symbol-function (intern "SYMBOL-LOOKUP" :r5rs-lookup))
- s))))
- (if result
- (format nil "<a href=\"~A\" class=\"symbol\">~A</a>"
- result (call-parent-formatter))
- (call-parent-formatter)))))))
- (define-coloring-type :elisp "Emacs Lisp"
- :autodetect (lambda (name)
- (member name '("emacs")
- :test #'(lambda (name ext)
- (search ext name :test #'char-equal))))
- :parent :lisp
- :formatters
- (((:symbol :escaped-symbol)
- (lambda (type s)
- (declare (ignore type))
- (let ((result (if (find-package :elisp-lookup)
- (funcall (symbol-function (intern "SYMBOL-LOOKUP" :elisp-lookup))
- s))))
- (if result
- (format nil "<a href=\"~A\" class=\"symbol\">~A</a>"
- result (call-parent-formatter))
- (call-parent-formatter)))))))
- (define-coloring-type :common-lisp "Common Lisp"
- :autodetect (lambda (text)
- (search "lisp" text :test #'char-equal))
- :parent :lisp
- :transitions
- (((:normal :in-list)
- ((scan #\|)
- (set-mode :escaped-symbol
- :until (scan #\|)))))
- :formatters
- (((:symbol :escaped-symbol)
- (lambda (type s)
- (declare (ignore type))
- (let* ((colon (position #\: s :from-end t :test #'char=))
- (to-lookup (if colon (subseq s (1+ colon)) s))
- (result (if (find-package :clhs-lookup)
- (funcall (symbol-function (intern "SYMBOL-LOOKUP" :clhs-lookup))
- to-lookup))))
- (if result
- (format nil "<a href=\"~A\" class=\"symbol\">~A</a>"
- result (call-parent-formatter))
- (call-parent-formatter)))))))
- (define-coloring-type :common-lisp-file "Common Lisp File"
- :parent :common-lisp
- :default-mode :in-list
- :invisible t)
- (defvar *c-open-parens* "([{")
- (defvar *c-close-parens* ")]}")
- (defvar *c-reserved-words*
- '("auto" "break" "case" "char" "const"
- "continue" "default" "do" "double" "else"
- "enum" "extern" "float" "for" "goto"
- "if" "int" "long" "register" "return"
- "short" "signed" "sizeof" "static" "struct"
- "switch" "typedef" "union" "unsigned" "void"
- "volatile" "while" "__restrict" "_Bool"))
- (defparameter *c-begin-word* "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789")
- (defparameter *c-terminators* '(#\space #\return #\tab #\newline #\. #\/ #\- #\* #\+ #\{ #\} #\( #\) #\' #\" #\[ #\] #\< #\> #\#))
- (define-coloring-type :basic-c "Basic C"
- :modes (:normal :comment :word-ish :paren-ish :string :char :single-escape :preprocessor)
- :default-mode :normal
- :invisible t
- :transitions
- ((:normal
- ((scan-any *c-begin-word*)
- (set-mode :word-ish
- :until (scan-any *c-terminators*)
- :advancing nil))
- ((scan "/*")
- (set-mode :comment
- :until (scan "*/")))
- ((or
- (scan-any *c-open-parens*)
- (scan-any *c-close-parens*))
- (set-mode :paren-ish
- :until (advance 1)
- :advancing nil))
- ((scan #\")
- (set-mode :string
- :until (scan #\")))
- ((or (scan "'\\")
- (scan #\'))
- (set-mode :character
- :until (advance 2))))
- (:string
- ((scan #\\)
- (set-mode :single-escape
- :until (advance 1)))))
- :formatter-variables
- ((paren-counter 0))
- :formatter-after-hook (lambda nil
- (format nil "~{~A~}"
- (loop for i from paren-counter downto 1
- collect "</span></span>")))
- :formatters
- ((:normal
- (lambda (type s)
- (declare (ignore type))
- s))
- (:comment
- (lambda (type s)
- (declare (ignore type))
- (format nil "<span class=\"comment\">~A</span>"
- s)))
- (:string
- (lambda (type s)
- (declare (ignore type))
- (format nil "<span class=\"string\">~A</span>"
- s)))
- (:character
- (lambda (type s)
- (declare (ignore type))
- (format nil "<span class=\"character\">~A</span>"
- s)))
- (:single-escape
- (lambda (type s)
- (call-formatter (cdr type) s)))
- (:paren-ish
- (lambda (type s)
- (declare (ignore type))
- (let ((open nil)
- (count 0))
- (if (eql (length s) 1)
- (progn
- (when (member (elt s 0) (coerce *c-open-parens* 'list))
- (setf open t)
- (setf count (mod paren-counter 6))
- (incf paren-counter))
- (when (member (elt s 0) (coerce *c-close-parens* 'list))
- (setf open nil)
- (decf paren-counter)
- (setf count (mod paren-counter 6)))
- (if open
- (format nil "<span class=\"paren~A\">~A<span class=\"~A\">"
- (1+ count) s *css-background-class*)
- (format nil "</span>~A</span>"
- s)))
- s))))
- (:word-ish
- (lambda (type s)
- (declare (ignore type))
- (if (member s *c-reserved-words* :test #'string=)
- (format nil "<span class=\"symbol\">~A</span>" s)
- s)))
- ))
- (define-coloring-type :c "C"
- :parent :basic-c
- :transitions
- ((:normal
- ((scan #\#)
- (set-mode :preprocessor
- :until (scan-any '(#\return #\newline))))))
- :formatters
- ((:preprocessor
- (lambda (type s)
- (declare (ignore type))
- (format nil "<span class=\"special\">~A</span>" s)))))
- (defvar *c++-reserved-words*
- '("asm" "auto" "bool" "break" "case"
- "catch" "char" "class" "const" "const_cast"
- "continue" "default" "delete" "do" "double"
- "dynamic_cast" "else" "enum" "explicit" "export"
- "extern" "false" "float" "for" "friend"
- "goto" "if" "inline" "int" "long"
- "mutable" "namespace" "new" "operator" "private"
- "protected" "public" "register" "reinterpret_cast" "return"
- "short" "signed" "sizeof" "static" "static_cast"
- "struct" "switch" "template" "this" "throw"
- "true" "try" "typedef" "typeid" "typename"
- "union" "unsigned" "using" "virtual" "void"
- "volatile" "wchar_t" "while"))
- (define-coloring-type :c++ "C++"
- :parent :c
- :transitions
- ((:normal
- ((scan "//")
- (set-mode :comment
- :until (scan-any '(#\return #\newline))))))
- :formatters
- ((:word-ish
- (lambda (type s)
- (declare (ignore type))
- (if (member s *c++-reserved-words* :test #'string=)
- (format nil "<span class=\"symbol\">~A</span>"
- s)
- s)))))
- (defvar *java-reserved-words*
- '("abstract" "boolean" "break" "byte" "case"
- "catch" "char" "class" "const" "continue"
- "default" "do" "double" "else" "extends"
- "final" "finally" "float" "for" "goto"
- "if" "implements" "import" "instanceof" "int"
- "interface" "long" "native" "new" "package"
- "private" "protected" "public" "return" "short"
- "static" "strictfp" "super" "switch" "synchronized"
- "this" "throw" "throws" "transient" "try"
- "void" "volatile" "while"))
- (define-coloring-type :java "Java"
- :parent :c++
- :formatters
- ((:word-ish
- (lambda (type s)
- (declare (ignore type))
- (if (member s *java-reserved-words* :test #'string=)
- (format nil "<span class=\"symbol\">~A</span>"
- s)
- s)))))
- (let ((terminate-next nil))
- (define-coloring-type :objective-c "Objective C"
- :autodetect (lambda (text) (search "mac" text :test #'char=))
- :modes (:begin-message-send :end-message-send)
- :transitions
- ((:normal
- ((scan #\[)
- (set-mode :begin-message-send
- :until (advance 1)
- :advancing nil))
- ((scan #\])
- (set-mode :end-message-send
- :until (advance 1)
- :advancing nil))
- ((scan-any *c-begin-word*)
- (set-mode :word-ish
- :until (or
- (and (peek-any '(#\:))
- (setf terminate-next t))
- (and terminate-next (progn
- (setf terminate-next nil)
- (advance 1)))
- (scan-any *c-terminators*))
- :advancing nil)))
- (:word-ish
- #+nil
- ((scan #\:)
- (format t "hi~%")
- (set-mode :word-ish :until (advance 1) :advancing nil)
- (setf terminate-next t))))
- :parent :c++
- :formatter-variables ((is-keyword nil) (in-message-send nil))
- :formatters
- ((:begin-message-send
- (lambda (type s)
- (setf is-keyword nil)
- (setf in-message-send t)
- (call-formatter (cons :paren-ish type) s)))
- (:end-message-send
- (lambda (type s)
- (setf is-keyword nil)
- (setf in-message-send nil)
- (call-formatter (cons :paren-ish type) s)))
- (:word-ish
- (lambda (type s)
- (declare (ignore type))
- (prog1
- (let ((result (if (find-package :cocoa-lookup)
- (funcall (symbol-function (intern "SYMBOL-LOOKUP" :cocoa-lookup))
- s))))
- (if result
- (format nil "<a href=\"~A\" class=\"symbol\">~A</a>"
- result s)
- (if (member s *c-reserved-words* :test #'string=)
- (format nil "<span class=\"symbol\">~A</span>" s)
- (if in-message-send
- (if is-keyword
- (format nil "<span class=\"keyword\">~A</span>" s)
- s)
- s))))
- (setf is-keyword (not is-keyword))))))))
- ;#!/usr/bin/clisp
- ;#+sbcl
- ;(require :asdf)
- ;(asdf:oos 'asdf:load-op :colorize)
- (defmacro with-each-stream-line ((var stream) &body body)
- (let ((eof (gensym))
- (eof-value (gensym))
- (strm (gensym)))
- `(let ((,strm ,stream)
- (,eof ',eof-value))
- (do ((,var (read-line ,strm nil ,eof) (read-line ,strm nil ,eof)))
- ((eql ,var ,eof))
- ,@body))))
- (defun system (control-string &rest args)
- "Interpolate ARGS into CONTROL-STRING as if by FORMAT, and
- synchronously execute the result using a Bourne-compatible shell, with
- output to *verbose-out*. Returns the shell's exit code."
- (let ((command (apply #'format nil control-string args)))
- (format t "; $ ~A~%" command)
- #+sbcl
- (sb-impl::process-exit-code
- (sb-ext:run-program
- "/bin/sh"
- (list "-c" command)
- :input nil :output *standard-output*))
- #+(or cmucl scl)
- (ext:process-exit-code
- (ext:run-program
- "/bin/sh"
- (list "-c" command)
- :input nil :output *verbose-out*))
- #+clisp ;XXX not exactly *verbose-out*, I know
- (ext:run-shell-command command :output :terminal :wait t)
- ))
- (defun strcat (&rest strings)
- (apply #'concatenate 'string strings))
- (defun string-starts-with (start str)
- (and (>= (length str) (length start))
- (string-equal start str :end2 (length start))))
- (defmacro string-append (outputstr &rest args)
- `(setq ,outputstr (concatenate 'string ,outputstr ,@args)))
- (defconstant +indent+ 0
- "Indentation used in the examples.")
- (defun texinfo->raw-lisp (code)
- "Answer CODE with spurious Texinfo output removed. For use in
- preprocessing output in a @lisp block before passing to colorize."
- (decode-from-tt
- (with-output-to-string (output)
- (do* ((last-position 0)
- (next-position
- #0=(search #1="<span class=\"roman\">" code
- :start2 last-position :test #'char-equal)
- #0#))
- ((eq nil next-position)
- (write-string code output :start last-position))
- (write-string code output :start last-position :end next-position)
- (let ((end (search #2="</span>" code
- :start2 (+ next-position (length #1#))
- :test #'char-equal)))
- (assert (integerp end) ()
- "Missing ~A tag in HTML for @lisp block~%~
- HTML contents of block:~%~A" #2# code)
- (write-string code output
- :start (+ next-position (length #1#))
- :end end)
- (setf last-position (+ end (length #2#))))))))
- (defun process-file (from to)
- (with-open-file (output to :direction :output :if-exists :error)
- (with-open-file (input from :direction :input)
- (let ((line-processor nil)
- (piece-of-code '()))
- (labels
- ((process-line-inside-pre (line)
- (cond ((string-starts-with "</pre>" line)
- (with-input-from-string
- (stream (colorize:html-colorization
- :common-lisp
- (texinfo->raw-lisp
- (apply #'concatenate 'string
- (nreverse piece-of-code)))))
- (with-each-stream-line (cline stream)
- (format output " ~A~%" cline)))
- (write-line line output)
- (setq piece-of-code '()
- line-processor #'process-regular-line))
- (t (let ((to-append (subseq line +indent+)))
- (push (if (string= "" to-append)
- " "
- to-append) piece-of-code)
- (push (string #\Newline) piece-of-code)))))
- (process-regular-line (line)
- (let ((len (some (lambda (test-string)
- (when (string-starts-with test-string line)
- (length test-string)))
- '("<pre class=\"lisp\">"
- "<pre class=\"smalllisp\">"))))
- (cond (len
- (setq line-processor #'process-line-inside-pre)
- (write-string "<pre class=\"lisp\">" output)
- (push (subseq line (+ len +indent+)) piece-of-code)
- (push (string #\Newline) piece-of-code))
- (t (write-line line output))))))
- (setf line-processor #'process-regular-line)
- (with-each-stream-line (line input)
- (funcall line-processor line)))))))
- (defun process-dir (dir)
- (dolist (html-file (directory dir))
- (let* ((name (namestring html-file))
- (temp-name (strcat name ".temp")))
- (process-file name temp-name)
- (system "mv ~A ~A" temp-name name))))
- ;; (go "/tmp/doc/manual/html_node/*.html")
- #+clisp
- (progn
- (assert (first ext:*args*))
- (process-dir (first ext:*args*)))
- #+sbcl
- (progn
- (assert (second sb-ext:*posix-argv*))
- (process-dir (second sb-ext:*posix-argv*))
- (sb-ext:quit))
|