506 lines
19 KiB
Text
Executable file
506 lines
19 KiB
Text
Executable file
#!/usr/bin/env newlisp
|
|
|
|
;; @module newlispdoc
|
|
;; @description Generates documentation and hightligted source from newLISP source files.
|
|
;; @version 1.3 - handle remote files specified in URLs in a url-file
|
|
;; @version 1.4 - title on page changed to index or module name and new index module option
|
|
;; @version 1.5 - removed font restrictions on h1,h2,h3,h4 and added hr as a legal tag
|
|
;; @version 1.6 - don't allow 3 semicolons at the beginning of a comment line
|
|
;; @version 1.7 - 1.6 did not sense lines with semicolon only as parapgraph separators
|
|
;; @version 1.8 - fixed problem of "true" appearing before multiple syntax statements
|
|
;; @version 1.9 - write-line is now version sensitive for 10.0
|
|
;; @version 2.0 - adds handling of < ?...> XML tag
|
|
;; @version 2.1 - generate more compliant HTML 4.01 for doc and syntax highlighting
|
|
;; but special arithmetik op characters in functionnames still cause
|
|
;; non-compliant HTML (this occurs only in modules/gmp.lsp)
|
|
;; @version 2.2 - fix issue with paragraph spacing and module text font from 2.1
|
|
;; @version 2.3 - handle scientific notation with e
|
|
;; @version 2.4 - improved keyword regex for syntax highlighting
|
|
;; @version 2.5 - scientific notation with E
|
|
;; @version 2.6 - allow custom tags e.g: @MyTag the descriptive text (may contain @link)
|
|
;; @version 2.7 - link rag did not work at beginnning of line
|
|
;; @version 2.8 - support for newLISPdoc tag color
|
|
;; @version 2.9 - correctly highlight & and ^ keywords
|
|
;; @version 3.0 - when -d is specified, add download link
|
|
;; @version 3.1 - changed <tt>write-buffer</tt> to shorter <tt>write</tt>, <tt>name</tt> to <tt>term</tt>
|
|
;; @version 3.2 - formatting when view source, new stylesheet newlispdoc.css
|
|
;; @version 3.3 - allow descriving variables using the @syntax tag. They will be colored red as well.
|
|
;; @version 3.4 - make sure all @xxxxxx custom tags are title cased
|
|
;; @version 3.5 - added META tag for UTF-8 encoding for html output
|
|
;; @version 3.6 - allow trailing spaces on lines in index files
|
|
;; @version 3.7 - forgotten * in @example pattern
|
|
;;
|
|
;; @author Lutz Mueller, 2006-2012
|
|
;; @location http://newlisp.org
|
|
;;
|
|
;; <h3>Usage:</h3>
|
|
;; The <tt>-s</tt> and <tt>-s</tt> switches can be used to generate highlighted source files,
|
|
;; links and and download links
|
|
;; <pre>
|
|
;; newlispdoc afile.lsp bfile.lsp
|
|
;; newlispdoc -s afile.lsp bfile.lsp
|
|
;; newlispdoc -s *.lsp
|
|
;; newlispdoc -s -d *.lsp
|
|
;; <br>
|
|
;; ; or on Win32
|
|
;; newlisp newlispdoc afile.lsp bfile.lsp
|
|
;; newlisp newlispdoc -s afile.lsp bfile.lsp
|
|
;; newlisp newlispdoc -s *.lsp
|
|
;; newlisp newlispdoc -s -d *.lsp
|
|
;; </pre>
|
|
;; newlispdoc can take a file of URLs and generate documentation and syntax
|
|
;; highlighted source from remote files:
|
|
;; <pre>
|
|
;; newlispdoc -url file-with-urls.txt 10000
|
|
;; newlispdoc -s -url file-with-urls.txt 10000
|
|
;; <br>
|
|
;; ; or on Win32
|
|
;; newlisp newlispdoc -url file-with-urls.txt 10000
|
|
;; newlisp newlispdoc -s -url file-with-urls.txt 10000
|
|
;; </pre>
|
|
;; file-with-urls.txt contains one URL per line in the file. A URLstarts either
|
|
;; with http:// or file:// - This allows mixing remote and local files. An optional
|
|
;; timeout of 10 seconds is specified after the url file name. If no timeout is specified
|
|
;; newlispdoc assumes 5 seconds.
|
|
;;
|
|
;; Execute from within the same directory of the source files when
|
|
;; no url file is given.
|
|
;;
|
|
;; For each file a file with the same name and extension '.html' is generated
|
|
;; and written to the current directory. A file 'index.htm' is written as
|
|
;; an index for all other files generated. If the '-s' switch is specified,
|
|
;; a file with the extension '.src.html' is generated for each file.
|
|
;;
|
|
;; Please read @link http://newlisp.org/newLISPdoc.html newLISPdoc.html to learn
|
|
;; about tagging of newLISP source code for newlispdoc.
|
|
;;
|
|
|
|
; make compatible with older versions of newLISP
|
|
(when (< (sys-info -2) 10111)
|
|
(constant (global 'write) write-buffer)
|
|
(constant (global 'term) name))
|
|
|
|
; get list of files from command line
|
|
(set 'files (2 (main-args)))
|
|
|
|
(when (empty? files)
|
|
(println "USAGE: newlispdoc [-s] [-d] <file-names>")
|
|
(println "USAGE: newlispdoc [-s] [-d] -url <file-with-urls>")
|
|
(exit -1))
|
|
|
|
|
|
(set 'prolog1
|
|
[text]<!DOCTYPE HTML PUBLIC "HTML 4.01 Transitional">
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<title>%s</title>
|
|
[/text])
|
|
|
|
(set 'stylesheet
|
|
[text]
|
|
<link rel="stylesheet" type="text/css" href="newlispdoc.css" />
|
|
</head>
|
|
[/text])
|
|
|
|
(set 'prolog2
|
|
[text]
|
|
<body style="margin: 20px;" text="#111111" bgcolor="#FFFFFF"
|
|
link="#376590" vlink="#551A8B" alink="#ffAA28">
|
|
<blockquote>
|
|
<center><h1>%s</h1></center>
|
|
[/text])
|
|
|
|
(set 'prolog3 {<p><a href="index.html">Module index</a></p>})
|
|
|
|
(set 'epilog [text]
|
|
<br/><br/><center>- ∂ -</center><br/>
|
|
<center><font face='Arial' size='-2' color='#444444'>
|
|
generated with <a href="http://newlisp.org">newLISP</a>
|
|
and <a href="http://newlisp.org/newLISPdoc.html">newLISPdoc</a>
|
|
</font></center>
|
|
</blockquote>
|
|
</body>
|
|
</html>
|
|
[/text])
|
|
|
|
; ---------- routines for generating syntax-highlighted file <file-name>.src.html ------------------
|
|
|
|
(define keyword-color "#0000AA") ; newLISP keywords
|
|
(define tag-color "#308080") ; newLISPdoc tags
|
|
(define string-color "#008800") ; single line quoted and braced strings
|
|
(define long-string-color "#008800") ; multiline for [text], [/text] tags
|
|
(define paren-color "#AA0000") ; parenthesis
|
|
(define comment-color "#555555") ; comments
|
|
(define number-color "#665500") ; numbers
|
|
|
|
(define function-name-color "#000088") ; not implemented yet for func in (define (func x y z) ...)
|
|
|
|
(set 'keywords (map term (filter (fn (x) (primitive? (eval x))) (sort (symbols) > ))))
|
|
(push "nil" keywords)
|
|
(push "true" keywords)
|
|
(set 'keyword-regex (join keywords "|"))
|
|
(replace "&" keyword-regex "&&")
|
|
(replace "?" keyword-regex "\\?")
|
|
(replace "^" keyword-regex "\\^")
|
|
(replace "$" keyword-regex "\\$")
|
|
(replace "!" keyword-regex "\\!")
|
|
(replace "+" keyword-regex "\\+")
|
|
(replace "*" keyword-regex "\\*")
|
|
(replace "||" keyword-regex "|\\|")
|
|
(set 'keyword-regex (append {(\G|\s+|\(|\))(} keyword-regex {)(\s+|\(|\))}))
|
|
|
|
(define (clean-comment str)
|
|
(replace {<font color='#......'>} str "" 0)
|
|
(replace {</font>} str "")
|
|
(replace {[text]} str "[&text]")
|
|
(replace {[/text]} str "[&/text]")
|
|
)
|
|
|
|
(define (format-quoted-string str)
|
|
(replace {<font color='#......'>} str "" 0)
|
|
(replace {</font>} str "")
|
|
(replace ";" str ";&")
|
|
(replace "{" str "{&")
|
|
(replace "}" str "}&")
|
|
(replace {\} str "\&")
|
|
(replace {[text]} str "[&text]")
|
|
(replace {[/text]} str "[&/text]")
|
|
(format {<font color='%s'>%s</font>} string-color str)
|
|
)
|
|
|
|
(define (format-braced-string str)
|
|
(replace {<font color='#......'>} str "" 0)
|
|
(replace {</font>} str "")
|
|
(replace ";" str ";&")
|
|
(replace {"} str ""&")
|
|
(replace {[text]} str "[&text]")
|
|
(replace {[/text]} str "[&/text]")
|
|
(format {<font color='%s'>%s</font>} string-color str)
|
|
)
|
|
|
|
(define (format-tagged-string str)
|
|
(replace {<font color='#......'>} str "" 0)
|
|
(replace {</font>} str "")
|
|
(replace ";" str ";&")
|
|
(format {<font color='%s'>%s</font>} string-color str)
|
|
)
|
|
|
|
(define (write-syntax-highlight title src-file outputfile)
|
|
; replace special HTML characters
|
|
(replace "\r\n" src-file "\n")
|
|
(replace "&" src-file "&&")
|
|
(replace "<(\\w)" src-file (append "<&" $1) 0)
|
|
(replace "(\\w)>" src-file (append $1 ">&") 0)
|
|
(replace "/>" src-file "/>&" 0)
|
|
(replace "</" src-file "<&/" 0)
|
|
(replace "<!" src-file "<&!" 0)
|
|
(replace "<\\?" src-file "<&?" 0)
|
|
; replace escaped quotes
|
|
(replace "\092\034" src-file "\&"&")
|
|
|
|
; color keywords
|
|
(replace keyword-regex src-file
|
|
(format {%s<font color='%s'>%s</font>%s} $1 keyword-color $2 $3) 0)
|
|
|
|
; color numbers
|
|
(replace
|
|
; <-- lead --><---- hex ---->|<- oct ->|<------- decimal ----- and ----- scientific -->
|
|
{(\s+|\(|\))(0x[0-9a-fA-F]+|[+-]?0\d+|([+-]?(0|[1-9]\d*)(\.\d*)?|\.\d+)([eE][+-]?\d+)?)} src-file
|
|
(format {%s<font color='%s'>%s</font>} $1 number-color $2) 0)
|
|
|
|
; color parens
|
|
(replace "(" src-file (format {<font color='%s'>(</font>} paren-color))
|
|
(replace ")" src-file (format {<font color='%s'>)</font>} paren-color))
|
|
|
|
; color braced strings
|
|
(replace "{.*?}" src-file (format-braced-string $0) 0) ; no multiline string
|
|
; color quoted strings
|
|
(replace {".*?"} src-file (format-quoted-string $0) 0) ; no multiline strings
|
|
|
|
; color ; comments
|
|
(replace ";.*" src-file (clean-comment $0) 0)
|
|
(replace ";.*" src-file (format {<font color='%s'>%s</font>} comment-color $0) 0)
|
|
(replace "(;;.*)(@.*)(\\s.*\n)" src-file
|
|
(append $1 (format {<font color='%s'>%s</font>} tag-color $2) $3) 512)
|
|
|
|
; color # comments
|
|
(set 'buff "")
|
|
(dolist (lne (parse src-file "\n"))
|
|
(replace "^\\s*#.*" lne (clean-comment $0) 0)
|
|
(replace "^\\s*#.*" lne (format {<font color='%s'>%s</font>} comment-color $0) 0)
|
|
(if (< (sys-info -2) 9909)
|
|
(write-line lne buff)
|
|
(write-line buff lne)))
|
|
|
|
(set 'src-file buff)
|
|
|
|
; color tagged strings
|
|
(replace {\[text\].*?\[/text\]} src-file
|
|
(format-tagged-string $0) 4) ; handles multiline strings
|
|
|
|
; xlate back special characters
|
|
(replace "&&" src-file "&") ; ampersand
|
|
(replace "<&" src-file "<") ; less
|
|
(replace ">&" src-file ">") ; greater
|
|
(replace {"&} src-file """) ; quotes
|
|
(replace {;&} src-file ";") ; semicolon
|
|
(replace {{&} src-file "{") ; left curly brace
|
|
(replace {}&} src-file "}") ; right curly brace
|
|
(replace {[&} src-file "[") ; left bracket
|
|
(replace {\&} src-file "\") ; back slash
|
|
|
|
; add pre and post tags
|
|
(write-file (string outputfile ".src.html")
|
|
(append
|
|
{<!DOCTYPE HTML PUBLIC "4.01 Transitional">}
|
|
{<META http-equiv="Content-Type" content="text/html; charset=utf-8" />}
|
|
"<html><title>" title "</title><body><pre>\n" src-file "\n</pre>"
|
|
{<center><font face='Arial' size='-3' color='#666666'>}
|
|
{syntax highlighting with <a href="http://newlisp.org">newLISP</a> }
|
|
{and <a href="http://newlisp.org/newLISPdoc.html">newLISPdoc</a>}
|
|
{</font></center></body></html>}))
|
|
)
|
|
|
|
;---------------------------------- End syntax highlighting routines ------------------------
|
|
|
|
; get command line switch -s for generating syntax highlighted source
|
|
(let (pos (find "-s" files))
|
|
(when pos
|
|
(pop files pos)
|
|
(set 'source-link true)))
|
|
|
|
; get command line switch -d for generating a download link
|
|
(let (pos (find "-d" files))
|
|
(when pos
|
|
(pop files pos)
|
|
(set 'download-link true)))
|
|
|
|
; get command line switch -url for retrieving files via http from remote location
|
|
(let (pos (find "-url" files))
|
|
(when pos
|
|
(pop files pos)
|
|
(set 'url-file (files pos))
|
|
(set 'time-out (int (last files) 5000))))
|
|
|
|
; if url-file is specified make a list of all urls
|
|
(when url-file
|
|
(set 'files (parse (read-file url-file) "\\s+" 0)))
|
|
|
|
(when (= (last files) "") (pop files -1))
|
|
|
|
(set 'indexpage "") ; buffer for modules index page
|
|
(write indexpage (format prolog1 "Index"))
|
|
(write indexpage stylesheet)
|
|
(write indexpage (format prolog2 "Index"))
|
|
|
|
; reformat
|
|
|
|
(define (protect-html text)
|
|
(replace "<h1>" text "[h1]")
|
|
(replace "<h2>" text "[h2]")
|
|
(replace "<h3>" text "[h3]")
|
|
(replace "<h4>" text "[h4]")
|
|
(replace "</h1>" text "[/h1]")
|
|
(replace "</h2>" text "[/h2]")
|
|
(replace "</h3>" text "[/h3]")
|
|
(replace "</h4>" text "[/h4]")
|
|
(replace "<i>" text "[i]")
|
|
(replace "</i>" text "[/i]")
|
|
(replace "<em>" text "[em]")
|
|
(replace "</em>" text "[/em]")
|
|
(replace "<b>" text "[b]")
|
|
(replace "</b>" text "[/b]")
|
|
(replace "<tt>" text "[tt]")
|
|
(replace "</tt>" text "[/tt]")
|
|
(replace "<p>" text "[p]")
|
|
(replace "</p>" text "[/p]")
|
|
(replace "<br>" text "[br]")
|
|
(replace "<br/>" text "[br/]")
|
|
(replace "<pre>" text "[pre]")
|
|
(replace "</pre>" text "[/pre]")
|
|
(replace "<center>" text "[center]")
|
|
(replace "</center>" text "[/center]")
|
|
(replace "<li>" text "[li]")
|
|
(replace "</li>" text "[/li]")
|
|
(replace "</ul>" text "[/ul]")
|
|
(replace "<ul>" text "[ul]")
|
|
(replace "</blockquote>" text "[/blockquote]")
|
|
(replace "<blockquote>" text "[blockquote]")
|
|
(replace "<hr>" text "[hr]")
|
|
(replace "<hr/>" text "[hr/]")
|
|
)
|
|
|
|
(define (unprotect-html text)
|
|
(replace "[h1]" text "<h1>")
|
|
(replace "[h2]" text "<h2>")
|
|
(replace "[h3]" text "<h3>")
|
|
(replace "[h4]" text "<h4>")
|
|
(replace "[/h1]" text "</h1>")
|
|
(replace "[/h2]" text "</h2>")
|
|
(replace "[/h3]" text "</h3>")
|
|
(replace "[/h4]" text "</h4>")
|
|
(replace "[i]" text "<i>")
|
|
(replace "[/i]" text "</i>")
|
|
(replace "[em]" text "<em>")
|
|
(replace "[/em]" text "</em>")
|
|
(replace "[b]" text "<b>")
|
|
(replace "[/b]" text "</b>")
|
|
(replace "[tt]" text "<tt>")
|
|
(replace "[/tt]" text "</tt>")
|
|
(replace "[p]" text "<p>")
|
|
(replace "[/p]" text "</p>")
|
|
(replace "[br]" text "<br>")
|
|
(replace "[br/]" text "<br/>")
|
|
(replace "[pre]" text "<pre>")
|
|
(replace "[/pre]" text "</pre>")
|
|
(replace "[center]" text "<center>")
|
|
(replace "[/center]" text "</center>")
|
|
(replace "[li]" text "<li>")
|
|
(replace "[/li]" text "</li>")
|
|
(replace "[ul]" text "<ul>")
|
|
(replace "[/ul]" text "</ul>")
|
|
(replace "[blockquote]" text "<blockquote>")
|
|
(replace "[/blockquote]" text "</blockquote>")
|
|
(replace "[hr]" text "<hr>")
|
|
(replace "[hr/]" text "<hr/>")
|
|
)
|
|
|
|
; format the example tags
|
|
(define (format-example text)
|
|
(replace "<" text "<")
|
|
(replace ">" text ">")
|
|
(string "<b>Example:</b><blockquote><pre>" (replace ";;" text "") "</pre></blockquote>\n")
|
|
)
|
|
|
|
; write the module tag link on the index page
|
|
; put source link on doc page if -s flag
|
|
(define (format-module text desc filename , module)
|
|
(set 'module (string "<br/>\n<h2>Module: " text "</h2>"))
|
|
(write indexpage (string {<a href="} filename {.html">} module "</a>\n" ))
|
|
(write indexpage (string "<p>" desc "</p>\n"))
|
|
|
|
(let (link "")
|
|
(if source-link (setq link (string {<a href="} filename {.src.html">source</a> })))
|
|
(if download-link (write link (string {<a href="} filename {">download</a>})))
|
|
(string link module)
|
|
)
|
|
)
|
|
|
|
; write the function name links on the index page under the module
|
|
(define (format-func-link func-name file-name)
|
|
(let (names (if (find ":" func-name) (parse func-name ":") (list "" func-name)))
|
|
(write indexpage (string {<a href="} file-name
|
|
{.html#} (names 0) "_" (names 1) {">} (names 1) {</a> }))
|
|
(string (names 0) "_" (names 1))
|
|
)
|
|
)
|
|
|
|
; format the syntax line
|
|
(define (format-syntax text file-name, tag)
|
|
(replace "<([^<]*?)>" text (string "<em>" $1 "</em>") 0)
|
|
(replace {^ *\((.*?) (.*?\))} text (string "(<font color=#CC0000>" $1 "</font> " $2) 0)
|
|
(replace {^ *\(([^ ]*?)\)} text (string "(<font color=#CC0000>" $1 "</font>)") 0)
|
|
(replace {^ *([^ ()]*?)$} text (string "<font color=#CC0000>" $1 "</font>") 0)
|
|
(string
|
|
(if (!= old-syntax $1)
|
|
(begin
|
|
(set 'old-syntax $1)
|
|
(set 'tag (format-func-link $1 file-name))
|
|
(set 'tag (string {<a name="} tag {"></a>}))
|
|
(string "<br/><br/><center>§</center><br/>\n" tag
|
|
"<h3><font color=#CC0000>" old-syntax "</font></h3>\n"))
|
|
"")
|
|
"<b>syntax: " (trim text) "</b><br/>\n")
|
|
)
|
|
|
|
(define (format-parameter param text)
|
|
(string "<b>parameter: </b>" (format-text (trim param)) " - " (format-text text) "<br/>\n")
|
|
)
|
|
|
|
(define (format-return text)
|
|
(string "<p><b>return: </b>" (format-text text) "</p>\n")
|
|
)
|
|
|
|
(define (format-text text)
|
|
(replace "<([^<]*?)>" text (string "<em>" $1 "</em>") 0)
|
|
(replace "'([^\\s].*?[^\\s])'" text (string "<tt>" $1 "</tt>") 0)
|
|
)
|
|
|
|
;---------------------------------- End newlisdoc formatting subroutines ----------------
|
|
; MAIN function
|
|
|
|
(dolist (fle files)
|
|
(println fle)
|
|
(set 'html "")
|
|
|
|
(set 'original (read-file fle time-out))
|
|
|
|
(if (not original)
|
|
(begin
|
|
(println "Could not read " fle)
|
|
(exit 1)))
|
|
|
|
(if (starts-with original "ERR:")
|
|
(println "Could not read " fle " " original))
|
|
|
|
(set 'outfile (last (parse fle "\\\\|/" 0)))
|
|
|
|
(set 'page (parse (replace "\r\n" original "\n") "\n"))
|
|
|
|
(set 'page (filter (fn (ln) (or (starts-with ln ";;(?!;)" 0) (= (length (trim ln)) 0))) page))
|
|
(set 'page (join page "\n"))
|
|
|
|
; link to another index page
|
|
(when (find ";; *@index ([^ ]*?) ([^ ]*?)\\s*\n" page 0)
|
|
(write indexpage
|
|
(string {<br /><br /><h2><a href="} $2 {">Index: } $1 "</a></h2>\n"))
|
|
(when (find ";; *@description (.*?)\n" page 0)
|
|
(write indexpage (string $1 "<br/>\n")))
|
|
)
|
|
|
|
|
|
(if (find ";; *@module " page 0)
|
|
(begin
|
|
(replace {;;(.*) @link ([^ ]*?) ([^ ]*?)\s} page (string $1 { <a href="} $2 {">} $3 {</a> }) 0)
|
|
(replace ";; *@example *\n(.*?)\n\\s*\n" page (format-example $1) 4)
|
|
(set 'page (protect-html page))
|
|
(set 'desc "")
|
|
(replace ";; *@description (.*?)\n" page (begin (set 'desc $1) (string "<p>" desc "</p>\n") ) 0)
|
|
(replace ";; *@module (.*?)\n" page (format-module $1 desc outfile) 0)
|
|
(set 'module-title $1)
|
|
(replace ";; *@author (.*?)\n" page (string "<b>Author: </b>" $1 "<br/>\n") 0)
|
|
(replace ";; *@version (.*?)\n" page (string "<b>Version: </b>" $1 "<br/>\n") 0)
|
|
(replace ";; *@location (.*?)\n" page
|
|
(string {<b>Location: </b><a href="} $1 {">} $1 "</a><br/>\n") 0)
|
|
(replace ";; *@syntax (.*?)\n" page (format-syntax $1 outfile) 0)
|
|
(replace ";; *@param (.*?) (.*?)\n" page (format-parameter $1 $2) 0)
|
|
(replace ";; *@return (.*?)\n" page (format-return $1) 0)
|
|
;; custom tags, upper-case first letter
|
|
(replace ";; *@([a-zA-Z_-]*?) (.*?)\n" page (string "<b>" (title-case $1) ": </b>" $2 "<br/>\n") 0)
|
|
(replace ";;\\s*\n" page "<br/><br/>\n" 0)
|
|
(replace ";;(.*\n)" page (format-text $1) 0)
|
|
(set 'page (unprotect-html page))
|
|
(write html (format prolog1 outfile))
|
|
(write html stylesheet)
|
|
(write html (format prolog2 outfile))
|
|
(write html prolog3)
|
|
(write html page)
|
|
(write html epilog)
|
|
|
|
(write-file (string outfile ".html") html)
|
|
|
|
; write syntax highlighted source
|
|
(if source-link
|
|
(write-syntax-highlight module-title original outfile))
|
|
|
|
)
|
|
)
|
|
)
|
|
|
|
; write the modules index page
|
|
(write indexpage epilog)
|
|
(write-file "index.html" indexpage)
|
|
|
|
(exit)
|
|
|