├── .gitignore ├── Makefile ├── README ├── css ├── example.css ├── exp.css ├── green.css ├── jacob.css ├── jemdoc.css ├── nolines.css ├── page.css ├── prob.css ├── table.css └── white.css ├── jemdoc ├── latexmath2png.py ├── notes └── www ├── .gitignore ├── MENU ├── Makefile ├── cheatsheet.jemdoc ├── contact.jemdoc ├── dist ├── Makefile ├── jemdoc.css ├── jemdoc.py ├── jemdoc.py-0.2.0 ├── jemdoc.py-0.3.0 ├── jemdoc.py-0.3.3 ├── jemdoc.py-0.3.4 ├── jemdoc.py-0.3.5 ├── jemdoc.py-0.3.6 ├── jemdoc.py-0.4.0 ├── jemdoc.py-0.5.0 ├── jemdoc.py-0.5.1 ├── jemdoc.py-0.5.2 ├── jemdoc.py-0.5.3 ├── jemdoc.py-0.5.4 ├── jemdoc.py-0.6.0 ├── jemdoc.py-0.6.1 ├── jemdoc.py-0.6.2 ├── jemdoc.py-0.6.3 ├── jemdoc.py-0.6.4 ├── jemdoc.py-0.6.5 ├── jemdoc.py-0.6.6 ├── jemdoc.py-0.6.7 ├── jemdoc.py-0.6.8 ├── jemdoc.py-0.7.0 ├── jemdoc.py-0.7.1 ├── jemdoc.py-0.7.2 ├── jemdoc.py-0.7.3 └── jemdoc.vim ├── download.jemdoc ├── example.jemdoc ├── exampleIN.jemdoc ├── extra.jemdoc ├── htmlchanges.jemdoc ├── index.jemdoc ├── jemdoc.conf ├── latex.jemdoc ├── menu.jemdoc ├── modelines.jemdoc ├── procexample.py ├── revision.jemdoc ├── stuff.jemdoc ├── tables.jemdoc └── using.jemdoc /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | otherstuff 3 | proctags.py 4 | *.swp 5 | tags.vim 6 | tags 7 | matlab 8 | build 9 | MANIFEST 10 | jo 11 | *.html 12 | stage/ 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY : update 2 | update : 3 | @make -C www update 4 | 5 | .PHONY : realupdate 6 | realupdate : 7 | @make -C www realupdate 8 | 9 | .PHONY : wwws 10 | docs : 11 | @make -C www docs 12 | 13 | .PHONY : clean 14 | clean : 15 | @make -C www clean 16 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | jemdoc is a light text-based markup language designed for creating websites. It 2 | takes a text file written with jemdoc markup, an optional configuration file and 3 | an optional menu file, and makes static websites that look something like 4 | http://jemdoc.jaboc.net/. 5 | 6 | It was written by me, Jacob Mattingley, in 2007, and definitely isn't the type 7 | of code I would put on my CV. Lots of people use jemdoc, especially in academia. 8 | 9 | Much more info at http://jemdoc.jaboc.net/. 10 | -------------------------------------------------------------------------------- /css/example.css: -------------------------------------------------------------------------------- 1 | table.dual-mode { 2 | padding: 0; 3 | margin-top, margin-bottom: 0.5em; 4 | border-width: 0; 5 | } 6 | 7 | table.dual-mode tr { 8 | vertical-align: top; 9 | } 10 | 11 | table.dual-mode h1, tr h2{ 12 | padding-top: 0em; 13 | margin-top: 0; 14 | } 15 | 16 | td { 17 | text-align: left; 18 | border: none; 19 | } 20 | 21 | td.rightcell tt { 22 | background: none; 23 | } 24 | 25 | td.rightcell div.blockcontent { 26 | padding: 0; 27 | border: 0; 28 | } 29 | 30 | td.rightcell div.codeblock { 31 | margin-top: 0; 32 | margin-bottom: 0; 33 | } 34 | 35 | 36 | td.leftcell { 37 | padding-right: 10px; 38 | padding-top: 10px; 39 | width: 50%; 40 | } 41 | 42 | td.rightcell { 43 | background-color: #f6f6f6; 44 | padding-left: 5px; 45 | vertical-align: top; 46 | padding-right: 10px; 47 | width: 50%; 48 | padding-bottom: 1em; 49 | } 50 | 51 | td.sepcell { 52 | padding-left: 0px; 53 | } 54 | 55 | td.leftcell div.infoblock { 56 | margin-top: 0; 57 | margin-bottom: 0; 58 | } 59 | -------------------------------------------------------------------------------- /css/exp.css: -------------------------------------------------------------------------------- 1 | body { 2 | font: 80% Verdana, sans-serif; 3 | } 4 | 5 | pre, tt { 6 | font-size: 110%; 7 | } 8 | 9 | tt { 10 | background: #ffffdd; 11 | color: #000050; 12 | } 13 | 14 | pre { 15 | color: black; 16 | } 17 | 18 | a { 19 | border-bottom: 1px solid #bbbbbb; 20 | } 21 | 22 | a:hover { 23 | border-bottom: 1px solid #bbbbbb; 24 | } 25 | 26 | h1 { 27 | font-size: 150%; 28 | border: none; 29 | } 30 | 31 | h2 { 32 | font-size: 115%; 33 | border: none; 34 | } 35 | 36 | h3 { 37 | font-size: 100%; 38 | border: none; 39 | } 40 | 41 | 42 | div.infoblock > div.blockcontent { 43 | background: #ffffdd; 44 | } 45 | 46 | div.blockcontent { 47 | padding-left: 10px; 48 | padding-right: 10px; 49 | padding-top: 6px; 50 | padding-bottom: 7px; 51 | } 52 | 53 | p { 54 | line-height: 1.5em; 55 | margin-bottom: 1.2em; 56 | } 57 | 58 | #layout-menu { 59 | padding-left: 15px; 60 | line-height: 1.7em; 61 | text-align: right; 62 | padding-top: 0.5em; 63 | } 64 | 65 | b { 66 | font-weight: normal; 67 | } 68 | 69 | p b { 70 | font-style: italic; 71 | } 72 | 73 | 74 | div.menu-item { 75 | padding-left: 0; 76 | text-indent: 0; 77 | padding-bottom: 2px; 78 | } 79 | 80 | #layout-menu a:link, #layout-menu a:visited, #layout-menu a:hover { 81 | color: black; 82 | border-bottom: 1px gray solid; 83 | } 84 | 85 | #layout-menu a.current:link, #layout-menu a.current:visited { 86 | border-bottom: none; 87 | } 88 | 89 | div#footer { 90 | border-top: 1px solid #e0e0e0; 91 | font-size: 80%; 92 | padding-bottom: 0; 93 | } 94 | 95 | div#footer a { 96 | color: #aaaaaa; 97 | border-bottom: 1px solid #cccccc; 98 | } 99 | 100 | #fwtitle div#toptitle { 101 | padding: 1.3em; 102 | } 103 | 104 | 105 | #layout-content { 106 | padding-top: 1.3em; 107 | padding-left: 30px; 108 | padding-right: 30px; 109 | } 110 | -------------------------------------------------------------------------------- /css/green.css: -------------------------------------------------------------------------------- 1 | #layout-menu { 2 | background: white; 3 | border: 1px solid #c0f0c0; 4 | } 5 | 6 | tt { 7 | color: #202020; 8 | } 9 | 10 | a, a > tt { 11 | color: #308050; 12 | } 13 | 14 | a:hover { 15 | border-bottom: 1px #30a030 dotted; 16 | } 17 | 18 | #layout-menu a.current:link, #layout-menu a.current:visited { 19 | color: #004010; 20 | border-bottom: 1px #c0f0c0 solid; 21 | } 22 | #layout-menu a:link, #layout-menu a:visited, #layout-menu a:hover { 23 | color: #009000; 24 | } 25 | 26 | h1, h2, h3, h4, h5, h6 { 27 | color: #202020; 28 | } 29 | 30 | div.blocktitle { 31 | color: #402020; 32 | } 33 | -------------------------------------------------------------------------------- /css/jacob.css: -------------------------------------------------------------------------------- 1 | /* Extra css file for personal jemdoc customizations. */ 2 | /* Copyright (C) Jacob Mattingley 2007. */ 3 | 4 | a, a > tt { 5 | color: #305080; 6 | } 7 | a:hover { 8 | border-bottom: 1px #305080 dotted; 9 | } 10 | 11 | div#toptitle { 12 | margin-bottom: 1.3em; 13 | border-bottom: 1px solid #c0c0c0; 14 | } 15 | 16 | h1, h2, h3, #layout-menu a.current:link, #layout-menu a.current:visited { 17 | color: #203060; 18 | } 19 | 20 | h1, h2, h3 { 21 | border-bottom: 1px solid #c0c0c0; 22 | } 23 | 24 | div#footer-text { 25 | padding-bottom: 0; 26 | } 27 | 28 | div.blocktitle { 29 | color: #203070; 30 | } 31 | 32 | div.blockcontent { 33 | border: 1px solid #c0c0c0; 34 | } 35 | 36 | div#footer-text { 37 | padding-bottom: 8px; 38 | } 39 | -------------------------------------------------------------------------------- /css/jemdoc.css: -------------------------------------------------------------------------------- 1 | /* Default css file for jemdoc. */ 2 | 3 | table#tlayout { 4 | border: none; 5 | border-collapse: separate; 6 | background: white; 7 | } 8 | 9 | body { 10 | background: white; 11 | font-family: Georgia, serif; 12 | padding-bottom: 8px; 13 | margin: 0; 14 | } 15 | 16 | #layout-menu { 17 | background: #f6f6f6; 18 | border: 1px solid #dddddd; 19 | padding-top: 0.5em; 20 | padding-left: 8px; 21 | padding-right: 8px; 22 | font-size: 1.0em; 23 | width: auto; 24 | white-space: nowrap; 25 | text-align: left; 26 | vertical-align: top; 27 | } 28 | 29 | #layout-menu td { 30 | background: #f4f4f4; 31 | vertical-align: top; 32 | } 33 | 34 | #layout-content { 35 | padding-top: 0.0em; 36 | padding-left: 1.0em; 37 | padding-right: 1.0em; 38 | border: none; 39 | background: white; 40 | text-align: left; 41 | vertical-align: top; 42 | } 43 | 44 | #layout-menu a { 45 | line-height: 1.5em; 46 | margin-left: 0.5em; 47 | } 48 | 49 | tt { 50 | background: #ffffdd; 51 | } 52 | 53 | pre, tt { 54 | font-size: 90%; 55 | font-family: monaco, monospace; 56 | } 57 | 58 | a, a > tt { 59 | color: #224b8d; 60 | text-decoration: none; 61 | } 62 | 63 | a:hover { 64 | border-bottom: 1px gray dotted; 65 | } 66 | 67 | #layout-menu a.current:link, #layout-menu a.current:visited { 68 | color: #022b6d; 69 | border-bottom: 1px gray solid; 70 | } 71 | #layout-menu a:link, #layout-menu a:visited, #layout-menu a:hover { 72 | color: #527bbd; 73 | text-decoration: none; 74 | } 75 | #layout-menu a:hover { 76 | text-decoration: none; 77 | } 78 | 79 | div.menu-category { 80 | border-bottom: 1px solid gray; 81 | margin-top: 0.8em; 82 | padding-top: 0.2em; 83 | padding-bottom: 0.1em; 84 | font-weight: bold; 85 | } 86 | 87 | div.menu-item { 88 | padding-left: 16px; 89 | text-indent: -16px; 90 | } 91 | 92 | div#toptitle { 93 | padding-bottom: 0.2em; 94 | margin-bottom: 1.5em; 95 | border-bottom: 3px double gray; 96 | } 97 | 98 | /* Reduce space if we begin the page with a title. */ 99 | div#toptitle + h2, div#toptitle + h3 { 100 | margin-top: -0.7em; 101 | } 102 | 103 | div#subtitle { 104 | margin-top: 0.0em; 105 | margin-bottom: 0.0em; 106 | padding-top: 0em; 107 | padding-bottom: 0.1em; 108 | } 109 | 110 | em { 111 | font-style: italic; 112 | } 113 | 114 | strong { 115 | font-weight: bold; 116 | } 117 | 118 | 119 | h1, h2, h3 { 120 | color: #527bbd; 121 | margin-top: 0.7em; 122 | margin-bottom: 0.3em; 123 | padding-bottom: 0.2em; 124 | line-height: 1.0; 125 | padding-top: 0.5em; 126 | border-bottom: 1px solid #aaaaaa; 127 | } 128 | 129 | h1 { 130 | font-size: 165%; 131 | } 132 | 133 | h2 { 134 | padding-top: 0.8em; 135 | font-size: 125%; 136 | } 137 | 138 | h2 + h3 { 139 | padding-top: 0.2em; 140 | } 141 | 142 | h3 { 143 | font-size: 110%; 144 | border-bottom: none; 145 | } 146 | 147 | p { 148 | margin-top: 0.0em; 149 | margin-bottom: 0.8em; 150 | padding: 0; 151 | line-height: 1.3; 152 | } 153 | 154 | pre { 155 | padding: 0; 156 | margin: 0; 157 | } 158 | 159 | div#footer { 160 | font-size: small; 161 | border-top: 1px solid #c0c0c0; 162 | padding-top: 0.1em; 163 | margin-top: 4.0em; 164 | color: #c0c0c0; 165 | } 166 | 167 | div#footer a { 168 | color: #80a0b0; 169 | } 170 | 171 | div#footer-text { 172 | float: left; 173 | padding-bottom: 8px; 174 | } 175 | 176 | ul, ol, dl { 177 | margin-top: 0.2em; 178 | padding-top: 0; 179 | margin-bottom: 0.8em; 180 | } 181 | 182 | dt { 183 | margin-top: 0.5em; 184 | margin-bottom: 0; 185 | } 186 | 187 | dl { 188 | margin-left: 20px; 189 | } 190 | 191 | dd { 192 | color: #222222; 193 | } 194 | 195 | dd > *:first-child { 196 | margin-top: 0; 197 | } 198 | 199 | ul { 200 | list-style-position: outside; 201 | list-style-type: square; 202 | } 203 | 204 | p + ul, p + ol { 205 | margin-top: -0.5em; 206 | } 207 | 208 | li ul, li ol { 209 | margin-top: -0.3em; 210 | } 211 | 212 | ol { 213 | list-style-position: outside; 214 | list-style-type: decimal; 215 | } 216 | 217 | li p, dd p { 218 | margin-bottom: 0.3em; 219 | } 220 | 221 | 222 | ol ol { 223 | list-style-type: lower-alpha; 224 | } 225 | 226 | ol ol ol { 227 | list-style-type: lower-roman; 228 | } 229 | 230 | p + div.codeblock { 231 | margin-top: -0.6em; 232 | } 233 | 234 | div.codeblock, div.infoblock { 235 | margin-right: 0%; 236 | margin-top: 1.2em; 237 | margin-bottom: 1.3em; 238 | } 239 | 240 | div.blocktitle { 241 | font-weight: bold; 242 | color: #cd7b62; 243 | margin-top: 1.2em; 244 | margin-bottom: 0.1em; 245 | } 246 | 247 | div.blockcontent { 248 | border: 1px solid silver; 249 | padding: 0.3em 0.5em; 250 | } 251 | 252 | div.infoblock > div.blockcontent { 253 | background: #ffffee; 254 | } 255 | 256 | div.blockcontent p + ul, div.blockcontent p + ol { 257 | margin-top: 0.4em; 258 | } 259 | 260 | div.infoblock p { 261 | margin-bottom: 0em; 262 | } 263 | 264 | div.infoblock li p, div.infoblock dd p { 265 | margin-bottom: 0.5em; 266 | } 267 | 268 | div.infoblock p + p { 269 | margin-top: 0.8em; 270 | } 271 | 272 | div.codeblock > div.blockcontent { 273 | background: #f6f6f6; 274 | } 275 | 276 | span.pycommand { 277 | color: #000070; 278 | } 279 | 280 | span.statement { 281 | color: #008800; 282 | } 283 | span.builtin { 284 | color: #000088; 285 | } 286 | span.special { 287 | color: #990000; 288 | } 289 | span.operator { 290 | color: #880000; 291 | } 292 | span.error { 293 | color: #aa0000; 294 | } 295 | span.comment, span.comment > *, span.string, span.string > * { 296 | color: #606060; 297 | } 298 | 299 | @media print { 300 | #layout-menu { display: none; } 301 | } 302 | 303 | #fwtitle { 304 | margin: 2px; 305 | } 306 | 307 | #fwtitle #toptitle { 308 | padding-left: 0.5em; 309 | margin-bottom: 0.5em; 310 | } 311 | 312 | #layout-content h1:first-child, #layout-content h2:first-child, #layout-content h3:first-child { 313 | margin-top: -0.7em; 314 | } 315 | 316 | div#toptitle h1, #layout-content div#toptitle h1 { 317 | margin-bottom: 0.0em; 318 | padding-bottom: 0.1em; 319 | padding-top: 0; 320 | margin-top: 0.5em; 321 | border-bottom: none; 322 | } 323 | 324 | img.eq { 325 | padding: 0; 326 | padding-left: 0.1em; 327 | padding-right: 0.1em; 328 | margin: 0; 329 | } 330 | 331 | img.eqwl { 332 | padding-left: 2em; 333 | padding-top: 0.6em; 334 | padding-bottom: 0.2em; 335 | margin: 0; 336 | } 337 | 338 | table { 339 | border: 2px solid black; 340 | border-collapse: collapse; 341 | } 342 | 343 | td { 344 | padding: 2px; 345 | padding-left: 0.5em; 346 | padding-right: 0.5em; 347 | text-align: center; 348 | border: 1px solid gray; 349 | } 350 | 351 | table + table { 352 | margin-top: 1em; 353 | } 354 | 355 | tr.heading { 356 | font-weight: bold; 357 | border-bottom: 2px solid black; 358 | } 359 | 360 | img { 361 | border: none; 362 | } 363 | 364 | table.imgtable, table.imgtable td { 365 | border: none; 366 | text-align: left; 367 | } 368 | -------------------------------------------------------------------------------- /css/nolines.css: -------------------------------------------------------------------------------- 1 | #layout-menu { 2 | border: none; 3 | border-right: 1px solid #c0c0c0; 4 | padding: 10px 20px 10px 20px; 5 | background: white; 6 | } 7 | 8 | #layout-menu a.current:link, #layout-menu a.current:visited { 9 | border-bottom: 1px gray solid; 10 | } 11 | 12 | div.menu-category { 13 | border-bottom: 0px solid gray; 14 | } 15 | 16 | div#toptitle { 17 | border-bottom: 1px solid #c0c0c0; 18 | } 19 | 20 | h1, h2, h3, h4, h5, h6 { 21 | border-bottom: 0px solid #c0c0c0; 22 | } 23 | 24 | div#footer { 25 | border-top: 1px solid #c0c0c0; 26 | } 27 | 28 | div.blockcontent { 29 | border: 1px solid #c0c0c0; 30 | } 31 | -------------------------------------------------------------------------------- /css/page.css: -------------------------------------------------------------------------------- 1 | #fwtitle { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | #fwtitle div#toptitle { 7 | background-color: #303050; 8 | padding: 1em; 9 | margin: 0; 10 | border: none; 11 | } 12 | 13 | div#toptitle h1 { 14 | margin-top: 0.1em; 15 | } 16 | 17 | #fwtitle div#toptitle h1, div#subtitle, div#subtitle a { 18 | color: white; 19 | font-weight: normal; 20 | text-align: left; 21 | } 22 | 23 | #layout-menu { 24 | border: none; 25 | border-right: 1px dashed #aaaaaa; 26 | margin: 0; 27 | padding-top: 0; 28 | } 29 | 30 | div.menu-category { 31 | border-bottom: none; 32 | padding-bottom: 0; 33 | } 34 | 35 | #layout-content { 36 | border: none; 37 | padding: 8px; 38 | padding-left: 16px; 39 | padding-right: 16px; 40 | padding-bottom: 0; 41 | margin: 0; 42 | } 43 | 44 | body { 45 | padding: 0; 46 | padding-bottom: 8px; 47 | } 48 | -------------------------------------------------------------------------------- /css/prob.css: -------------------------------------------------------------------------------- 1 | div.codeblock pre { 2 | font-size: 0.2em; 3 | } 4 | 5 | p b { 6 | font-style: normal; 7 | font-weight: bold; 8 | } 9 | 10 | td.c1 { 11 | text-align: right; 12 | } 13 | 14 | td.c2 { 15 | text-align: left; 16 | font-weight: bold; 17 | } 18 | 19 | table { 20 | border: 1px solid black; 21 | margin-top: 0.5em; 22 | margin-bottom: 1em; 23 | } 24 | 25 | p + table { 26 | margin-top: -0.3em; 27 | } 28 | 29 | a.imglink { 30 | border: none; 31 | } 32 | 33 | /* Exceedingly lame hack to eliminate borders with figure images. */ 34 | a.imglink > img { 35 | margin-left: -55px; 36 | } 37 | 38 | .red { 39 | color: red; 40 | } 41 | 42 | .green { 43 | color: green; 44 | } 45 | 46 | h1 { 47 | padding-top: 1em; 48 | } 49 | 50 | table#allprobs td { 51 | font-weight: normal; 52 | } 53 | 54 | table#allprobs td.c1, table#allprobs tr.r1 td, table#allprobs tr.r1 td.c1 { 55 | font-weight: bold; 56 | } 57 | -------------------------------------------------------------------------------- /css/table.css: -------------------------------------------------------------------------------- 1 | #countries tr.r1 { 2 | border-bottom: 2px solid black; 3 | font-weight: bold; 4 | } 5 | -------------------------------------------------------------------------------- /css/white.css: -------------------------------------------------------------------------------- 1 | body { 2 | font: 80% Verdana; 3 | margin-left: 2em; 4 | margin-top: 1em; 5 | } 6 | 7 | pre, tt { 8 | font-size: 110%; 9 | background: #ffffdd; 10 | } 11 | 12 | tt { 13 | color: #700000; 14 | } 15 | 16 | pre { 17 | color: black; 18 | } 19 | 20 | a { 21 | border-bottom: 1px solid #bbbbbb; 22 | color: black; 23 | } 24 | 25 | h1 { 26 | font-size: 150%; 27 | border: none; 28 | } 29 | 30 | h2 { 31 | font-size: 115%; 32 | border: none; 33 | } 34 | 35 | h3 { 36 | font-size: 100%; 37 | border: none; 38 | } 39 | 40 | h1, h2, h3, div.blocktitle { 41 | color: #990000; 42 | } 43 | 44 | div.blockcontent { 45 | border: none; 46 | } 47 | 48 | div.infoblock > div.blockcontent { 49 | background: #ffffdd; 50 | } 51 | 52 | div.codeblock > div.blockcontent, div.blockcontent pre { 53 | background: #f8f8f8; 54 | } 55 | 56 | body, p { 57 | line-height: 1.5em; 58 | margin-bottom: 1.2em; 59 | } 60 | 61 | #layout-menu { 62 | padding-left: 20px; 63 | padding-right: 20px; 64 | background: none; 65 | text-align: right; 66 | border: none; 67 | padding-top: 3.0em; 68 | } 69 | 70 | #layout-content { 71 | padding-left: 25px; 72 | padding-top: 1em; 73 | width: 600px; 74 | } 75 | 76 | b { 77 | font-weight: normal; 78 | } 79 | 80 | p b { 81 | font-style: italic; 82 | } 83 | 84 | div.menu-category { 85 | border: none; 86 | border-bottom: 1px solid 87 | margin-top: 1.0em; 88 | padding-bottom: 0; 89 | } 90 | 91 | div.menu-item { 92 | padding-left: 0; 93 | text-indent: 0; 94 | padding-bottom: 2px; 95 | } 96 | 97 | #layout-menu a:link, #layout-menu a:visited, #layout-menu a:hover { 98 | color: black; 99 | border-bottom: 1px gray solid; 100 | } 101 | 102 | #layout-menu a.current:link, #layout-menu a.current:visited { 103 | color: #900000; 104 | border-bottom: 1px gray solid; 105 | } 106 | 107 | div#footer { 108 | border-top: 1px solid #e0e0e0; 109 | font-size: 80%; 110 | padding-bottom: none; 111 | } 112 | 113 | div#footer a { 114 | color: #bbbbbb; 115 | border-bottom: 1px solid #cccccc; 116 | } 117 | 118 | 119 | div#toptitle { 120 | border: none; 121 | } 122 | -------------------------------------------------------------------------------- /latexmath2png.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.5 2 | #from __future__ import with_statement # Until Python 2.6 3 | """ 4 | Converts LaTeX math to png images. 5 | Run latexmath2png.py --help for usage instructions. 6 | """ 7 | 8 | """ 9 | Author: 10 | Kamil Kisiel 11 | URL: http://www.kamilkisiel.net 12 | 13 | Revision History: 14 | 2007/04/20 - Initial version 15 | 16 | TODO: 17 | - Make handling of bad input more graceful? 18 | --- 19 | 20 | Some ideas borrowed from Kjell Fauske's article at http://fauskes.net/nb/htmleqII/ 21 | 22 | Licensed under the MIT License: 23 | 24 | Copyright (c) 2007 Kamil Kisiel 25 | 26 | Permission is hereby granted, free of charge, to any person obtaining a copy 27 | of this software and associated documentation files (the "Software"), to deal 28 | in the Software without restriction, including without limitation the rights 29 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 30 | copies of the Software, and to permit persons to whom the Software is 31 | furnished to do so, subject to the following conditions: 32 | 33 | The above copyright notice and this permission notice shall be included in 34 | all copies or substantial portions of the Software. 35 | 36 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 37 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 38 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 39 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 40 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 41 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 42 | IN THE SOFTWARE. 43 | """ 44 | 45 | import os 46 | import sys 47 | import tempfile 48 | import getopt 49 | from StringIO import StringIO 50 | from subprocess import * 51 | 52 | # Default packages to use when generating output 53 | default_packages = [ 54 | #'amsmath', 55 | #'amsthm', 56 | #'amssymb', 57 | ] 58 | 59 | def __build_preamble(packages): 60 | preamble = '\documentclass{article}\n' 61 | for p in packages: 62 | preamble += "\usepackage{%s}\n" % p 63 | #preamble += "\usepackage[active]{preview}\n" 64 | preamble += "\pagestyle{empty}\n\\begin{document}\n" 65 | return preamble 66 | 67 | def __write_output(infile, outdir, workdir = '.', prefix = '', dpi = 100): 68 | try: 69 | # Generate the DVI file 70 | latexcmd = 'latex -file-line-error-style -interaction=nonstopmode -output-directory %s %s'\ 71 | % (workdir, infile) 72 | p = Popen(latexcmd, shell=True, stdout=PIPE) 73 | rc = p.wait() 74 | 75 | # Something bad happened, abort 76 | if rc != 0: 77 | print p.stdout.read() 78 | raise Exception('latex error') 79 | 80 | 81 | # Convert the DVI file to PNG's 82 | dvifile = infile.replace('.tex', '.dvi') 83 | outprefix = os.path.join(outdir, prefix) 84 | dvicmd = "dvipng --freetype0 -Q 8 --depth -q -T tight -D %i -z 3 -bg Transparent "\ 85 | "-o %s.png %s" % (dpi, outprefix, dvifile) 86 | p = Popen(dvicmd, shell=True, stdout=PIPE) 87 | rc = p.wait() 88 | if rc != 0: 89 | raise Exception('dvipng error') 90 | depth = int(p.stdout.readlines()[-1].split('=')[-1]) 91 | finally: 92 | # Cleanup temporaries 93 | basefile = infile.replace('.tex', '') 94 | tempext = [ '.aux', '.dvi', '.log' ] 95 | for te in tempext: 96 | t = basefile + te 97 | if os.path.exists(t): 98 | os.remove(t) 99 | 100 | return depth 101 | 102 | def math2png(eq, outdir, packages = default_packages, prefix = '', dpi = 100): 103 | #try: 104 | 105 | # Set the working directory 106 | workdir = tempfile.gettempdir() 107 | 108 | # Get a temporary file 109 | fd, texfile = tempfile.mkstemp('.tex', '', workdir, True) 110 | 111 | # Create the TeX document 112 | #with os.fdopen(fd, 'w+') as f: 113 | f = os.fdopen(fd, 'w') 114 | f.write(__build_preamble(packages)) 115 | f.write("$%s$\n" % eq) 116 | f.write('\end{document}') 117 | f.close() 118 | 119 | depth = __write_output(texfile, outdir, workdir, prefix, dpi) 120 | 121 | #finally: 122 | # pass 123 | # #if os.path.exists(texfile): 124 | # # os.remove(texfile) 125 | 126 | return depth 127 | 128 | def math2pngwl(eq, outdir, packages = default_packages, prefix = '', dpi = 100): 129 | #try: 130 | 131 | # Set the working directory 132 | workdir = tempfile.gettempdir() 133 | 134 | # Get a temporary file 135 | fd, texfile = tempfile.mkstemp('.tex', '', workdir, True) 136 | 137 | # Create the TeX document 138 | #with os.fdopen(fd, 'w+') as f: 139 | f = os.fdopen(fd, 'w') 140 | f.write(__build_preamble(packages)) 141 | f.write("\\[%s\\]\n\\newpage\n" % eq) 142 | f.write('\end{document}') 143 | f.close() 144 | 145 | depth = __write_output(texfile, outdir, workdir, prefix, dpi) 146 | 147 | #finally: 148 | # pass 149 | # #if os.path.exists(texfile): 150 | # # os.remove(texfile) 151 | 152 | return depth 153 | -------------------------------------------------------------------------------- /notes: -------------------------------------------------------------------------------- 1 | normalize spacing (or rely on tidy?). 2 | 3 | learn proper difference between span and div. 4 | --> div includes paragraph breaks as well. 5 | 6 | # marks in highlighting are *not* comments for jemdoc, they're comments for the highlighting. 7 | --> enable comments in code blocks, somehow? 8 | 9 | syntax highlighting runs out on +this is 10 | 11 | fix wrapping when lines start with .s. fix wrapping with \n at the end of the 12 | line. 13 | 14 | allow different orders of stuff. 15 | 16 | custom numbers in lists. 17 | 18 | single tilde should not provoke block mode 19 | 20 | add proper wrapping in vim file for lists etc. don't push \n onto previous 21 | line, if possible. 22 | 23 | do word wrap (properly). 24 | 25 | paragraph with {{}} should have no

. 26 | --> no. use raw block instead. 27 | 28 | investigate proper string continuation in python. 29 | 30 | proper vim handling of python \. 31 | 32 | remove argument for menu name and figure it out implicitly instead? (no) 33 | 34 | what happens if you nest blocks? 35 | --> doesn't work. should it? 36 | 37 | --show-config with -c. 38 | 39 | half the functions should hang off the controlstruct class. 40 | 41 | errors for unrecognised jemdoc options? 42 | 43 | fix h1 not starting at the top. 44 | 45 | hide latex output if no errors. otherwise package latex output, and perhaps indent? 46 | 47 | be able to set default directory for output equations. will create eqs/ directory by default. 48 | 49 | add testing of dvipng and latex to jemdoc --version call. 50 | --> done. 51 | 52 | noclean option for not removing tex file. 53 | call tex files after equation name, as well! 54 | nocaching option? 55 | clean option! 56 | 57 | strip tags from title. 58 | 59 | mention punctuation + latex equations wrapping. 60 | 61 | caching, i.e. .jemdoceqoffsets, or filename_offset. 62 | need tables as well (e.g. atoms page) 63 | 64 | definitions files for latex. 65 | 66 | possibly add package stuff etc to equation hashing. 67 | 68 | add hair space around em dashes? ( ) 69 | --> done, for better or for worse. 70 | 71 | errors should say what file was being processed? 72 | 73 | easy way to add latex packages. 74 | 75 | allow || on last line of tables. 76 | -------------------------------------------------------------------------------- /www/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | html 3 | eqs 4 | -------------------------------------------------------------------------------- /www/MENU: -------------------------------------------------------------------------------- 1 | jemdoc 2 | home [index.html] 3 | download [download.html] 4 | version/bug info [revision.html] 5 | contact [contact.html] 6 | 7 | user's guide 8 | running jemdoc [using.html] 9 | example page [example.html] 10 | cheat sheet [cheatsheet.html] 11 | extra syntax [extra.html] 12 | 13 | configuration 14 | html changes [htmlchanges.html] 15 | adding a menu [menu.html] 16 | modelines [modelines.html] 17 | 18 | goodies 19 | vim, make [stuff.html] 20 | latex equations [latex.html] 21 | tables [tables.html] 22 | 23 | 24 | # vim: et 25 | -------------------------------------------------------------------------------- /www/Makefile: -------------------------------------------------------------------------------- 1 | DOCS=index cheatsheet contact download revision using menu stuff extra example modelines htmlchanges latex tables 2 | 3 | HDOCS=$(addsuffix .html, $(DOCS)) 4 | PHDOCS=$(addprefix html/, $(HDOCS)) 5 | 6 | .PHONY : update 7 | update : $(PHDOCS) 8 | @echo -n 'Copying to (hidden) server...' 9 | @rsync -a --delete --copy-unsafe-links *.jemdoc html/* dist eqs ~/jemdoc/stage/ 10 | @echo ' done.' 11 | 12 | .PHONY : extra 13 | extra : 14 | cp ~/.vim/syntax/jemdoc.vim dist/ 15 | 16 | .PHONY : docs 17 | docs : $(PHDOCS) 18 | 19 | html/%.html : %.jemdoc MENU jemdoc.conf 20 | ~/jemdoc/jemdoc -o $@ -c jemdoc.conf $< 21 | 22 | example.jemdoc : exampleIN.jemdoc procexample.py 23 | @echo 'making exampleIN' 24 | @./procexample.py 25 | 26 | .PHONY : realupdate 27 | realupdate : $(PHDOCS) 28 | @echo -n 'Copying to (hidden) server...' 29 | @rsync -a --delete --copy-unsafe-links *.jemdoc html/* dist ~/jemdoc/stage/ 30 | @echo ' done.' 31 | @echo 'Copying to moa...' 32 | rsync -a --delete --copy-unsafe-links *.jemdoc ~/jemdoc/stage/ moa:/var/www/jemdoc/ 33 | @echo ' done.' 34 | 35 | .PHONY : clean 36 | clean : 37 | -rm -f html/*.html 38 | -------------------------------------------------------------------------------- /www/cheatsheet.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{cheatsheet.html} 2 | = jemdoc -- cheatsheet 3 | 4 | == Basic formatting 5 | - /\/italics\// 6 | - *\*bold\** 7 | - +\+monospace\++ 8 | - +\-+ is a hyphen (-) 9 | - +\-\-+ is an en-dash (--) 10 | - +\-\-\-+ is an em-dash (---) 11 | - +\.\.\.+ is an ellipsis (...) 12 | - +\~+ is a non-breaking space (~) 13 | - +\#+ begins a comment, for the remainder of the line 14 | - +\\C+ is \C 15 | - +\\R+ is \R 16 | - +\\M+ is \M 17 | - `singly quoted text' is written +\`singly quoted text\'+ 18 | - "doubly quoted text" is written +\"doubly quoted text\"+ 19 | - jemdoc's apostrophes are converted automatically from +jemdoc\'s+ input 20 | - the sequence +\\n+ \n forces a manual line break 21 | - paragraphs are separated by blank lines 22 | - +\$inline LaTeX equation\$+ 23 | - +\\( LaTeX equation on its own line \\)+ 24 | - +\#+s (and only +\#+s) must be quoted in URLs 25 | 26 | == Blocks 27 | ~~~ 28 | {Code block syntax}{} 29 | \~~~ 30 | \{Optionally empty title}{Optionally empty highlight mode} 31 | Code block with monospaced text. 32 | \~~~ 33 | ~~~ 34 | 35 | ~~~ 36 | {Information block} 37 | Omit the second pair of braces in the first line of the block (or omit the whole 38 | first line altogether if you don't want a title) and you will get an 39 | /information block/. All the usual conventions apply in here. 40 | ~~~ 41 | 42 | == Headings and lists 43 | Headings are defined by starting a line with +=+. 44 | - += Heading level 1+ 45 | - +== Heading level 2+, /etc./ 46 | 47 | Lists are defined with +-+ for bulleted lists, +.+ for numbered lists and +:+ 48 | for lists of definitions. Here is some code and the resulting list: 49 | 50 | ~~~ 51 | {}{} 52 | - Bullet level one 53 | -- Bullet level two 54 | 55 | . Number level one 56 | .. Number level two 57 | .. Number level two (again) 58 | 59 | : {jemdoc} light markup 60 | : {asciidoc} a great alternative, but more complicated 61 | ~~~ 62 | 63 | ~~~ 64 | - Bullet level one 65 | -- Bullet level two 66 | 67 | . Number level one 68 | .. Number level two 69 | .. Number level two (again) 70 | 71 | : {jemdoc} light markup 72 | : {asciidoc} a great alternative, but more complicated 73 | ~~~ 74 | 75 | == Preventing matches 76 | - a literal backslash (\\) is written +{{\\\\}}+ 77 | - the literal characters \/, \*, \+ and \~ and \# are written +\\/+, +\\*+, 78 | +\\\++, +\\\~+ and +\\\#+ to avoid the above formatting 79 | - +\\\...+ avoids an ellipsis 80 | - +-\\-+ avoids an en-dash 81 | - +-\\-\\-+ avoids an em-dash 82 | - +\\\`+ gives a back-tick (\`) 83 | - +\\\'+ gives an ordinary single quotation mark (\') 84 | - +\\\"+ gives an ordinary double quotation mark (\") 85 | 86 | == Other stuff 87 | - +\{\{html text\}\}+ will insert +html text+ directly into the output document 88 | without performing any substitutions. (This is for inline escaping; use 89 | [extra.html raw blocks] for larger amounts of html.) 90 | - +\%quoted tt\%+ is an alias for +\+{\{quoted tt\}\}\++. It's not quite as 91 | robust, so use +\+{\{plus signs with double brace blocks}\}\++ if you run into 92 | problems with some characters. 93 | - +{\\{text}\\}+ /will/ perform replacements and insert {\{text}\}. 94 | 95 | This page is not exhaustive. 96 | -------------------------------------------------------------------------------- /www/contact.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{contact.html} 2 | = jemdoc -- contact details 3 | 4 | == Development 5 | jemdoc is developed by [http://stanford.edu/~jacobm/ Jacob Mattingley]. 6 | Please [jacobm@stanford.edu contact Jacob] with any bug reports and 7 | comments. 8 | If reporting a bug, please run the command +jemdoc -\-version+ and include the 9 | result in your email. 10 | 11 | There are two levels of support: 12 | - Basic jemdoc, which I will attempt to support well, and 13 | - LaTeX equations in jemdoc, which I may attempt to support. 14 | -------------------------------------------------------------------------------- /www/dist/Makefile: -------------------------------------------------------------------------------- 1 | DOCS=index otherpage 2 | 3 | HDOCS=$(addsuffix .html, $(DOCS)) 4 | PHDOCS=$(addprefix html/, $(HDOCS)) 5 | 6 | .PHONY : docs 7 | docs : $(PHDOCS) 8 | 9 | .PHONY : update 10 | update : $(PHDOCS) 11 | @echo -n 'Copying to server...' 12 | # insert code for copying to server here. 13 | @echo ' done.' 14 | 15 | html/%.html : %.jemdoc MENU 16 | jemdoc -o $@ $< 17 | 18 | .PHONY : clean 19 | clean : 20 | -rm -f html/*.html 21 | -------------------------------------------------------------------------------- /www/dist/jemdoc.css: -------------------------------------------------------------------------------- 1 | /Users/jem/jemdoc/css/jemdoc.css -------------------------------------------------------------------------------- /www/dist/jemdoc.py: -------------------------------------------------------------------------------- 1 | jemdoc.py-0.7.3 -------------------------------------------------------------------------------- /www/dist/jemdoc.py-0.2.0: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | jemdoc: light markup. 5 | 6 | version 0.2.0, October 2007. 7 | """ 8 | 9 | # Copyright (C) 2007 Jacob Mattingley. 10 | # 11 | # This file is part of jemdoc. 12 | # 13 | # jemdoc is free software; you can redistribute it and/or modify it under the 14 | # terms of the GNU General Public License as published by the Free Software 15 | # Foundation; either version 3 of the License, or (at your option) any later 16 | # version. 17 | # 18 | # jemdoc is distributed in the hope that it will be useful, but WITHOUT ANY 19 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 20 | # A PARTICULAR PURPOSE. See the GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License along with 23 | # this program. If not, see . 24 | 25 | import sys 26 | import re 27 | import time 28 | import StringIO 29 | 30 | # better checking of arguments? 31 | def showhelp(): 32 | print """Usage: jemdoc [OPTIONS] [SOURCEFILE] 33 | Produces html markup from a jemdoc SOURCEFILE. 34 | 35 | Most of the time you can use jemdoc without any additional flags. 36 | For example, typing 37 | 38 | jemdoc index.jemdoc 39 | 40 | will produce an index.html, using a default configuration. You can 41 | change the output file by using -o OUTFILE, for example 42 | 43 | jemdoc -o html/main.html index.jemdoc 44 | 45 | Some configuration options can be overridden by specifying a 46 | configuration file. You can use 47 | 48 | jemdoc --show-config 49 | 50 | to print a sample configuration file (which includes all of the 51 | default options). Any or all of the configuration [blocks] can be 52 | overwritten by including them in a configuration file, and running, 53 | for example, 54 | 55 | jemdoc -c mywebsite.conf index.jemdoc 56 | 57 | See http://jemdoc.jaboc.net/ for more details. 58 | """ 59 | 60 | def standardconf(): 61 | return """[firstbit] 62 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | [windowtitle] 71 | # used in header for window title. 72 | | 73 | 74 | [doctitle] 75 | # used at top of document. 76 |
77 |

|

78 | 79 | [subtitle] 80 |
|
81 | 82 | [doctitleend] 83 |
84 | 85 | [bodystart] 86 | 87 | 88 | 89 | [menustart] 90 | 91 | 92 | 96 | 114 | 115 |
93 | 94 | [menuend] 95 | 97 |
98 | 99 | [menucategory] 100 | 101 | 102 | [menuitem] 103 | 104 | 105 | [currentmenuitem] 106 | 107 | 108 | [nomenu] 109 |
110 | 111 | [menulastbit] 112 |
113 |
116 | 117 | [nomenulastbit] 118 | 119 | 120 | [bodyend] 121 | 122 | 123 | 124 | [infoblock] 125 |
126 | 127 | [codeblock] 128 |
129 | 130 | [blocktitle] 131 |
|
132 | 133 | [infoblockcontent] 134 |
135 | 136 | [codeblockcontent] 137 |
138 | 
139 | [codeblockend]
140 | 
141 | 142 | [infoblockend] 143 |
144 | 145 | [footerstart] 146 | 152 | 153 | [lastupdated] 154 | Last updated |, using jemdoc. 155 | """ 156 | 157 | class JandalError(Exception): 158 | pass 159 | 160 | def raisejandal(msg, line=0): 161 | if line == 0: 162 | s = "%s" % msg 163 | else: 164 | s = "line %d: %s" % (line, msg) 165 | raise JandalError(s) 166 | 167 | if len(sys.argv) == 1 or sys.argv[1] in ('--help', '-h'): 168 | showhelp() 169 | raise SystemExit 170 | elif len(sys.argv[2:]) % 2 != 0: 171 | raise JandalError('invalid arguments, try --help') 172 | if sys.argv[1] == '--show-config': 173 | print standardconf() 174 | raise SystemExit 175 | else: 176 | inname = sys.argv[-1] 177 | outname = re.search(r'(.*)\.', inname).group(1) + '.html' 178 | 179 | outoverride = False 180 | confoverride = False 181 | confnames = [] 182 | for i in range(1, len(sys.argv) - 1, 2): 183 | if sys.argv[i] == '-o': 184 | if outoverride: 185 | raise RuntimeError("only one output file, please") 186 | outname = sys.argv[i+1] 187 | outoverride = True 188 | elif sys.argv[i] == '-c': 189 | if confoverride: 190 | raise RuntimeError("only one config file, please") 191 | confnames.append(sys.argv[i+1]) 192 | confoverride = True 193 | else: 194 | raise RuntimeError('unrecognised argument %s, try --help' % sys.argv[i]) 195 | 196 | def readnoncomment(f): 197 | l = f.readline() 198 | if l == '': 199 | return l 200 | elif l[0] == '#': # jem: be a little more generous with the comments we accept? 201 | return readnoncomment(f) 202 | else: 203 | return l.rstrip() + '\n' # leave just one \n and no spaces etc. 204 | 205 | def parseconf(cns): 206 | syntax = {} 207 | warn = False # jem. make configurable? 208 | # manually add the defaults as a file handle. 209 | fs = [StringIO.StringIO(standardconf())] 210 | for sname in cns: 211 | fs.append(open(sname)) 212 | 213 | for f in fs: 214 | while pc(f) != '': 215 | l = readnoncomment(f) 216 | r = re.match(r'\[(.*)\]\n', l) 217 | 218 | if r: 219 | tag = r.group(1) 220 | 221 | s = '' 222 | l = readnoncomment(f) 223 | while l not in ('\n', ''): 224 | s += l 225 | l = readnoncomment(f) 226 | 227 | syntax[tag] = s 228 | 229 | f.close() 230 | 231 | return syntax 232 | 233 | def insertmenuitems(mname, current): 234 | f = open(mname) 235 | while pc(f) != '': 236 | l = readnoncomment(f) 237 | l = l.strip() 238 | if l == '': 239 | continue 240 | 241 | r = re.match(r'\s*(.*?)\s*\[(.*)\]', l) 242 | 243 | if r: # then we have a link. 244 | if r.group(2) == current: 245 | hb(conf['currentmenuitem'], r.group(2), br(r.group(1))) 246 | else: 247 | hb(conf['menuitem'], r.group(2), br(r.group(1))) 248 | 249 | else: # menu category. 250 | hb(conf['menucategory'], br(l)) 251 | 252 | f.close() 253 | 254 | 255 | infile = open(inname) 256 | outfile = open(outname, 'w') 257 | 258 | def out(s): 259 | outfile.write(s) 260 | 261 | def hb(tag, content1, content2=None): 262 | """Writes out a halfblock (hb).""" 263 | if content2 is None: 264 | out(re.sub(r'\|', content1, tag)) 265 | else: 266 | r = re.sub(r'\|1', content1, tag) 267 | r = re.sub(r'\|2', content2, r) 268 | out(r) 269 | 270 | def pc(f = infile): 271 | """Peeks at next character in the file.""" 272 | # Should only be used to look at the first character of a new line. 273 | c = f.read(1) 274 | if c: # only undo forward movement if we're not at the end. 275 | #if c == '#': # interpret comment lines as blank. 276 | # return '\n' 277 | 278 | if c in ' \t': 279 | return pc() 280 | 281 | f.seek(-1, 1) 282 | 283 | return c 284 | 285 | def nl(withcount=False, codemode=False): 286 | global linenum 287 | """Get input file line.""" 288 | s = infile.readline() 289 | linenum += 1 290 | if not codemode: 291 | # remove any special characters - assume they were checked by pc() before 292 | # we got here. 293 | # remove any trailing comments. 294 | s = s.lstrip(' \t') 295 | s = re.sub(r'\s*(?$\.~[\]-]""", r'\\\g<0>', s) 341 | else: 342 | return re.sub(r"""[\\*/+"'<>\.~[\]-]""", r'\\\g<0>', s) 343 | 344 | def replacequoted(b): 345 | """Quotes {{raw html}} sections. Insert a backslash right before the end 346 | with &bs;, an illegal html character.""" 347 | r = re.compile(r'\{\{(.*?)\}\}', re.M + re.S) 348 | m = r.search(b) 349 | while m: 350 | qb = quote(m.group(1), True) 351 | 352 | b = b[:m.start()] + qb + b[m.end():] 353 | 354 | m = r.search(b, m.start()) 355 | 356 | # likewise replace $sections$ as +{{sections}}+. 357 | r = re.compile(r'(?%s<\/a>' % (link, linkname) + b[m.end():] 389 | 390 | m = r.search(b, m.start()) 391 | 392 | return b 393 | 394 | def br(b): 395 | """Does simple text replacements on a block of text. ('block replacements')""" 396 | # Deal with literal backspaces. 397 | b = re.sub(r'\\\\', '&jemLITerl33talBS;', b) 398 | 399 | # Deal with {{html embedding}}. 400 | b = replacequoted(b) 401 | 402 | b = allreplace(b) 403 | 404 | # First do the URL thing. 405 | b = b.lstrip('-. \t') # remove leading spaces, tabs, dashes, dots. 406 | b = replacelinks(b) 407 | 408 | # Deal with /italics/ first because the '/' in other tags would otherwise 409 | # interfere. 410 | r = re.compile(r'(?\1', b) 412 | 413 | # Deal with *bold*. 414 | r = re.compile(r'(?\1', b) 416 | 417 | # Deal with +monospace+. 418 | r = re.compile(r'(?\1', b) 420 | 421 | # Deal with "double quotes". 422 | r = re.compile(r'(?', b) 460 | 461 | # Second to last, remove any remaining quoting backslashes. 462 | b = re.sub(r'\\(?!\\)', '', b) 463 | 464 | # Deal with literal backspaces. 465 | b = re.sub('&jemLITerl33talBS;', r'\\', b) 466 | 467 | return b 468 | 469 | def allreplace(b): 470 | """Replacements that should be done on everything.""" 471 | r = re.compile(r"(?", re.M + re.S) 472 | b = re.sub(r, r'>', b) 473 | 474 | r = re.compile(r"(?>>'): 482 | hb('|\n', allreplace(l)) 483 | elif l.startswith('#'): # jem upgrade this to handle not at the beginning. 484 | hb('|\n', allreplace(l)) 485 | else: 486 | out(allreplace(l) + '\n') 487 | 488 | def py(l): 489 | # jem need to do much better here. 490 | l = l.rstrip() 491 | if l.startswith('>>>'): 492 | hb('|\n', allreplace(l)) 493 | elif l.startswith('#'): 494 | hb('|\n', allreplace(l)) 495 | else: 496 | out(allreplace(l) + '\n') 497 | 498 | def dashlist(): 499 | level = 0 500 | 501 | while pc() == '-': 502 | (s, newlevel) = np(True) 503 | 504 | # first adjust list number as appropriate. 505 | if newlevel > level: 506 | for i in range(newlevel - level): 507 | if newlevel > 1: 508 | out('\n') 509 | out('
    \n
  • ') 510 | elif newlevel < level: 511 | for i in range(level - newlevel): 512 | out('
  • \n
\n
  • ') 513 | else: 514 | out('
  • \n
  • ') 515 | 516 | out(br(s)) 517 | level = newlevel 518 | 519 | for i in range(level): 520 | out('
  • \n\n') 521 | 522 | def dotlist(): 523 | level = 0 524 | 525 | while pc() == '.': 526 | (s, newlevel) = np(True) 527 | 528 | # first adjust list number as appropriate. 529 | if newlevel > level: 530 | for i in range(newlevel - level): 531 | if newlevel > 1: 532 | out('\n') 533 | out('
      \n
    1. ') 534 | elif newlevel < level: 535 | for i in range(level - newlevel): 536 | out('
    2. \n
    \n
  • ') 537 | else: 538 | out('
  • \n
  • ') 539 | 540 | out(br(s)) 541 | level = newlevel 542 | 543 | for i in range(level): 544 | out('
  • \n\n') 545 | 546 | def colonlist(): 547 | out('
    \n') 548 | while pc() == ':': 549 | s = np() 550 | r = re.compile(r'\s*{(.*?)(?|\n', br(defpart)) 561 | hb('
    |
    \n', br(rest)) 562 | 563 | out('
    \n') 564 | 565 | def codeblock(): 566 | out(conf['codeblock']) 567 | if len(g[0]): 568 | hb(conf['blocktitle'], g[0]) 569 | out(conf['codeblockcontent']) 570 | 571 | if g[1] not in ('', 'pyint', 'py'): 572 | raise SyntaxError( \ 573 | "couldn't handle the jandal: unrecognised syntax " 574 | "highlighting on line %d" % linenum) 575 | 576 | # Now we are handling code. 577 | # Handle \~ and ~ differently. 578 | while 1: # wait for EOF. 579 | l = nl(codemode=True) 580 | if not l: 581 | break 582 | elif l.startswith('~'): 583 | break 584 | elif l.startswith('\\~'): 585 | l = l[1:] 586 | elif l.startswith('\\{'): 587 | l = l[1:] 588 | 589 | if g[1] == 'pyint': 590 | pyint(l) 591 | elif g[1] == 'py': 592 | py(l) 593 | else: 594 | out(allreplace(l)) 595 | 596 | out(conf['codeblockend']) 597 | 598 | # load the conf. 599 | conf = parseconf(confnames) 600 | 601 | # Get the file started with the firstbit. 602 | out(conf['firstbit']) 603 | 604 | linenum = 0 605 | 606 | menu = None 607 | footer = True 608 | if pc() == '#': 609 | l = infile.readline() 610 | linenum += 1 611 | if l.startswith('# jemdoc: '): 612 | l = l[len('# jemdoc: '):] 613 | a = l.split(',') 614 | # jem only handle one argument for now. 615 | for b in a: 616 | b = b.strip() 617 | if b.startswith('menu'): 618 | sidemenu = True 619 | r = re.compile(r'(?|\n' % (c, c), br(s)) 678 | 679 | # look for comments. 680 | elif p == '#': 681 | nl() 682 | 683 | elif p == '\n': 684 | nl() 685 | 686 | # look for blocks. 687 | elif p == '~': 688 | nl() 689 | if infoblock: 690 | out(conf['infoblockend']) 691 | infoblock = False 692 | nl() 693 | continue 694 | else: 695 | if pc() == '{': 696 | l = br(nl()) 697 | r = re.compile(r'(?|

    \n', s) 721 | 722 | if footer: 723 | s = time.strftime('%F %R:%S %Z', time.localtime(time.time())) 724 | out(conf['footerstart']) 725 | hb(conf['lastupdated'], s) 726 | out(conf['footerend']) 727 | 728 | if menu: 729 | out(conf['menulastbit']) 730 | else: 731 | out(conf['nomenulastbit']) 732 | 733 | out(conf['bodyend']) 734 | 735 | if outfile is not sys.stdout: 736 | outfile.close() 737 | -------------------------------------------------------------------------------- /www/dist/jemdoc.py-0.3.0: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | jemdoc: light markup. 5 | 6 | version 0.3.0, November 2007. 7 | """ 8 | 9 | # Copyright (C) 2007 Jacob Mattingley. 10 | # 11 | # This file is part of jemdoc. 12 | # 13 | # jemdoc is free software; you can redistribute it and/or modify it under the 14 | # terms of the GNU General Public License as published by the Free Software 15 | # Foundation; either version 3 of the License, or (at your option) any later 16 | # version. 17 | # 18 | # jemdoc is distributed in the hope that it will be useful, but WITHOUT ANY 19 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 20 | # A PARTICULAR PURPOSE. See the GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License along with 23 | # this program. If not, see . 24 | 25 | import sys 26 | import os 27 | import re 28 | import time 29 | import StringIO 30 | 31 | class controlstruct(object): 32 | def __init__(self, infile, outfile, conf): 33 | self.inf = infile 34 | self.outf = outfile 35 | self.conf = conf 36 | self.linenum = 0 37 | 38 | # better checking of arguments? 39 | def showhelp(): 40 | a = """Usage: jemdoc [OPTIONS] [SOURCEFILE] 41 | Produces html markup from a jemdoc SOURCEFILE. 42 | 43 | Most of the time you can use jemdoc without any additional flags. 44 | For example, typing 45 | 46 | jemdoc index.jemdoc 47 | 48 | will produce an index.html, using a default configuration. You can 49 | change the output file by using -o OUTFILE, for example 50 | 51 | jemdoc -o html/main.html index.jemdoc 52 | 53 | Some configuration options can be overridden by specifying a 54 | configuration file. You can use 55 | 56 | jemdoc --show-config 57 | 58 | to print a sample configuration file (which includes all of the 59 | default options). Any or all of the configuration [blocks] can be 60 | overwritten by including them in a configuration file, and running, 61 | for example, 62 | 63 | jemdoc -c mywebsite.f.conf index.jemdoc 64 | 65 | See http://jemdoc.jaboc.net/ for more details. 66 | """ 67 | b = '' 68 | for l in a.splitlines(True): 69 | if l.startswith(' '*4): 70 | b += l[4:] 71 | else: 72 | b += l 73 | 74 | print b 75 | 76 | def standardconf(): 77 | a = """[firstbit] 78 | 80 | 81 | 82 | 83 | 84 | 85 | [defaultcss] 86 | 87 | 88 | [windowtitle] 89 | # used in header for window title. 90 | | 91 | 92 | [doctitle] 93 | # used at top of document. 94 |
    95 |

    |

    96 | 97 | [subtitle] 98 |
    |
    99 | 100 | [doctitleend] 101 |
    102 | 103 | [bodystart] 104 | 105 | 106 | 107 | [menustart] 108 | 109 | 110 | 114 | 135 | 136 |
    111 | 112 | [menuend] 113 | 115 |
    116 | 117 | [menucategory] 118 | 119 | 120 | [menuitem] 121 | 122 | 123 | [currentmenuitem] 124 | 125 | 126 | [nomenu] 127 |
    128 | 129 | [css] 130 | 131 | 132 | [menulastbit] 133 |
    134 |
    137 | 138 | [nomenulastbit] 139 | 140 | 141 | [bodyend] 142 | 143 | 144 | 145 | [infoblock] 146 |
    147 | 148 | [codeblock] 149 |
    150 | 151 | [blocktitle] 152 |
    |
    153 | 154 | [infoblockcontent] 155 |
    156 | 157 | [codeblockcontent] 158 |
    159 |     
    160 |     [codeblockend]
    161 |     
    162 | 163 | [infoblockend] 164 |
    165 | 166 | [footerstart] 167 | 173 | 174 | [lastupdated] 175 | Last updated |, using jemdoc. 176 | """ 177 | b = '' 178 | for l in a.splitlines(True): 179 | if l.startswith(' '): 180 | b += l[4:] 181 | else: 182 | b += l 183 | 184 | return b 185 | 186 | class JandalError(Exception): 187 | pass 188 | 189 | def raisejandal(msg, line=0): 190 | if line == 0: 191 | s = "%s" % msg 192 | else: 193 | s = "line %d: %s" % (line, msg) 194 | raise JandalError(s) 195 | 196 | 197 | def readnoncomment(f): 198 | l = f.readline() 199 | if l == '': 200 | return l 201 | elif l[0] == '#': # jem: be a little more generous with the comments we accept? 202 | return readnoncomment(f) 203 | else: 204 | return l.rstrip() + '\n' # leave just one \n and no spaces etc. 205 | 206 | def parseconf(cns): 207 | syntax = {} 208 | warn = False # jem. make configurable? 209 | # manually add the defaults as a file handle. 210 | fs = [StringIO.StringIO(standardconf())] 211 | for sname in cns: 212 | fs.append(open(sname)) 213 | 214 | for f in fs: 215 | while pc(f) != '': 216 | l = readnoncomment(f) 217 | r = re.match(r'\[(.*)\]\n', l) 218 | 219 | if r: 220 | tag = r.group(1) 221 | 222 | s = '' 223 | l = readnoncomment(f) 224 | while l not in ('\n', ''): 225 | s += l 226 | l = readnoncomment(f) 227 | 228 | syntax[tag] = s 229 | 230 | f.close() 231 | 232 | return syntax 233 | 234 | def insertmenuitems(f, mname, current, prefix): 235 | m = open(mname) 236 | while pc(m) != '': 237 | l = readnoncomment(m) 238 | l = l.strip() 239 | if l == '': 240 | continue 241 | 242 | r = re.match(r'\s*(.*?)\s*\[(.*)\]', l) 243 | 244 | if r: # then we have a link. 245 | if r.group(2) == current: 246 | hb(f.outf, f.conf['currentmenuitem'], prefix + r.group(2), br(r.group(1))) 247 | else: 248 | hb(f.outf, f.conf['menuitem'], prefix + r.group(2), br(r.group(1))) 249 | 250 | else: # menu category. 251 | hb(f.outf, f.conf['menucategory'], br(l)) 252 | 253 | m.close() 254 | 255 | def out(f, s): 256 | f.write(s) 257 | 258 | def hb(f, tag, content1, content2=None): 259 | """Writes out a halfblock (hb).""" 260 | if content2 is None: 261 | out(f, re.sub(r'\|', content1, tag)) 262 | else: 263 | r = re.sub(r'\|1', content1, tag) 264 | r = re.sub(r'\|2', content2, r) 265 | out(f, r) 266 | 267 | def pc(f): 268 | """Peeks at next character in the file.""" 269 | # Should only be used to look at the first character f.outf a new line. 270 | c = f.read(1) 271 | if c: # only undo forward movement if we're not at the end. 272 | #if c == '#': # interpret comment lines as blank. 273 | # return '\n' 274 | 275 | if c in ' \t': 276 | return pc(f) 277 | 278 | f.seek(-1, 1) 279 | 280 | return c 281 | 282 | def nl(f, withcount=False, codemode=False): 283 | """Get input file line.""" 284 | s = f.inf.readline() 285 | f.linenum += 1 286 | if not codemode: 287 | # remove any special characters - assume they were checked by pc() 288 | # before we got here. 289 | # remove any trailing comments. 290 | s = s.lstrip(' \t') 291 | s = re.sub(r'\s*(?$%\.~[\]-]""", r'\\\g<0>', s) 337 | else: 338 | return re.sub(r"""[\\*/+"'<>\.~[\]-]""", r'\\\g<0>', s) 339 | 340 | def replacequoted(b): 341 | """Quotes {{raw html}} sections. Insert a backslash right before the end 342 | with &bs;, an illegal html character.""" 343 | r = re.compile(r'\{\{(.*?)\}\}', re.M + re.S) 344 | m = r.search(b) 345 | while m: 346 | qb = quote(m.group(1), True) 347 | 348 | b = b[:m.start()] + qb + b[m.end():] 349 | 350 | m = r.search(b, m.start()) 351 | 352 | r = re.compile(r'(?' % " ".join(bits) + b[m.end():] 399 | 400 | m = r.search(b, m.start()) 401 | 402 | return b 403 | 404 | def replacelinks(b): 405 | # works with [link.html new link style]. 406 | r = re.compile(r'(?%s<\/a>' % (link, linkname) + b[m.end():] 425 | 426 | m = r.search(b, m.start()) 427 | 428 | return b 429 | 430 | def br(b): 431 | """Does simple text replacements on a block of text. ('block replacements')""" 432 | # Deal with literal backspaces. 433 | b = re.sub(r'\\\\', '&jemLITerl33talBS;', b) 434 | 435 | # Deal with {{html embedding}}. 436 | b = replacequoted(b) 437 | 438 | b = allreplace(b) 439 | 440 | # First do the URL thing. 441 | b = b.lstrip('-. \t') # remove leading spaces, tabs, dashes, dots. 442 | b = replacelinks(b) 443 | 444 | # Deal with /italics/ first because the '/' in other tags would otherwise 445 | # interfere. 446 | r = re.compile(r'(?\1', b) 448 | 449 | # Deal with *bold*. 450 | r = re.compile(r'(?\1', b) 452 | 453 | # Deal with +monospace+. 454 | r = re.compile(r'(?\1', b) 456 | 457 | # Deal with "double quotes". 458 | r = re.compile(r'(?', b) 496 | 497 | ## Deal with zero width \_. 498 | #r = re.compile(r"(?", re.M + re.S) 512 | b = re.sub(r, r'>', b) 513 | 514 | r = re.compile(r"(?\1', l) 525 | 526 | if l.startswith('>>>'): 527 | hb(f, '|\n', l) 528 | else: 529 | out(f, l + '\n') 530 | 531 | def py(f, l): 532 | # jem need to do much better here. 533 | l = l.rstrip() 534 | if l.startswith('>>>'): 535 | hb(f, '|\n', allreplace(l)) 536 | elif l.startswith('#'): 537 | hb(f, '|\n', allreplace(l)) 538 | else: 539 | out(f, allreplace(l) + '\n') 540 | 541 | def dashlist(f): 542 | level = 0 543 | 544 | while pc(f.inf) == '-': 545 | (s, newlevel) = np(f, True) 546 | 547 | # first adjust list number as appropriate. 548 | if newlevel > level: 549 | for i in range(newlevel - level): 550 | if newlevel > 1: 551 | out(f.outf, '\n') 552 | out(f.outf, '
      \n
    • ') 553 | elif newlevel < level: 554 | for i in range(level - newlevel): 555 | out(f.outf, '
    • \n
    \n
  • ') 556 | else: 557 | out(f.outf, '
  • \n
  • ') 558 | 559 | out(f.outf, br(s)) 560 | level = newlevel 561 | 562 | for i in range(level): 563 | out(f.outf, '
  • \n\n') 564 | 565 | def dotlist(f): 566 | level = 0 567 | 568 | while pc(f.inf) == '.': 569 | (s, newlevel) = np(f, True) 570 | 571 | # first adjust list number as appropriate. 572 | if newlevel > level: 573 | for i in range(newlevel - level): 574 | if newlevel > 1: 575 | out(f.outf, '\n') 576 | out(f.outf, '
      \n
    1. ') 577 | elif newlevel < level: 578 | for i in range(level - newlevel): 579 | out(f.outf, '
    2. \n
    \n
  • ') 580 | else: 581 | out(f.outf, '
  • \n
  • ') 582 | 583 | out(f.outf, br(s)) 584 | level = newlevel 585 | 586 | for i in range(level): 587 | out(f.outf, '
  • \n\n') 588 | 589 | def colonlist(f): 590 | out(f.outf, '
    \n') 591 | while pc(f.inf) == ':': 592 | s = np(f) 593 | r = re.compile(r'\s*{(.*?)(?|\n', br(defpart)) 604 | hb(f.outf, '
    |
    \n', br(rest)) 605 | 606 | out(f.outf, '
    \n') 607 | 608 | def codeblock(f, g): 609 | out(f.outf, f.conf['codeblock']) 610 | if len(g[0]): 611 | hb(f.outf, f.conf['blocktitle'], g[0]) 612 | out(f.outf, f.conf['codeblockcontent']) 613 | 614 | if g[1] not in ('', 'pyint', 'py'): 615 | raise SyntaxError( \ 616 | "couldn't handle the jandal: unrecognised syntax " 617 | "highlighting on line %d" % linenum) 618 | 619 | # Now we are handling code. 620 | # Handle \~ and ~ differently. 621 | while 1: # wait for EOF. 622 | l = nl(f, codemode=True) 623 | if not l: 624 | break 625 | elif l.startswith('~'): 626 | break 627 | elif l.startswith('\\~'): 628 | l = l[1:] 629 | elif l.startswith('\\{'): 630 | l = l[1:] 631 | 632 | if g[1] == 'pyint': 633 | pyint(f.outf, l) 634 | elif g[1] == 'py': 635 | py(f.outf, l) 636 | else: 637 | out(f.outf, allreplace(l)) 638 | 639 | out(f.outf, f.conf['codeblockend']) 640 | 641 | def procfile(f): 642 | linenum = 0 643 | 644 | menu = None 645 | footer = True 646 | nodefaultcss = False 647 | css = [] 648 | if pc(f.inf) == '#': 649 | l = f.inf.readline() 650 | linenum += 1 651 | if l.startswith('# jemdoc: '): 652 | l = l[len('# jemdoc: '):] 653 | a = l.split(',') 654 | # jem only handle one argument for now. 655 | for b in a: 656 | b = b.strip() 657 | if b.startswith('menu'): 658 | sidemenu = True 659 | r = re.compile(r'(? 3 or len(g) < 2: 662 | raise SyntaxError('sidemenu error on line %d' % linenum) 663 | 664 | if len(g) == 2: 665 | menu = (f, g[0], g[1], '') 666 | else: 667 | menu = (f, g[0], g[1], g[2]) 668 | 669 | elif b.startswith('nodate'): 670 | footer = False 671 | 672 | elif b.startswith('nodefaultcss'): 673 | nodefaultcss = True 674 | 675 | elif b.startswith('addcss'): 676 | r = re.compile(r'(?|\n' % (c, c), br(s)) 742 | 743 | # look for comments. 744 | elif p == '#': 745 | nl(f) 746 | 747 | elif p == '\n': 748 | nl(f) 749 | 750 | # look for blocks. 751 | elif p == '~': 752 | nl(f) 753 | if infoblock: 754 | out(f.outf, f.conf['infoblockend']) 755 | infoblock = False 756 | nl(f) 757 | continue 758 | else: 759 | if pc(f.inf) == '{': 760 | l = br(nl(f)) 761 | r = re.compile(r'(?|

    \n', s) 785 | 786 | if footer: 787 | s = time.strftime('%F %R:%S %Z', time.localtime(time.time())) 788 | out(f.outf, f.conf['footerstart']) 789 | hb(f.outf, f.conf['lastupdated'], s) 790 | out(f.outf, f.conf['footerend']) 791 | 792 | if menu: 793 | out(f.outf, f.conf['menulastbit']) 794 | else: 795 | out(f.outf, f.conf['nomenulastbit']) 796 | 797 | out(f.outf, f.conf['bodyend']) 798 | 799 | if f.outf is not sys.stdout: 800 | f.outf.close() 801 | 802 | 803 | def main(): 804 | if len(sys.argv) == 1 or sys.argv[1] in ('--help', '-h'): 805 | showhelp() 806 | raise SystemExit 807 | if sys.argv[1] == '--show-config': 808 | print standardconf() 809 | raise SystemExit 810 | 811 | outoverride = False 812 | confoverride = False 813 | outname = None 814 | confnames = [] 815 | for i in range(1, len(sys.argv), 2): 816 | if sys.argv[i] == '-o': 817 | if outoverride: 818 | raise RuntimeError("only one output file / directory, please") 819 | outname = sys.argv[i+1] 820 | outoverride = True 821 | elif sys.argv[i] == '-c': 822 | if confoverride: 823 | raise RuntimeError("only one config file, please") 824 | confnames.append(sys.argv[i+1]) 825 | confoverride = True 826 | elif sys.argv[i].startswith('-'): 827 | raise RuntimeError('unrecognised argument %s, try --help' % sys.argv[i]) 828 | else: 829 | break 830 | 831 | conf = parseconf(confnames) 832 | 833 | innames = [] 834 | for j in range(i, len(sys.argv)): 835 | # First, if not a file and no dot, try opening .jemdoc. Otherwise, fall back 836 | # to just doing exactly as asked. 837 | inname = sys.argv[j] 838 | if not os.path.isfile(inname) and '.' not in inname: 839 | inname += '.jemdoc' 840 | 841 | innames.append(inname) 842 | 843 | if outname is not None and not os.path.isdir(outname) and len(innames) > 1: 844 | raise RuntimeError('cannot handle one outfile with multiple infiles') 845 | 846 | for inname in innames: 847 | if outname is None: 848 | thisout = re.sub(r'.jemdoc$', '', inname) + '.html' 849 | elif os.path.isdir(outname): 850 | # if directory, prepend directory to automatically generated name. 851 | thisout = outname + re.sub(r'.jemdoc$', '', inname) + '.html' 852 | else: 853 | thisout = outname 854 | 855 | infile = open(inname) 856 | outfile = open(thisout, 'w') 857 | 858 | f = controlstruct(infile, outfile, conf) 859 | procfile(f) 860 | 861 | # 862 | if __name__ == '__main__': 863 | main() 864 | -------------------------------------------------------------------------------- /www/dist/jemdoc.py-0.3.3: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | jemdoc: light markup, see http://jemdoc.jaboc.net/. 5 | 6 | version 0.3.3, November 2007. 7 | """ 8 | 9 | # Copyright (C) 2007 Jacob Mattingley. 10 | # 11 | # This file is part of jemdoc. 12 | # 13 | # jemdoc is free software; you can redistribute it and/or modify it under the 14 | # terms of the GNU General Public License as published by the Free Software 15 | # Foundation; either version 3 of the License, or (at your option) any later 16 | # version. 17 | # 18 | # jemdoc is distributed in the hope that it will be useful, but WITHOUT ANY 19 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 20 | # A PARTICULAR PURPOSE. See the GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License along with 23 | # this program. If not, see . 24 | 25 | import sys 26 | import os 27 | import re 28 | import time 29 | import StringIO 30 | 31 | class controlstruct(object): 32 | def __init__(self, infile, outfile=None, conf=None): 33 | self.inf = infile 34 | self.outf = outfile 35 | self.conf = conf 36 | self.linenum = 0 37 | 38 | # better checking of arguments? 39 | def showhelp(): 40 | a = """Usage: jemdoc [OPTIONS] [SOURCEFILE] 41 | Produces html markup from a jemdoc SOURCEFILE. 42 | 43 | Most of the time you can use jemdoc without any additional flags. 44 | For example, typing 45 | 46 | jemdoc index.jemdoc 47 | 48 | will produce an index.html, using a default configuration. You can 49 | change the output file by using -o OUTFILE, for example 50 | 51 | jemdoc -o html/main.html index.jemdoc 52 | 53 | Some configuration options can be overridden by specifying a 54 | configuration file. You can use 55 | 56 | jemdoc --show-config 57 | 58 | to print a sample configuration file (which includes all of the 59 | default options). Any or all of the configuration [blocks] can be 60 | overwritten by including them in a configuration file, and running, 61 | for example, 62 | 63 | jemdoc -c mywebsite.conf index.jemdoc 64 | 65 | See http://jemdoc.jaboc.net/ for more details. 66 | """ 67 | b = '' 68 | for l in a.splitlines(True): 69 | if l.startswith(' '*4): 70 | b += l[4:] 71 | else: 72 | b += l 73 | 74 | print b 75 | 76 | def standardconf(): 77 | a = """[firstbit] 78 | 80 | 81 | 82 | 83 | 84 | 85 | [defaultcss] 86 | 87 | 88 | [windowtitle] 89 | # used in header for window title. 90 | | 91 | 92 | [doctitle] 93 | # used at top of document. 94 |
    95 |

    |

    96 | 97 | [subtitle] 98 |
    |
    99 | 100 | [doctitleend] 101 |
    102 | 103 | [bodystart] 104 | 105 | 106 | 107 | [menustart] 108 | 109 | 110 | 114 | 135 | 136 |
    111 | 112 | [menuend] 113 | 115 |
    116 | 117 | [menucategory] 118 | 119 | 120 | [menuitem] 121 | 122 | 123 | [currentmenuitem] 124 | 125 | 126 | [nomenu] 127 |
    128 | 129 | [css] 130 | 131 | 132 | [menulastbit] 133 |
    134 |
    137 | 138 | [nomenulastbit] 139 | 140 | 141 | [bodyend] 142 | 143 | 144 | 145 | [infoblock] 146 |
    147 | 148 | [codeblock] 149 |
    150 | 151 | [blocktitle] 152 |
    |
    153 | 154 | [infoblockcontent] 155 |
    156 | 157 | [codeblockcontent] 158 |
    159 |     
    160 |     [codeblockend]
    161 |     
    162 | 163 | [infoblockend] 164 |
    165 | 166 | [footerstart] 167 | 173 | 174 | [lastupdated] 175 | Page generated |, by jemdoc. 176 | """ 177 | b = '' 178 | for l in a.splitlines(True): 179 | if l.startswith(' '): 180 | b += l[4:] 181 | else: 182 | b += l 183 | 184 | return b 185 | 186 | class JandalError(Exception): 187 | pass 188 | 189 | def raisejandal(msg, line=0): 190 | if line == 0: 191 | s = "%s" % msg 192 | else: 193 | s = "line %d: %s" % (line, msg) 194 | raise JandalError(s) 195 | 196 | def readnoncomment(f): 197 | l = f.readline() 198 | if l == '': 199 | return l 200 | elif l[0] == '#': # jem: be a little more generous with the comments we accept? 201 | return readnoncomment(f) 202 | else: 203 | return l.rstrip() + '\n' # leave just one \n and no spaces etc. 204 | 205 | def parseconf(cns): 206 | syntax = {} 207 | warn = False # jem. make configurable? 208 | # manually add the defaults as a file handle. 209 | fs = [StringIO.StringIO(standardconf())] 210 | for sname in cns: 211 | fs.append(open(sname)) 212 | 213 | for f in fs: 214 | while pc(controlstruct(f)) != '': 215 | l = readnoncomment(f) 216 | r = re.match(r'\[(.*)\]\n', l) 217 | 218 | if r: 219 | tag = r.group(1) 220 | 221 | s = '' 222 | l = readnoncomment(f) 223 | while l not in ('\n', ''): 224 | s += l 225 | l = readnoncomment(f) 226 | 227 | syntax[tag] = s 228 | 229 | f.close() 230 | 231 | return syntax 232 | 233 | def insertmenuitems(f, mname, current, prefix): 234 | m = open(mname) 235 | while pc(controlstruct(m)) != '': 236 | l = readnoncomment(m) 237 | l = l.strip() 238 | if l == '': 239 | continue 240 | 241 | r = re.match(r'\s*(.*?)\s*\[(.*)\]', l) 242 | 243 | if r: # then we have a link. 244 | link = r.group(2) 245 | # Don't use prefix if we have an absolute link. 246 | if '://' not in r.group(2): 247 | link = prefix + allreplace(link) 248 | 249 | if r.group(2) == current: 250 | hb(f.outf, f.conf['currentmenuitem'], link, br(r.group(1))) 251 | else: 252 | hb(f.outf, f.conf['menuitem'], link, br(r.group(1))) 253 | 254 | else: # menu category. 255 | hb(f.outf, f.conf['menucategory'], br(l)) 256 | 257 | m.close() 258 | 259 | def out(f, s): 260 | f.write(s) 261 | 262 | def hb(f, tag, content1, content2=None): 263 | """Writes out a halfblock (hb).""" 264 | if content2 is None: 265 | out(f, re.sub(r'\|', content1, tag)) 266 | else: 267 | r = re.sub(r'\|1', content1, tag) 268 | r = re.sub(r'\|2', content2, r) 269 | out(f, r) 270 | 271 | def pc(f, ditchcomments=True): 272 | """Peeks at next character in the file.""" 273 | # Should only be used to look at the first character of a new line. 274 | c = f.inf.read(1) 275 | if c: # only undo forward movement if we're not at the end. 276 | #if c == '#': # interpret comment lines as blank. 277 | # return '\n' 278 | if ditchcomments and c == '#': 279 | nl(f) 280 | 281 | if c in ' \t': 282 | return pc(f) 283 | 284 | f.inf.seek(-1, 1) 285 | 286 | return c 287 | 288 | def nl(f, withcount=False, codemode=False): 289 | """Get input file line.""" 290 | s = f.inf.readline() 291 | f.linenum += 1 292 | if not codemode: 293 | # remove any special characters - assume they were checked by pc() 294 | # before we got here. 295 | # remove any trailing comments. 296 | s = s.lstrip(' \t') 297 | s = re.sub(r'\s*(?&$%\.~[\]-]""", r'\\\g<0>', s) 343 | else: 344 | return re.sub(r"""[\\*/+"'<>&$\.~[\]-]""", r'\\\g<0>', s) 345 | 346 | def replacequoted(b): 347 | """Quotes {{raw html}} sections. Insert a backslash right before the end 348 | with &bs;, an illegal html character.""" 349 | r = re.compile(r'\{\{(.*?)\}\}', re.M + re.S) 350 | m = r.search(b) 351 | while m: 352 | qb = quote(m.group(1), True) 353 | 354 | b = b[:m.start()] + qb + b[m.end():] 355 | 356 | m = r.search(b, m.start()) 357 | 358 | r = re.compile(r'(?' % " ".join(bits) + b[m.end():] 405 | 406 | m = r.search(b, m.start()) 407 | 408 | return b 409 | 410 | def replacelinks(b): 411 | # works with [link.html new link style]. 412 | r = re.compile(r'(?%s<\/a>' % (link, linkname) + b[m.end():] 431 | 432 | m = r.search(b, m.start()) 433 | 434 | return b 435 | 436 | def br(b): 437 | """Does simple text replacements on a block of text. ('block replacements')""" 438 | # Deal with literal backspaces. 439 | b = re.sub(r'\\\\', 'jemLITerl33talBS', b) 440 | 441 | # Deal with {{html embedding}}. 442 | b = replacequoted(b) 443 | 444 | b = allreplace(b) 445 | 446 | # First do the URL thing. 447 | b = b.lstrip('-. \t') # remove leading spaces, tabs, dashes, dots. 448 | b = replaceimages(b) 449 | b = replacelinks(b) 450 | 451 | # Deal with /italics/ first because the '/' in other tags would otherwise 452 | # interfere. 453 | r = re.compile(r'(?\1', b) 455 | 456 | # Deal with *bold*. 457 | r = re.compile(r'(?\1', b) 459 | 460 | # Deal with +monospace+. 461 | r = re.compile(r'(?\1', b) 463 | 464 | # Deal with "double quotes". 465 | r = re.compile(r'(?', b) 503 | 504 | ## Deal with zero width \_. 505 | #r = re.compile(r"(?", re.M + re.S) 522 | b = re.sub(r, r'>', b) 523 | 524 | r = re.compile(r"(?\1', l) 535 | 536 | if l.startswith('>>>'): 537 | hb(f, '|\n', l) 538 | else: 539 | out(f, l + '\n') 540 | 541 | def putbsbs(l): 542 | for i in range(len(l)): 543 | l[i] = '\\b' + l[i] + '\\b' 544 | 545 | return l 546 | 547 | def gethl(lang): 548 | # disable comments by default, by choosing unlikely regex. 549 | d = {'statement':[], 'commentstart':'######%%%%%', 'operator':[], 'builtin':[], 550 | 'error':[]} 551 | if lang in ('py', 'python'): 552 | d['statement'] = putbsbs(['break', 'continue', 'del', 'except', 'exec', 553 | 'finally', 'pass', 'print', 'raise', 'return', 554 | 'try', 'with', 'global', 'assert', 'lambda', 555 | 'yield', 'def', 'class', 'for', 'while', 'if', 556 | 'elif', 'else', 'import', 'from', 'as']) 557 | d['operator'] = putbsbs(['and', 'in', 'is', 'not', 'or']) 558 | d['builtin'] = putbsbs(['True', 'False', 'set', 'open', 'frozenset', 559 | 'enumerate', 'object', 'hasattr', 'getattr', 560 | 'filter', 'eval', 'zip', 'vars', 'unicode', 561 | 'type', 'str', 'repr', 'round']) 562 | d['error'] = putbsbs(['\w*Error',]) 563 | d['commentstart'] = '#' 564 | elif lang == 'sh': 565 | d['statement'] = putbsbs(['cd', 'ls', 'sudo']) 566 | d['operator'] = ['>'] 567 | d['builtin'] = putbsbs(['curl', 'wget', '(?|\n', allreplace(l)) 577 | else: 578 | l = allreplace(l) 579 | # handle strings. 580 | r = re.compile(r'(".*?")') 581 | l = r.sub(r'\1', l) 582 | r = re.compile(r"('.*?')") 583 | l = r.sub(r'\1', l) 584 | 585 | # handle comments. 586 | r = re.compile(hl['commentstart']) 587 | l = r.sub(r'\1', l) 588 | 589 | if hl['statement']: 590 | r = re.compile('(' + '|'.join(hl['statement']) + ')') 591 | l = r.sub(r'\1', l) 592 | 593 | if hl['operator']: 594 | r = re.compile('(' + '|'.join(hl['operator']) + ')') 595 | l = r.sub(r'\1', l) 596 | 597 | if hl['builtin']: 598 | r = re.compile('(' + '|'.join(hl['builtin']) + ')') 599 | l = r.sub(r'\1', l) 600 | 601 | if hl['error']: 602 | r = re.compile('(' + '|'.join(hl['error']) + ')') 603 | l = r.sub(r'\1', l) 604 | 605 | l = re.sub('CLASS', 'class', l) 606 | 607 | out(f, l + '\n') 608 | 609 | def dashlist(f): 610 | level = 0 611 | 612 | while pc(f) == '-': 613 | (s, newlevel) = np(f, True) 614 | 615 | # first adjust list number as appropriate. 616 | if newlevel > level: 617 | for i in range(newlevel - level): 618 | if newlevel > 1: 619 | out(f.outf, '\n') 620 | out(f.outf, '
      \n
    • ') 621 | elif newlevel < level: 622 | for i in range(level - newlevel): 623 | out(f.outf, '
    • \n
    \n
  • ') 624 | else: 625 | out(f.outf, '
  • \n
  • ') 626 | 627 | out(f.outf, br(s)) 628 | level = newlevel 629 | 630 | for i in range(level): 631 | out(f.outf, '
  • \n\n') 632 | 633 | def dotlist(f): 634 | level = 0 635 | 636 | while pc(f) == '.': 637 | (s, newlevel) = np(f, True) 638 | 639 | # first adjust list number as appropriate. 640 | if newlevel > level: 641 | for i in range(newlevel - level): 642 | if newlevel > 1: 643 | out(f.outf, '\n') 644 | out(f.outf, '
      \n
    1. ') 645 | elif newlevel < level: 646 | for i in range(level - newlevel): 647 | out(f.outf, '
    2. \n
    \n
  • ') 648 | else: 649 | out(f.outf, '
  • \n
  • ') 650 | 651 | out(f.outf, br(s)) 652 | level = newlevel 653 | 654 | for i in range(level): 655 | out(f.outf, '
  • \n\n') 656 | 657 | def colonlist(f): 658 | out(f.outf, '
    \n') 659 | while pc(f) == ':': 660 | s = np(f) 661 | r = re.compile(r'\s*{(.*?)(?|\n', br(defpart)) 672 | hb(f.outf, '
    |
    \n', br(rest)) 673 | 674 | out(f.outf, '
    \n') 675 | 676 | def codeblock(f, g): 677 | if g[1] == 'raw': 678 | raw = True 679 | else: 680 | raw = False 681 | out(f.outf, f.conf['codeblock']) 682 | if g[0]: 683 | hb(f.outf, f.conf['blocktitle'], g[0]) 684 | out(f.outf, f.conf['codeblockcontent']) 685 | 686 | # Now we are handling code. 687 | # Handle \~ and ~ differently. 688 | while 1: # wait for EOF. 689 | l = nl(f, codemode=True) 690 | if not l: 691 | break 692 | elif l.startswith('~'): 693 | break 694 | elif l.startswith('\\~'): 695 | l = l[1:] 696 | elif l.startswith('\\{'): 697 | l = l[1:] 698 | 699 | # jem revise pyint out of the picture. 700 | if g[1] == 'pyint': 701 | pyint(f.outf, l) 702 | else: 703 | if raw: 704 | out(f.outf, l) 705 | else: 706 | language(f.outf, l, gethl(g[1])) 707 | 708 | if not raw: 709 | out(f.outf, f.conf['codeblockend']) 710 | 711 | def procfile(f): 712 | linenum = 0 713 | 714 | menu = None 715 | footer = True 716 | nodefaultcss = False 717 | css = [] 718 | if pc(f, False) == '#': 719 | l = f.inf.readline() 720 | linenum += 1 721 | if l.startswith('# jemdoc: '): 722 | l = l[len('# jemdoc: '):] 723 | a = l.split(',') 724 | # jem only handle one argument for now. 725 | for b in a: 726 | b = b.strip() 727 | if b.startswith('menu'): 728 | sidemenu = True 729 | r = re.compile(r'(? 3 or len(g) < 2: 732 | raise SyntaxError('sidemenu error on line %d' % linenum) 733 | 734 | if len(g) == 2: 735 | menu = (f, g[0], g[1], '') 736 | else: 737 | menu = (f, g[0], g[1], g[2]) 738 | 739 | elif b.startswith('nodate'): 740 | footer = False 741 | 742 | elif b.startswith('nodefaultcss'): 743 | nodefaultcss = True 744 | 745 | elif b.startswith('addcss'): 746 | r = re.compile(r'(?|\n' % (c, c), br(s)) 813 | 814 | # look for comments. 815 | elif p == '#': 816 | nl(f) 817 | 818 | elif p == '\n': 819 | nl(f) 820 | 821 | # look for blocks. 822 | elif p == '~': 823 | nl(f) 824 | if infoblock: 825 | out(f.outf, f.conf['infoblockend']) 826 | infoblock = False 827 | nl(f) 828 | continue 829 | elif imgblock: 830 | out(f.outf, '\n') 831 | imgblock = False 832 | nl(f) 833 | continue 834 | else: 835 | if pc(f) == '{': 836 | l = allreplace(nl(f)) 837 | r = re.compile(r'(?= 1: 844 | g[0] = br(g[0]) 845 | 846 | if len(g) in (0, 1): # info block. 847 | out(f.outf, f.conf['infoblock']) 848 | infoblock = True 849 | 850 | if len(g) == 1: # info block. 851 | hb(f.outf, f.conf['blocktitle'], g[0]) 852 | 853 | out(f.outf, f.conf['infoblockcontent']) 854 | 855 | elif len(g) == 2: 856 | codeblock(f, g) 857 | 858 | elif len(g) >= 4 and g[1] == 'img_left': 859 | # handles 860 | # {}{img_left}{source}{alttext}{width}{height}{linktarget}. 861 | g += ['']*(7 - len(g)) 862 | 863 | if g[4].isdigit(): 864 | g[4] += 'px' 865 | 866 | if g[5].isdigit(): 867 | g[5] += 'px' 868 | 869 | out(f.outf, '\n
    \n') 870 | if g[6]: 871 | out(f.outf, '' % g[6]) 872 | out(f.outf, '%s') 879 | if g[6]: 880 | out(f.outf, '') 881 | out(f.outf, ' ') 882 | imgblock = True 883 | 884 | else: 885 | raise JandalError("couldn't handle block", linenum) 886 | 887 | else: 888 | s = br(np(f)) 889 | if s: 890 | hb(f.outf, '

    |

    \n', s) 891 | 892 | if footer: 893 | s = time.strftime('%F %R:%S %Z', time.localtime(time.time())) 894 | out(f.outf, f.conf['footerstart']) 895 | hb(f.outf, f.conf['lastupdated'], s) 896 | out(f.outf, f.conf['footerend']) 897 | 898 | if menu: 899 | out(f.outf, f.conf['menulastbit']) 900 | else: 901 | out(f.outf, f.conf['nomenulastbit']) 902 | 903 | out(f.outf, f.conf['bodyend']) 904 | 905 | if f.outf is not sys.stdout: 906 | f.outf.close() 907 | 908 | def main(): 909 | if len(sys.argv) == 1 or sys.argv[1] in ('--help', '-h'): 910 | showhelp() 911 | raise SystemExit 912 | if sys.argv[1] == '--show-config': 913 | print standardconf() 914 | raise SystemExit 915 | 916 | outoverride = False 917 | confoverride = False 918 | outname = None 919 | confnames = [] 920 | for i in range(1, len(sys.argv), 2): 921 | if sys.argv[i] == '-o': 922 | if outoverride: 923 | raise RuntimeError("only one output file / directory, please") 924 | outname = sys.argv[i+1] 925 | outoverride = True 926 | elif sys.argv[i] == '-c': 927 | if confoverride: 928 | raise RuntimeError("only one config file, please") 929 | confnames.append(sys.argv[i+1]) 930 | confoverride = True 931 | elif sys.argv[i].startswith('-'): 932 | raise RuntimeError('unrecognised argument %s, try --help' % sys.argv[i]) 933 | else: 934 | break 935 | 936 | conf = parseconf(confnames) 937 | 938 | innames = [] 939 | for j in range(i, len(sys.argv)): 940 | # First, if not a file and no dot, try opening .jemdoc. Otherwise, fall back 941 | # to just doing exactly as asked. 942 | inname = sys.argv[j] 943 | if not os.path.isfile(inname) and '.' not in inname: 944 | inname += '.jemdoc' 945 | 946 | innames.append(inname) 947 | 948 | if outname is not None and not os.path.isdir(outname) and len(innames) > 1: 949 | raise RuntimeError('cannot handle one outfile with multiple infiles') 950 | 951 | for inname in innames: 952 | if outname is None: 953 | thisout = re.sub(r'.jemdoc$', '', inname) + '.html' 954 | elif os.path.isdir(outname): 955 | # if directory, prepend directory to automatically generated name. 956 | thisout = outname + re.sub(r'.jemdoc$', '', inname) + '.html' 957 | else: 958 | thisout = outname 959 | 960 | infile = open(inname) 961 | outfile = open(thisout, 'w') 962 | 963 | f = controlstruct(infile, outfile, conf) 964 | procfile(f) 965 | 966 | # 967 | if __name__ == '__main__': 968 | main() 969 | -------------------------------------------------------------------------------- /www/dist/jemdoc.py-0.3.4: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | jemdoc: light markup, see http://jemdoc.jaboc.net/. 5 | 6 | version 0.3.4, November 2007. 7 | """ 8 | 9 | # Copyright (C) 2007 Jacob Mattingley. 10 | # 11 | # This file is part of jemdoc. 12 | # 13 | # jemdoc is free software; you can redistribute it and/or modify it under the 14 | # terms of the GNU General Public License as published by the Free Software 15 | # Foundation; either version 3 of the License, or (at your option) any later 16 | # version. 17 | # 18 | # jemdoc is distributed in the hope that it will be useful, but WITHOUT ANY 19 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 20 | # A PARTICULAR PURPOSE. See the GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License along with 23 | # this program. If not, see . 24 | 25 | import sys 26 | import os 27 | import re 28 | import time 29 | import StringIO 30 | 31 | class controlstruct(object): 32 | def __init__(self, infile, outfile=None, conf=None): 33 | self.inf = infile 34 | self.outf = outfile 35 | self.conf = conf 36 | self.linenum = 0 37 | 38 | # better checking of arguments? 39 | def showhelp(): 40 | a = """Usage: jemdoc [OPTIONS] [SOURCEFILE] 41 | Produces html markup from a jemdoc SOURCEFILE. 42 | 43 | Most of the time you can use jemdoc without any additional flags. 44 | For example, typing 45 | 46 | jemdoc index.jemdoc 47 | 48 | will produce an index.html, using a default configuration. You can 49 | change the output file by using -o OUTFILE, for example 50 | 51 | jemdoc -o html/main.html index.jemdoc 52 | 53 | Some configuration options can be overridden by specifying a 54 | configuration file. You can use 55 | 56 | jemdoc --show-config 57 | 58 | to print a sample configuration file (which includes all of the 59 | default options). Any or all of the configuration [blocks] can be 60 | overwritten by including them in a configuration file, and running, 61 | for example, 62 | 63 | jemdoc -c mywebsite.conf index.jemdoc 64 | 65 | See http://jemdoc.jaboc.net/ for more details. 66 | """ 67 | b = '' 68 | for l in a.splitlines(True): 69 | if l.startswith(' '*4): 70 | b += l[4:] 71 | else: 72 | b += l 73 | 74 | print b 75 | 76 | def standardconf(): 77 | a = """[firstbit] 78 | 80 | 81 | 82 | 83 | 84 | 85 | [defaultcss] 86 | 87 | 88 | [windowtitle] 89 | # used in header for window title. 90 | | 91 | 92 | [doctitle] 93 | # used at top of document. 94 |
    95 |

    |

    96 | 97 | [subtitle] 98 |
    |
    99 | 100 | [doctitleend] 101 |
    102 | 103 | [bodystart] 104 | 105 | 106 | 107 | [menustart] 108 | 109 | 110 | 114 | 135 | 136 |
    111 | 112 | [menuend] 113 | 115 |
    116 | 117 | [menucategory] 118 | 119 | 120 | [menuitem] 121 | 122 | 123 | [currentmenuitem] 124 | 125 | 126 | [nomenu] 127 |
    128 | 129 | [css] 130 | 131 | 132 | [menulastbit] 133 |
    134 |
    137 | 138 | [nomenulastbit] 139 | 140 | 141 | [bodyend] 142 | 143 | 144 | 145 | [infoblock] 146 |
    147 | 148 | [codeblock] 149 |
    150 | 151 | [blocktitle] 152 |
    |
    153 | 154 | [infoblockcontent] 155 |
    156 | 157 | [codeblockcontent] 158 |
    159 |     
    160 |     [codeblockend]
    161 |     
    162 | 163 | [infoblockend] 164 |
    165 | 166 | [footerstart] 167 | 173 | 174 | [lastupdated] 175 | Page generated |, by jemdoc. 176 | """ 177 | b = '' 178 | for l in a.splitlines(True): 179 | if l.startswith(' '): 180 | b += l[4:] 181 | else: 182 | b += l 183 | 184 | return b 185 | 186 | class JandalError(Exception): 187 | pass 188 | 189 | def raisejandal(msg, line=0): 190 | if line == 0: 191 | s = "%s" % msg 192 | else: 193 | s = "line %d: %s" % (line, msg) 194 | raise JandalError(s) 195 | 196 | def readnoncomment(f): 197 | l = f.readline() 198 | if l == '': 199 | return l 200 | elif l[0] == '#': # jem: be a little more generous with the comments we accept? 201 | return readnoncomment(f) 202 | else: 203 | return l.rstrip() + '\n' # leave just one \n and no spaces etc. 204 | 205 | def parseconf(cns): 206 | syntax = {} 207 | warn = False # jem. make configurable? 208 | # manually add the defaults as a file handle. 209 | fs = [StringIO.StringIO(standardconf())] 210 | for sname in cns: 211 | fs.append(open(sname)) 212 | 213 | for f in fs: 214 | while pc(controlstruct(f)) != '': 215 | l = readnoncomment(f) 216 | r = re.match(r'\[(.*)\]\n', l) 217 | 218 | if r: 219 | tag = r.group(1) 220 | 221 | s = '' 222 | l = readnoncomment(f) 223 | while l not in ('\n', ''): 224 | s += l 225 | l = readnoncomment(f) 226 | 227 | syntax[tag] = s 228 | 229 | f.close() 230 | 231 | return syntax 232 | 233 | def insertmenuitems(f, mname, current, prefix): 234 | m = open(mname) 235 | while pc(controlstruct(m)) != '': 236 | l = readnoncomment(m) 237 | l = l.strip() 238 | if l == '': 239 | continue 240 | 241 | r = re.match(r'\s*(.*?)\s*\[(.*)\]', l) 242 | 243 | if r: # then we have a link. 244 | link = r.group(2) 245 | # Don't use prefix if we have an absolute link. 246 | if '://' not in r.group(2): 247 | link = prefix + allreplace(link) 248 | 249 | if r.group(2) == current: 250 | hb(f.outf, f.conf['currentmenuitem'], link, br(r.group(1))) 251 | else: 252 | hb(f.outf, f.conf['menuitem'], link, br(r.group(1))) 253 | 254 | else: # menu category. 255 | hb(f.outf, f.conf['menucategory'], br(l)) 256 | 257 | m.close() 258 | 259 | def out(f, s): 260 | f.write(s) 261 | 262 | def hb(f, tag, content1, content2=None): 263 | """Writes out a halfblock (hb).""" 264 | if content2 is None: 265 | out(f, re.sub(r'\|', content1, tag)) 266 | else: 267 | r = re.sub(r'\|1', content1, tag) 268 | r = re.sub(r'\|2', content2, r) 269 | out(f, r) 270 | 271 | def pc(f, ditchcomments=True): 272 | """Peeks at next character in the file.""" 273 | # Should only be used to look at the first character of a new line. 274 | c = f.inf.read(1) 275 | if c: # only undo forward movement if we're not at the end. 276 | #if c == '#': # interpret comment lines as blank. 277 | # return '\n' 278 | if ditchcomments and c == '#': 279 | nl(f) 280 | 281 | if c in ' \t': 282 | return pc(f) 283 | 284 | f.inf.seek(-1, 1) 285 | 286 | return c 287 | 288 | def nl(f, withcount=False, codemode=False): 289 | """Get input file line.""" 290 | s = f.inf.readline() 291 | f.linenum += 1 292 | if not codemode: 293 | # remove any special characters - assume they were checked by pc() 294 | # before we got here. 295 | # remove any trailing comments. 296 | s = s.lstrip(' \t') 297 | s = re.sub(r'\s*(?&$%\.~[\]-]""", r'\\\g<0>', s) 343 | else: 344 | return re.sub(r"""[\\*/+"'<>&$\.~[\]-]""", r'\\\g<0>', s) 345 | 346 | def replacequoted(b): 347 | """Quotes {{raw html}} sections. Insert a backslash right before the end 348 | with &bs;, an illegal html character.""" 349 | r = re.compile(r'\{\{(.*?)\}\}', re.M + re.S) 350 | m = r.search(b) 351 | while m: 352 | qb = quote(m.group(1), True) 353 | 354 | b = b[:m.start()] + qb + b[m.end():] 355 | 356 | m = r.search(b, m.start()) 357 | 358 | r = re.compile(r'(?' % " ".join(bits) + b[m.end():] 405 | 406 | m = r.search(b, m.start()) 407 | 408 | return b 409 | 410 | def replacelinks(b): 411 | # works with [link.html new link style]. 412 | r = re.compile(r'(?%s<\/a>' % (link, linkname) + b[m.end():] 431 | 432 | m = r.search(b, m.start()) 433 | 434 | return b 435 | 436 | def br(b): 437 | """Does simple text replacements on a block of text. ('block replacements')""" 438 | # Deal with literal backspaces. 439 | b = re.sub(r'\\\\', 'jemLITerl33talBS', b) 440 | 441 | # Deal with {{html embedding}}. 442 | b = replacequoted(b) 443 | 444 | b = allreplace(b) 445 | 446 | # First do the URL thing. 447 | b = b.lstrip('-. \t') # remove leading spaces, tabs, dashes, dots. 448 | b = replaceimages(b) 449 | b = replacelinks(b) 450 | 451 | # Deal with /italics/ first because the '/' in other tags would otherwise 452 | # interfere. 453 | r = re.compile(r'(?\1', b) 455 | 456 | # Deal with *bold*. 457 | r = re.compile(r'(?\1', b) 459 | 460 | # Deal with +monospace+. 461 | r = re.compile(r'(?\1', b) 463 | 464 | # Deal with "double quotes". 465 | r = re.compile(r'(?', b) 503 | 504 | ## Deal with zero width \_. 505 | #r = re.compile(r"(?", re.M + re.S) 522 | b = re.sub(r, r'>', b) 523 | 524 | r = re.compile(r"(?\1', l) 535 | 536 | if l.startswith('>>>'): 537 | hb(f, '|\n', l) 538 | else: 539 | out(f, l + '\n') 540 | 541 | def putbsbs(l): 542 | for i in range(len(l)): 543 | l[i] = '\\b' + l[i] + '\\b' 544 | 545 | return l 546 | 547 | def gethl(lang): 548 | # disable comments by default, by choosing unlikely regex. 549 | d = {'statement':[], 'commentstart':'######%%%%%', 'operator':[], 'builtin':[], 550 | 'error':[]} 551 | if lang in ('py', 'python'): 552 | d['statement'] = putbsbs(['break', 'continue', 'del', 'except', 'exec', 553 | 'finally', 'pass', 'print', 'raise', 'return', 554 | 'try', 'with', 'global', 'assert', 'lambda', 555 | 'yield', 'def', 'class', 'for', 'while', 'if', 556 | 'elif', 'else', 'import', 'from', 'as']) 557 | d['operator'] = putbsbs(['and', 'in', 'is', 'not', 'or']) 558 | d['builtin'] = putbsbs(['True', 'False', 'set', 'open', 'frozenset', 559 | 'enumerate', 'object', 'hasattr', 'getattr', 560 | 'filter', 'eval', 'zip', 'vars', 'unicode', 561 | 'type', 'str', 'repr', 'round']) 562 | d['error'] = putbsbs(['\w*Error',]) 563 | d['commentstart'] = '#' 564 | elif lang == 'sh': 565 | d['statement'] = putbsbs(['cd', 'ls', 'sudo']) 566 | d['operator'] = ['>'] 567 | d['builtin'] = putbsbs(['curl', 'wget', '(?|\n', allreplace(l)) 577 | else: 578 | l = allreplace(l) 579 | # handle strings. 580 | r = re.compile(r'(".*?")') 581 | l = r.sub(r'\1', l) 582 | r = re.compile(r"('.*?')") 583 | l = r.sub(r'\1', l) 584 | 585 | # handle comments. 586 | r = re.compile(hl['commentstart']) 587 | l = r.sub(r'\1', l) 588 | 589 | if hl['statement']: 590 | r = re.compile('(' + '|'.join(hl['statement']) + ')') 591 | l = r.sub(r'\1', l) 592 | 593 | if hl['operator']: 594 | r = re.compile('(' + '|'.join(hl['operator']) + ')') 595 | l = r.sub(r'\1', l) 596 | 597 | if hl['builtin']: 598 | r = re.compile('(' + '|'.join(hl['builtin']) + ')') 599 | l = r.sub(r'\1', l) 600 | 601 | if hl['error']: 602 | r = re.compile('(' + '|'.join(hl['error']) + ')') 603 | l = r.sub(r'\1', l) 604 | 605 | l = re.sub('CLASS', 'class', l) 606 | 607 | out(f, l + '\n') 608 | 609 | def dashlist(f): 610 | level = 0 611 | 612 | while pc(f) == '-': 613 | (s, newlevel) = np(f, True) 614 | 615 | # first adjust list number as appropriate. 616 | if newlevel > level: 617 | for i in range(newlevel - level): 618 | if newlevel > 1: 619 | out(f.outf, '\n') 620 | out(f.outf, '
      \n
    • ') 621 | elif newlevel < level: 622 | for i in range(level - newlevel): 623 | out(f.outf, '
    • \n
    \n
  • ') 624 | else: 625 | out(f.outf, '
  • \n
  • ') 626 | 627 | out(f.outf, br(s)) 628 | level = newlevel 629 | 630 | for i in range(level): 631 | out(f.outf, '
  • \n\n') 632 | 633 | def dotlist(f): 634 | level = 0 635 | 636 | while pc(f) == '.': 637 | (s, newlevel) = np(f, True) 638 | 639 | # first adjust list number as appropriate. 640 | if newlevel > level: 641 | for i in range(newlevel - level): 642 | if newlevel > 1: 643 | out(f.outf, '\n') 644 | out(f.outf, '
      \n
    1. ') 645 | elif newlevel < level: 646 | for i in range(level - newlevel): 647 | out(f.outf, '
    2. \n
    \n
  • ') 648 | else: 649 | out(f.outf, '
  • \n
  • ') 650 | 651 | out(f.outf, br(s)) 652 | level = newlevel 653 | 654 | for i in range(level): 655 | out(f.outf, '
  • \n\n') 656 | 657 | def colonlist(f): 658 | out(f.outf, '
    \n') 659 | while pc(f) == ':': 660 | s = np(f) 661 | r = re.compile(r'\s*{(.*?)(?|\n', br(defpart)) 672 | hb(f.outf, '
    |
    \n', br(rest)) 673 | 674 | out(f.outf, '
    \n') 675 | 676 | def codeblock(f, g): 677 | if g[1] == 'raw': 678 | raw = True 679 | else: 680 | raw = False 681 | out(f.outf, f.conf['codeblock']) 682 | if g[0]: 683 | hb(f.outf, f.conf['blocktitle'], g[0]) 684 | out(f.outf, f.conf['codeblockcontent']) 685 | 686 | # Now we are handling code. 687 | # Handle \~ and ~ differently. 688 | while 1: # wait for EOF. 689 | l = nl(f, codemode=True) 690 | if not l: 691 | break 692 | elif l.startswith('~'): 693 | break 694 | elif l.startswith('\\~'): 695 | l = l[1:] 696 | elif l.startswith('\\{'): 697 | l = l[1:] 698 | 699 | # jem revise pyint out of the picture. 700 | if g[1] == 'pyint': 701 | pyint(f.outf, l) 702 | else: 703 | if raw: 704 | out(f.outf, l) 705 | else: 706 | language(f.outf, l, gethl(g[1])) 707 | 708 | if not raw: 709 | out(f.outf, f.conf['codeblockend']) 710 | 711 | def procfile(f): 712 | linenum = 0 713 | 714 | menu = None 715 | footer = True 716 | nodefaultcss = False 717 | css = [] 718 | if pc(f, False) == '#': 719 | l = f.inf.readline() 720 | linenum += 1 721 | if l.startswith('# jemdoc: '): 722 | l = l[len('# jemdoc: '):] 723 | a = l.split(',') 724 | # jem only handle one argument for now. 725 | for b in a: 726 | b = b.strip() 727 | if b.startswith('menu'): 728 | sidemenu = True 729 | r = re.compile(r'(? 3 or len(g) < 2: 732 | raise SyntaxError('sidemenu error on line %d' % linenum) 733 | 734 | if len(g) == 2: 735 | menu = (f, g[0], g[1], '') 736 | else: 737 | menu = (f, g[0], g[1], g[2]) 738 | 739 | elif b.startswith('nodate'): 740 | footer = False 741 | 742 | elif b.startswith('nodefaultcss'): 743 | nodefaultcss = True 744 | 745 | elif b.startswith('addcss'): 746 | r = re.compile(r'(?|\n' % (c, c), br(s)) 813 | 814 | # look for comments. 815 | elif p == '#': 816 | nl(f) 817 | 818 | elif p == '\n': 819 | nl(f) 820 | 821 | # look for blocks. 822 | elif p == '~': 823 | nl(f) 824 | if infoblock: 825 | out(f.outf, f.conf['infoblockend']) 826 | infoblock = False 827 | nl(f) 828 | continue 829 | elif imgblock: 830 | out(f.outf, '
    \n') 831 | imgblock = False 832 | nl(f) 833 | continue 834 | else: 835 | if pc(f) == '{': 836 | l = allreplace(nl(f)) 837 | r = re.compile(r'(?= 1: 844 | g[0] = br(g[0]) 845 | 846 | if len(g) in (0, 1): # info block. 847 | out(f.outf, f.conf['infoblock']) 848 | infoblock = True 849 | 850 | if len(g) == 1: # info block. 851 | hb(f.outf, f.conf['blocktitle'], g[0]) 852 | 853 | out(f.outf, f.conf['infoblockcontent']) 854 | 855 | elif len(g) == 2: 856 | codeblock(f, g) 857 | 858 | elif len(g) >= 4 and g[1] == 'img_left': 859 | # handles 860 | # {}{img_left}{source}{alttext}{width}{height}{linktarget}. 861 | g += ['']*(7 - len(g)) 862 | 863 | if g[4].isdigit(): 864 | g[4] += 'px' 865 | 866 | if g[5].isdigit(): 867 | g[5] += 'px' 868 | 869 | out(f.outf, '\n
    \n') 870 | if g[6]: 871 | out(f.outf, '' % g[6]) 872 | out(f.outf, '%s') 879 | if g[6]: 880 | out(f.outf, '') 881 | out(f.outf, ' ') 882 | imgblock = True 883 | 884 | else: 885 | raise JandalError("couldn't handle block", linenum) 886 | 887 | else: 888 | s = br(np(f)) 889 | if s: 890 | hb(f.outf, '

    |

    \n', s) 891 | 892 | if footer: 893 | s = time.strftime('%Y-%m-%d %H:%M:%S %Z', time.localtime(time.time())) 894 | out(f.outf, f.conf['footerstart']) 895 | hb(f.outf, f.conf['lastupdated'], s) 896 | out(f.outf, f.conf['footerend']) 897 | 898 | if menu: 899 | out(f.outf, f.conf['menulastbit']) 900 | else: 901 | out(f.outf, f.conf['nomenulastbit']) 902 | 903 | out(f.outf, f.conf['bodyend']) 904 | 905 | if f.outf is not sys.stdout: 906 | f.outf.close() 907 | 908 | def main(): 909 | if len(sys.argv) == 1 or sys.argv[1] in ('--help', '-h'): 910 | showhelp() 911 | raise SystemExit 912 | if sys.argv[1] == '--show-config': 913 | print standardconf() 914 | raise SystemExit 915 | 916 | outoverride = False 917 | confoverride = False 918 | outname = None 919 | confnames = [] 920 | for i in range(1, len(sys.argv), 2): 921 | if sys.argv[i] == '-o': 922 | if outoverride: 923 | raise RuntimeError("only one output file / directory, please") 924 | outname = sys.argv[i+1] 925 | outoverride = True 926 | elif sys.argv[i] == '-c': 927 | if confoverride: 928 | raise RuntimeError("only one config file, please") 929 | confnames.append(sys.argv[i+1]) 930 | confoverride = True 931 | elif sys.argv[i].startswith('-'): 932 | raise RuntimeError('unrecognised argument %s, try --help' % sys.argv[i]) 933 | else: 934 | break 935 | 936 | conf = parseconf(confnames) 937 | 938 | innames = [] 939 | for j in range(i, len(sys.argv)): 940 | # First, if not a file and no dot, try opening .jemdoc. Otherwise, fall back 941 | # to just doing exactly as asked. 942 | inname = sys.argv[j] 943 | if not os.path.isfile(inname) and '.' not in inname: 944 | inname += '.jemdoc' 945 | 946 | innames.append(inname) 947 | 948 | if outname is not None and not os.path.isdir(outname) and len(innames) > 1: 949 | raise RuntimeError('cannot handle one outfile with multiple infiles') 950 | 951 | for inname in innames: 952 | if outname is None: 953 | thisout = re.sub(r'.jemdoc$', '', inname) + '.html' 954 | elif os.path.isdir(outname): 955 | # if directory, prepend directory to automatically generated name. 956 | thisout = outname + re.sub(r'.jemdoc$', '', inname) + '.html' 957 | else: 958 | thisout = outname 959 | 960 | infile = open(inname) 961 | outfile = open(thisout, 'w') 962 | 963 | f = controlstruct(infile, outfile, conf) 964 | procfile(f) 965 | 966 | # 967 | if __name__ == '__main__': 968 | main() 969 | -------------------------------------------------------------------------------- /www/dist/jemdoc.py-0.3.5: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | jemdoc: light markup, see http://jemdoc.jaboc.net/. 5 | 6 | version 0.3.5, 2007-11-26. 7 | """ 8 | 9 | # Copyright (C) 2007 Jacob Mattingley. 10 | # 11 | # This file is part of jemdoc. 12 | # 13 | # jemdoc is free software; you can redistribute it and/or modify it under the 14 | # terms of the GNU General Public License as published by the Free Software 15 | # Foundation; either version 3 of the License, or (at your option) any later 16 | # version. 17 | # 18 | # jemdoc is distributed in the hope that it will be useful, but WITHOUT ANY 19 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 20 | # A PARTICULAR PURPOSE. See the GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License along with 23 | # this program. If not, see . 24 | 25 | import sys 26 | import os 27 | import re 28 | import time 29 | import StringIO 30 | 31 | class controlstruct(object): 32 | def __init__(self, infile, outfile=None, conf=None, inname=None): 33 | self.inname = inname 34 | self.inf = infile 35 | self.outf = outfile 36 | self.conf = conf 37 | self.linenum = 0 38 | 39 | # better checking of arguments? 40 | def showhelp(): 41 | a = """Usage: jemdoc [OPTIONS] [SOURCEFILE] 42 | Produces html markup from a jemdoc SOURCEFILE. 43 | 44 | Most of the time you can use jemdoc without any additional flags. 45 | For example, typing 46 | 47 | jemdoc index.jemdoc 48 | 49 | will produce an index.html, using a default configuration. You can 50 | change the output file by using -o OUTFILE, for example 51 | 52 | jemdoc -o html/main.html index.jemdoc 53 | 54 | Some configuration options can be overridden by specifying a 55 | configuration file. You can use 56 | 57 | jemdoc --show-config 58 | 59 | to print a sample configuration file (which includes all of the 60 | default options). Any or all of the configuration [blocks] can be 61 | overwritten by including them in a configuration file, and running, 62 | for example, 63 | 64 | jemdoc -c mywebsite.conf index.jemdoc 65 | 66 | See http://jemdoc.jaboc.net/ for more details. 67 | """ 68 | b = '' 69 | for l in a.splitlines(True): 70 | if l.startswith(' '*4): 71 | b += l[4:] 72 | else: 73 | b += l 74 | 75 | print b 76 | 77 | def standardconf(): 78 | a = """[firstbit] 79 | 81 | 82 | 83 | 84 | 85 | 86 | [defaultcss] 87 | 88 | 89 | [windowtitle] 90 | # used in header for window title. 91 | | 92 | 93 | [doctitle] 94 | # used at top of document. 95 |
    96 |

    |

    97 | 98 | [subtitle] 99 |
    |
    100 | 101 | [doctitleend] 102 |
    103 | 104 | [bodystart] 105 | 106 | 107 | 108 | [menustart] 109 | 110 | 111 | 115 | 136 | 137 |
    112 | 113 | [menuend] 114 | 116 |
    117 | 118 | [menucategory] 119 | 120 | 121 | [menuitem] 122 | 123 | 124 | [currentmenuitem] 125 | 126 | 127 | [nomenu] 128 |
    129 | 130 | [css] 131 | 132 | 133 | [menulastbit] 134 |
    135 |
    138 | 139 | [nomenulastbit] 140 | 141 | 142 | [bodyend] 143 | 144 | 145 | 146 | [infoblock] 147 |
    148 | 149 | [codeblock] 150 |
    151 | 152 | [blocktitle] 153 |
    |
    154 | 155 | [infoblockcontent] 156 |
    157 | 158 | [codeblockcontent] 159 |
     160 |     
     161 |     [codeblockend]
     162 |     
    163 | 164 | [codeblockcontenttt] 165 |
    166 | 167 | [codeblockendtt] 168 |
    169 | 170 | [infoblockend] 171 |
    172 | 173 | [footerstart] 174 | 180 | 181 | [lastupdated] 182 | Page generated |, by jemdoc. 183 | 184 | [sourcelink] 185 | (source) 186 | 187 | """ 188 | b = '' 189 | for l in a.splitlines(True): 190 | if l.startswith(' '): 191 | b += l[4:] 192 | else: 193 | b += l 194 | 195 | return b 196 | 197 | class JandalError(Exception): 198 | pass 199 | 200 | def raisejandal(msg, line=0): 201 | if line == 0: 202 | s = "%s" % msg 203 | else: 204 | s = "line %d: %s" % (line, msg) 205 | raise JandalError(s) 206 | 207 | def readnoncomment(f): 208 | l = f.readline() 209 | if l == '': 210 | return l 211 | elif l[0] == '#': # jem: be a little more generous with the comments we accept? 212 | return readnoncomment(f) 213 | else: 214 | return l.rstrip() + '\n' # leave just one \n and no spaces etc. 215 | 216 | def parseconf(cns): 217 | syntax = {} 218 | warn = False # jem. make configurable? 219 | # manually add the defaults as a file handle. 220 | fs = [StringIO.StringIO(standardconf())] 221 | for sname in cns: 222 | fs.append(open(sname)) 223 | 224 | for f in fs: 225 | while pc(controlstruct(f)) != '': 226 | l = readnoncomment(f) 227 | r = re.match(r'\[(.*)\]\n', l) 228 | 229 | if r: 230 | tag = r.group(1) 231 | 232 | s = '' 233 | l = readnoncomment(f) 234 | while l not in ('\n', ''): 235 | s += l 236 | l = readnoncomment(f) 237 | 238 | syntax[tag] = s 239 | 240 | f.close() 241 | 242 | return syntax 243 | 244 | def insertmenuitems(f, mname, current, prefix): 245 | m = open(mname) 246 | while pc(controlstruct(m)) != '': 247 | l = readnoncomment(m) 248 | l = l.strip() 249 | if l == '': 250 | continue 251 | 252 | r = re.match(r'\s*(.*?)\s*\[(.*)\]', l) 253 | 254 | if r: # then we have a link. 255 | link = r.group(2) 256 | # Don't use prefix if we have an absolute link. 257 | if '://' not in r.group(2): 258 | link = prefix + allreplace(link) 259 | 260 | if r.group(2) == current: 261 | hb(f.outf, f.conf['currentmenuitem'], link, br(r.group(1))) 262 | else: 263 | hb(f.outf, f.conf['menuitem'], link, br(r.group(1))) 264 | 265 | else: # menu category. 266 | hb(f.outf, f.conf['menucategory'], br(l)) 267 | 268 | m.close() 269 | 270 | def out(f, s): 271 | f.write(s) 272 | 273 | def hb(f, tag, content1, content2=None): 274 | """Writes out a halfblock (hb).""" 275 | if content2 is None: 276 | out(f, re.sub(r'\|', content1, tag)) 277 | else: 278 | r = re.sub(r'\|1', content1, tag) 279 | r = re.sub(r'\|2', content2, r) 280 | out(f, r) 281 | 282 | def pc(f, ditchcomments=True): 283 | """Peeks at next character in the file.""" 284 | # Should only be used to look at the first character of a new line. 285 | c = f.inf.read(1) 286 | if c: # only undo forward movement if we're not at the end. 287 | #if c == '#': # interpret comment lines as blank. 288 | # return '\n' 289 | if ditchcomments and c == '#': 290 | nl(f) 291 | 292 | if c in ' \t': 293 | return pc(f) 294 | 295 | f.inf.seek(-1, 1) 296 | 297 | return c 298 | 299 | def nl(f, withcount=False, codemode=False): 300 | """Get input file line.""" 301 | s = f.inf.readline() 302 | f.linenum += 1 303 | if not codemode: 304 | # remove any special characters - assume they were checked by pc() 305 | # before we got here. 306 | # remove any trailing comments. 307 | s = s.lstrip(' \t') 308 | s = re.sub(r'\s*(?&$%\.~[\]-]""", r'\\\g<0>', s) 354 | else: 355 | return re.sub(r"""[\\*/+"'<>&$\.~[\]-]""", r'\\\g<0>', s) 356 | 357 | def replacequoted(b): 358 | """Quotes {{raw html}} sections. Insert a backslash right before the end 359 | with &bs;, an illegal html character.""" 360 | r = re.compile(r'\{\{(.*?)\}\}', re.M + re.S) 361 | m = r.search(b) 362 | while m: 363 | qb = quote(m.group(1), True) 364 | 365 | b = b[:m.start()] + qb + b[m.end():] 366 | 367 | m = r.search(b, m.start()) 368 | 369 | r = re.compile(r'(?' % " ".join(bits) + b[m.end():] 416 | 417 | m = r.search(b, m.start()) 418 | 419 | return b 420 | 421 | def replacelinks(b): 422 | # works with [link.html new link style]. 423 | r = re.compile(r'(?%s<\/a>' % (link, linkname) + b[m.end():] 442 | 443 | m = r.search(b, m.start()) 444 | 445 | return b 446 | 447 | def br(b): 448 | """Does simple text replacements on a block of text. ('block replacements')""" 449 | # Deal with literal backspaces. 450 | b = re.sub(r'\\\\', 'jemLITerl33talBS', b) 451 | 452 | # Deal with {{html embedding}}. 453 | b = replacequoted(b) 454 | 455 | b = allreplace(b) 456 | 457 | # First do the URL thing. 458 | b = b.lstrip('-. \t') # remove leading spaces, tabs, dashes, dots. 459 | b = replaceimages(b) 460 | b = replacelinks(b) 461 | 462 | # Deal with /italics/ first because the '/' in other tags would otherwise 463 | # interfere. 464 | r = re.compile(r'(?\1', b) 466 | 467 | # Deal with *bold*. 468 | r = re.compile(r'(?\1', b) 470 | 471 | # Deal with +monospace+. 472 | r = re.compile(r'(?\1', b) 474 | 475 | # Deal with "double quotes". 476 | r = re.compile(r'(?', b) 514 | 515 | ## Deal with zero width \_. 516 | #r = re.compile(r"(?", re.M + re.S) 533 | b = re.sub(r, r'>', b) 534 | 535 | r = re.compile(r"(?\1', l) 546 | 547 | if l.startswith('>>>'): 548 | hb(f, '|\n', l) 549 | else: 550 | out(f, l + '\n') 551 | 552 | def putbsbs(l): 553 | for i in range(len(l)): 554 | l[i] = '\\b' + l[i] + '\\b' 555 | 556 | return l 557 | 558 | def gethl(lang): 559 | # disable comments by default, by choosing unlikely regex. 560 | d = {'statement':[], 'commentstart':'######%%%%%', 'operator':[], 'builtin':[], 561 | 'error':[], 'strings':False} 562 | if lang in ('py', 'python'): 563 | d['statement'] = putbsbs(['break', 'continue', 'del', 'except', 'exec', 564 | 'finally', 'pass', 'print', 'raise', 'return', 565 | 'try', 'with', 'global', 'assert', 'lambda', 566 | 'yield', 'def', 'class', 'for', 'while', 'if', 567 | 'elif', 'else', 'import', 'from', 'as']) 568 | d['operator'] = putbsbs(['and', 'in', 'is', 'not', 'or']) 569 | d['builtin'] = putbsbs(['True', 'False', 'set', 'open', 'frozenset', 570 | 'enumerate', 'object', 'hasattr', 'getattr', 571 | 'filter', 'eval', 'zip', 'vars', 'unicode', 572 | 'type', 'str', 'repr', 'round']) 573 | d['error'] = putbsbs(['\w*Error',]) 574 | d['commentstart'] = '#' 575 | d['strings'] = True 576 | elif lang == 'sh': 577 | d['statement'] = putbsbs(['cd', 'ls', 'sudo']) 578 | d['operator'] = ['>'] 579 | d['builtin'] = putbsbs(['curl', 'wget', '(?|\n', allreplace(l)) 590 | else: 591 | l = allreplace(l) 592 | # handle strings. 593 | if hl['strings']: 594 | r = re.compile(r'(".*?")') 595 | l = r.sub(r'\1', l) 596 | r = re.compile(r"('.*?')") 597 | l = r.sub(r'\1', l) 598 | 599 | # handle comments. 600 | r = re.compile(hl['commentstart']) 601 | l = r.sub(r'\1', l) 602 | 603 | if hl['statement']: 604 | r = re.compile('(' + '|'.join(hl['statement']) + ')') 605 | l = r.sub(r'\1', l) 606 | 607 | if hl['operator']: 608 | r = re.compile('(' + '|'.join(hl['operator']) + ')') 609 | l = r.sub(r'\1', l) 610 | 611 | if hl['builtin']: 612 | r = re.compile('(' + '|'.join(hl['builtin']) + ')') 613 | l = r.sub(r'\1', l) 614 | 615 | if hl['error']: 616 | r = re.compile('(' + '|'.join(hl['error']) + ')') 617 | l = r.sub(r'\1', l) 618 | 619 | l = re.sub('CLASS', 'class', l) 620 | 621 | out(f, l + '\n') 622 | 623 | def dashlist(f): 624 | level = 0 625 | 626 | while pc(f) == '-': 627 | (s, newlevel) = np(f, True) 628 | 629 | # first adjust list number as appropriate. 630 | if newlevel > level: 631 | for i in range(newlevel - level): 632 | if newlevel > 1: 633 | out(f.outf, '\n') 634 | out(f.outf, '
      \n
    • ') 635 | elif newlevel < level: 636 | for i in range(level - newlevel): 637 | out(f.outf, '
    • \n
    \n
  • ') 638 | else: 639 | out(f.outf, '
  • \n
  • ') 640 | 641 | out(f.outf, br(s)) 642 | level = newlevel 643 | 644 | for i in range(level): 645 | out(f.outf, '
  • \n\n') 646 | 647 | def dotlist(f): 648 | level = 0 649 | 650 | while pc(f) == '.': 651 | (s, newlevel) = np(f, True) 652 | 653 | # first adjust list number as appropriate. 654 | if newlevel > level: 655 | for i in range(newlevel - level): 656 | if newlevel > 1: 657 | out(f.outf, '\n') 658 | out(f.outf, '
      \n
    1. ') 659 | elif newlevel < level: 660 | for i in range(level - newlevel): 661 | out(f.outf, '
    2. \n
    \n
  • ') 662 | else: 663 | out(f.outf, '
  • \n
  • ') 664 | 665 | out(f.outf, br(s)) 666 | level = newlevel 667 | 668 | for i in range(level): 669 | out(f.outf, '
  • \n\n') 670 | 671 | def colonlist(f): 672 | out(f.outf, '
    \n') 673 | while pc(f) == ':': 674 | s = np(f) 675 | r = re.compile(r'\s*{(.*?)(?|\n', br(defpart)) 686 | hb(f.outf, '
    |
    \n', br(rest)) 687 | 688 | out(f.outf, '
    \n') 689 | 690 | def codeblock(f, g): 691 | if g[1] == 'raw': 692 | raw = True 693 | else: 694 | raw = False 695 | out(f.outf, f.conf['codeblock']) 696 | if g[0]: 697 | hb(f.outf, f.conf['blocktitle'], g[0]) 698 | if g[1] == 'jemdoctt': 699 | out(f.outf, f.conf['codeblockcontenttt']) 700 | else: 701 | out(f.outf, f.conf['codeblockcontent']) 702 | 703 | # Now we are handling code. 704 | # Handle \~ and ~ differently. 705 | while 1: # wait for EOF. 706 | l = nl(f, codemode=True) 707 | if not l: 708 | break 709 | elif l.startswith('~'): 710 | break 711 | elif l.startswith('\\~'): 712 | l = l[1:] 713 | elif l.startswith('\\{'): 714 | l = l[1:] 715 | 716 | # jem revise pyint out of the picture. 717 | if g[1] == 'pyint': 718 | pyint(f.outf, l) 719 | else: 720 | if raw: 721 | out(f.outf, l) 722 | elif g[1] == 'jemdoctt': 723 | # doing this more nicely needs python 2.5. 724 | for x in ('#', '~', '>>>', '\~', '{'): 725 | if str(l).lstrip().startswith(x): 726 | out(f.outf, '
    ')
     727 |                         out(f.outf, l + '
    ') 728 | break 729 | else: 730 | for x in (':', '.', '-'): 731 | if str(l).lstrip().startswith(x): 732 | out(f.outf, '
    ' + prependnbsps(l)) 733 | break 734 | else: 735 | out(f.outf, l) 736 | else: 737 | language(f.outf, l, gethl(g[1])) 738 | 739 | if not raw: 740 | if g[1] == 'jemdoctt': 741 | out(f.outf, f.conf['codeblockendtt']) 742 | else: 743 | out(f.outf, f.conf['codeblockend']) 744 | 745 | def prependnbsps(l): 746 | g = re.search('(^ *)(.*)', l).groups() 747 | return g[0].replace(' ', ' ') + g[1] 748 | 749 | def procfile(f): 750 | linenum = 0 751 | 752 | menu = None 753 | showsourcelink = False 754 | showlastupdated = True 755 | nodefaultcss = False 756 | css = [] 757 | while pc(f, False) == '#': 758 | l = f.inf.readline() 759 | linenum += 1 760 | if l.startswith('# jemdoc:'): 761 | l = l[len('# jemdoc:'):] 762 | a = l.split(',') 763 | # jem only handle one argument for now. 764 | for b in a: 765 | b = b.strip() 766 | if b.startswith('menu'): 767 | sidemenu = True 768 | r = re.compile(r'(? 3 or len(g) < 2: 771 | raise SyntaxError('sidemenu error on line %d' % linenum) 772 | 773 | if len(g) == 2: 774 | menu = (f, g[0], g[1], '') 775 | else: 776 | menu = (f, g[0], g[1], g[2]) 777 | 778 | elif b.startswith('nodate'): 779 | showlastupdated = False 780 | 781 | elif b.startswith('showsource'): 782 | showsourcelink = True 783 | 784 | elif b.startswith('nodefaultcss'): 785 | nodefaultcss = True 786 | 787 | elif b.startswith('addcss'): 788 | r = re.compile(r'(?)|( ) *', ' ', t) 809 | hb(f.outf, f.conf['windowtitle'], u) 810 | out(f.outf, f.conf['bodystart']) 811 | 812 | else: 813 | out(f.outf, f.conf['bodystart']) 814 | t = None 815 | 816 | if menu: 817 | out(f.outf, f.conf['menustart']) 818 | insertmenuitems(*menu) 819 | out(f.outf, f.conf['menuend']) 820 | else: 821 | out(f.outf, f.conf['nomenu']) 822 | 823 | if t is not None: 824 | hb(f.outf, f.conf['doctitle'], t) 825 | 826 | # Look for a subtitle. 827 | if pc(f) != '\n': 828 | hb(f.outf, f.conf['subtitle'], br(np(f))) 829 | 830 | hb(f.outf, f.conf['doctitleend'], t) 831 | 832 | infoblock = False 833 | imgblock = False 834 | while 1: # wait for EOF. 835 | p = pc(f) 836 | 837 | if p == '': 838 | break 839 | 840 | # look for lists. 841 | elif p == '-': 842 | dashlist(f) 843 | 844 | elif p == '.': 845 | dotlist(f) 846 | 847 | elif p == ':': 848 | colonlist(f) 849 | 850 | # look for titles. 851 | elif p == '=': 852 | (s, c) = nl(f, True) 853 | # trim trailing \n. 854 | s = s[:-1] 855 | hb(f.outf, '|\n' % (c, c), br(s)) 856 | 857 | # look for comments. 858 | elif p == '#': 859 | nl(f) 860 | 861 | elif p == '\n': 862 | nl(f) 863 | 864 | # look for blocks. 865 | elif p == '~': 866 | nl(f) 867 | if infoblock: 868 | out(f.outf, f.conf['infoblockend']) 869 | infoblock = False 870 | nl(f) 871 | continue 872 | elif imgblock: 873 | out(f.outf, '
    \n') 874 | imgblock = False 875 | nl(f) 876 | continue 877 | else: 878 | if pc(f) == '{': 879 | l = allreplace(nl(f)) 880 | r = re.compile(r'(?= 1: 887 | g[0] = br(g[0]) 888 | 889 | if len(g) in (0, 1): # info block. 890 | out(f.outf, f.conf['infoblock']) 891 | infoblock = True 892 | 893 | if len(g) == 1: # info block. 894 | hb(f.outf, f.conf['blocktitle'], g[0]) 895 | 896 | out(f.outf, f.conf['infoblockcontent']) 897 | 898 | elif len(g) == 2: 899 | codeblock(f, g) 900 | 901 | elif len(g) >= 4 and g[1] == 'img_left': 902 | # handles 903 | # {}{img_left}{source}{alttext}{width}{height}{linktarget}. 904 | g += ['']*(7 - len(g)) 905 | 906 | if g[4].isdigit(): 907 | g[4] += 'px' 908 | 909 | if g[5].isdigit(): 910 | g[5] += 'px' 911 | 912 | out(f.outf, '\n
    \n') 913 | if g[6]: 914 | out(f.outf, '' % g[6]) 915 | out(f.outf, '%s') 922 | if g[6]: 923 | out(f.outf, '') 924 | out(f.outf, ' ') 925 | imgblock = True 926 | 927 | else: 928 | raise JandalError("couldn't handle block", linenum) 929 | 930 | else: 931 | s = br(np(f)) 932 | if s: 933 | hb(f.outf, '

    |

    \n', s) 934 | 935 | if showlastupdated or showsourcelink: 936 | out(f.outf, f.conf['footerstart']) 937 | if showlastupdated: 938 | s = time.strftime('%Y-%m-%d %H:%M:%S %Z', time.localtime(time.time())) 939 | hb(f.outf, f.conf['lastupdated'], s) 940 | if showsourcelink: 941 | hb(f.outf, f.conf['sourcelink'], f.inname) 942 | out(f.outf, f.conf['footerend']) 943 | 944 | if menu: 945 | out(f.outf, f.conf['menulastbit']) 946 | else: 947 | out(f.outf, f.conf['nomenulastbit']) 948 | 949 | out(f.outf, f.conf['bodyend']) 950 | 951 | if f.outf is not sys.stdout: 952 | f.outf.close() 953 | 954 | def main(): 955 | if len(sys.argv) == 1 or sys.argv[1] in ('--help', '-h'): 956 | showhelp() 957 | raise SystemExit 958 | if sys.argv[1] == '--show-config': 959 | print standardconf() 960 | raise SystemExit 961 | 962 | outoverride = False 963 | confoverride = False 964 | outname = None 965 | confnames = [] 966 | for i in range(1, len(sys.argv), 2): 967 | if sys.argv[i] == '-o': 968 | if outoverride: 969 | raise RuntimeError("only one output file / directory, please") 970 | outname = sys.argv[i+1] 971 | outoverride = True 972 | elif sys.argv[i] == '-c': 973 | if confoverride: 974 | raise RuntimeError("only one config file, please") 975 | confnames.append(sys.argv[i+1]) 976 | confoverride = True 977 | elif sys.argv[i].startswith('-'): 978 | raise RuntimeError('unrecognised argument %s, try --help' % sys.argv[i]) 979 | else: 980 | break 981 | 982 | conf = parseconf(confnames) 983 | 984 | innames = [] 985 | for j in range(i, len(sys.argv)): 986 | # First, if not a file and no dot, try opening .jemdoc. Otherwise, fall back 987 | # to just doing exactly as asked. 988 | inname = sys.argv[j] 989 | if not os.path.isfile(inname) and '.' not in inname: 990 | inname += '.jemdoc' 991 | 992 | innames.append(inname) 993 | 994 | if outname is not None and not os.path.isdir(outname) and len(innames) > 1: 995 | raise RuntimeError('cannot handle one outfile with multiple infiles') 996 | 997 | for inname in innames: 998 | if outname is None: 999 | thisout = re.sub(r'.jemdoc$', '', inname) + '.html' 1000 | elif os.path.isdir(outname): 1001 | # if directory, prepend directory to automatically generated name. 1002 | thisout = outname + re.sub(r'.jemdoc$', '', inname) + '.html' 1003 | else: 1004 | thisout = outname 1005 | 1006 | infile = open(inname) 1007 | outfile = open(thisout, 'w') 1008 | 1009 | f = controlstruct(infile, outfile, conf, inname) 1010 | procfile(f) 1011 | 1012 | # 1013 | if __name__ == '__main__': 1014 | main() 1015 | -------------------------------------------------------------------------------- /www/dist/jemdoc.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file 2 | " Language: jemdoc 3 | " Author: Jacob Mattingley (inspired by 4 | " Stuart Rackham's asciidoc). 5 | " Last Change: jemdoc 0.1.1 6 | " URL: http://jaboc.net/ 7 | " Licence: GPL (http://www.gnu.org) 8 | " Remarks: Vim 6 or greater 9 | " Limitations: See 'Appendix J: Vim Syntax Highlighter' in the AsciiDoc 'User 10 | " Guide'. 11 | 12 | "if exists("b:current_syntax") 13 | " finish 14 | "endif 15 | 16 | syn clear 17 | syn sync fromstart " change this if it gets slow. 18 | syn sync linebreaks=1 19 | 20 | " Run :help syn-priority to review syntax matching priority. 21 | " 22 | syn keyword jemdocToDo TODO FIXME XXX ZZZ 23 | syn match jemdocQuotedCharError /\\./ 24 | syn match jemdocQuotedChar /\\[[\]\\\*{}\/\.\-\+"=~np#%RC`'\$%]/ 25 | syn match jemdocListBullet /^\s*[-.:]\+\s/ 26 | syn match jemdocCommentLine "\\\@jemdoc.py}} 6 | (+v0.7.3+). You can also download this [dist/jemdoc.css example css 7 | file] to get you started. You can easily modify the css to adjust colours, fonts 8 | and general layout elements to your taste. 9 | 10 | You may like to %sudo cp jemdoc.py /usr/bin/jemdoc% 11 | so that you can just type 12 | +jemdoc+; alternatively, you could add a line to your %~/.bashrc% or 13 | similar like %alias jemdoc='/somepath/jemdoc.py'%. Remember to +chmod \+x+ your 14 | file to make it executable. 15 | 16 | jemdoc requires Python~2.3 or later. If you have a working installation of 17 | Python, you should be ready to go. This includes all Macs, and almost any 18 | fairly modern unix or linux. 19 | 20 | [dist/ Old versions] can still be found. Mahesh Shastry provides a package with 21 | [http://www.personal.psu.edu/mcs312/miscellany.html\#portablejemdoc 22 | jemdoc compiled for Windows]. 23 | 24 | == Where to next? 25 | Read about [using.html how to use jemdoc], check out an [example.html example 26 | page], then refer to the [cheatsheet.html cheat sheet] once you're underway. 27 | You could also download sample jemdoc code, like the [index.jemdoc index page] 28 | for this website. 29 | -------------------------------------------------------------------------------- /www/example.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{example.html}, addcss{example.css} 2 | = jemdoc -- example page 3 | 4 | ~~~ 5 | This page shows example jemdoc source and output side by side. (The spacing of 6 | the `page' on the left is consequently incorrect.) 7 | ~~~ 8 | 9 | ## jemdoc: start now. 10 | ~~~ 11 | {}{raw} 12 | 13 | 23 | 36 | 44 | 55 | 65 | 78 | 89 | 103 | 114 | 128 | 136 | 147 | 157 | 170 | 181 | 195 | 204 | 216 | 224 | 235 | 246 | 260 | 271 | 285 | 295 | 308 | 314 |
    14 | ~~~ 15 | # jemdoc: menu{MENU}{example.html} 16 | = jemdoc -- example page 17 | [http://stanford.edu/~jacobm/ Jacob Mattingley] 18 | ([jacobm@stanford.edu]) 19 | 20 | ~~~ 21 | {}{raw} 22 |   24 | ~~~ 25 | ~~~ 26 | {}{jemdoc} 27 | # jemdoc: menu{MENU}{example.html} 28 | = jemdoc -- example page 29 | [http://stanford.edu/~jacobm/ Jacob Mattingley] 30 | ([jacobm@stanford.edu]) 31 | 32 | ~~~ 33 | ~~~ 34 | {}{raw} 35 |
    37 | ~~~ 38 | If the first line of the file starts with +\# jemdoc+, special functions like 39 | [menu.html menus] will be used. 40 | 41 | ~~~ 42 | {}{raw} 43 |   45 | ~~~ 46 | ~~~ 47 | {}{jemdoc} 48 | If the first line of the file starts with +\# jemdoc+, special functions like 49 | [menu.html menus] will be used. 50 | 51 | ~~~ 52 | ~~~ 53 | {}{raw} 54 |
    56 | ~~~ 57 | == Example 58 | Here are some *text* /features/. I could [http://cvxmod.net/ link somewhere] or 59 | insert a raw link to another page like [download.html]. I could use 60 | +monospace+, too. 61 | 62 | ~~~ 63 | {}{raw} 64 |   66 | ~~~ 67 | ~~~ 68 | {}{jemdoc} 69 | == Example 70 | Here are some *text* /features/. I could [http://cvxmod.net/ link somewhere] or 71 | insert a raw link to another page like [download.html]. I could use 72 | +monospace+, too. 73 | 74 | ~~~ 75 | ~~~ 76 | {}{raw} 77 |
    79 | ~~~ 80 | I could write special characters like 81 | \#, \$ and \+ by just using a backslash 82 | (\\) in front of those characters. Or 83 | automatically detect an 84 | [jacobm@stanford.edu email address]. 85 | 86 | ~~~ 87 | {}{raw} 88 |   90 | ~~~ 91 | ~~~ 92 | {}{jemdoc} 93 | I could write special characters like 94 | \#, \$ and \+ by just using a backslash 95 | (\\) in front of those characters. Or 96 | automatically detect an 97 | [jacobm@stanford.edu email address]. 98 | 99 | ~~~ 100 | ~~~ 101 | {}{raw} 102 |
    104 | ~~~ 105 | ~~~ 106 | Save the file as +index.jemdoc+, say, and simply 107 | call +jemdoc index+ (after [download.html 108 | downloading jemdoc], of course). 109 | ~~~ 110 | 111 | ~~~ 112 | {}{raw} 113 |   115 | ~~~ 116 | ~~~ 117 | {}{jemdoc} 118 | \~~~ 119 | Save the file as +index.jemdoc+, say, and simply 120 | call +jemdoc index+ (after [download.html 121 | downloading jemdoc], of course). 122 | \~~~ 123 | 124 | ~~~ 125 | ~~~ 126 | {}{raw} 127 |
    129 | ~~~ 130 | == Next bit, next heading level two 131 | === Getting into level three now 132 | 133 | ~~~ 134 | {}{raw} 135 |   137 | ~~~ 138 | ~~~ 139 | {}{jemdoc} 140 | == Next bit, next heading level two 141 | === Getting into level three now 142 | 143 | ~~~ 144 | ~~~ 145 | {}{raw} 146 |
    148 | ~~~ 149 | Why not use a list 150 | - to explain the way you do lists? 151 | - to demonstrate how a line\n 152 | break might work? 153 | 154 | ~~~ 155 | {}{raw} 156 |   158 | ~~~ 159 | ~~~ 160 | {}{jemdoc} 161 | Why not use a list 162 | - to explain the way you do lists? 163 | - to demonstrate how a line\n 164 | break might work? 165 | 166 | ~~~ 167 | ~~~ 168 | {}{raw} 169 |
    171 | ~~~ 172 | Or perhaps a 173 | . Multilevel 174 | .. Numbered list 175 | .. Is more 176 | . Useful? 177 | 178 | ~~~ 179 | {}{raw} 180 |   182 | ~~~ 183 | ~~~ 184 | {}{jemdoc} 185 | Or perhaps a 186 | . Multilevel 187 | .. Numbered list 188 | .. Is more 189 | . Useful? 190 | 191 | ~~~ 192 | ~~~ 193 | {}{raw} 194 |
    196 | ~~~ 197 | : {Definition} lists, especially when there are 198 | many definitions 199 | : {Can be useful} for explaining things 200 | 201 | ~~~ 202 | {}{raw} 203 |   205 | ~~~ 206 | ~~~ 207 | {}{jemdoc} 208 | : {Definition} lists, especially when there are 209 | many definitions 210 | : {Can be useful} for explaining things 211 | 212 | ~~~ 213 | ~~~ 214 | {}{raw} 215 |
    217 | ~~~ 218 | == Finally, a few more blocks 219 | This `section' features "smart quotes". 220 | 221 | ~~~ 222 | {}{raw} 223 |   225 | ~~~ 226 | ~~~ 227 | {}{jemdoc} 228 | == Finally, a few more blocks 229 | This `section' features "smart quotes". 230 | 231 | ~~~ 232 | ~~~ 233 | {}{raw} 234 |
    236 | ~~~ 237 | ~~~ 238 | {Simple block} 239 | This is a simple text block, with a title. Notice how the previous line has only 240 | one set of braces (\{\}). 241 | ~~~ 242 | 243 | ~~~ 244 | {}{raw} 245 |   247 | ~~~ 248 | ~~~ 249 | {}{jemdoc} 250 | \~~~ 251 | {Simple block} 252 | This is a simple text block, with a title. Notice how the previous line has only 253 | one set of braces (\{\}). 254 | \~~~ 255 | 256 | ~~~ 257 | ~~~ 258 | {}{raw} 259 |
    261 | ~~~ 262 | ~~~ 263 | {Interactive Python listing}{pyint} 264 | >>> print 'Interactive Python code.' 265 | 'Interactive Python code.' 266 | ~~~ 267 | 268 | ~~~ 269 | {}{raw} 270 |   272 | ~~~ 273 | ~~~ 274 | {}{jemdoc} 275 | \~~~ 276 | {Interactive Python listing}{pyint} 277 | >>> print 'Interactive Python code.' 278 | 'Interactive Python code.' 279 | \~~~ 280 | 281 | ~~~ 282 | ~~~ 283 | {}{raw} 284 |
    286 | ~~~ 287 | ~~~ 288 | {}{} 289 | Plain code block with no title. 290 | ~~~ 291 | 292 | ~~~ 293 | {}{raw} 294 |   296 | ~~~ 297 | ~~~ 298 | {}{jemdoc} 299 | \~~~ 300 | {}{} 301 | Plain code block with no title. 302 | \~~~ 303 | 304 | ~~~ 305 | ~~~ 306 | {}{raw} 307 |
    309 | ~~~ 310 | You might need 2--3 different-sized dashes---they can be useful. Now we're done! 311 | ~~~ 312 | {}{raw} 313 |   315 | ~~~ 316 | ~~~ 317 | {}{jemdoc} 318 | You might need 2--3 different-sized dashes---they can be useful. Now we're done! 319 | ~~~ 320 | ~~~ 321 | {}{raw} 322 |
    323 | ~~~ 324 | -------------------------------------------------------------------------------- /www/exampleIN.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{example.html}, addcss{example.css} 2 | = jemdoc -- example page 3 | 4 | ~~~ 5 | This page shows example jemdoc source and output side by side. (The spacing of 6 | the `page' on the left is consequently incorrect.) 7 | ~~~ 8 | 9 | ## jemdoc: start now. 10 | # jemdoc: menu{MENU}{example.html} 11 | = jemdoc -- example page 12 | [http://stanford.edu/~jacobm/ Jacob Mattingley] 13 | ([jacobm@stanford.edu]) 14 | 15 | If the first line of the file starts with +\# jemdoc+, special functions like 16 | [menu.html menus] will be used. 17 | 18 | == Example 19 | Here are some *text* /features/. I could [http://cvxmod.net/ link somewhere] or 20 | insert a raw link to another page like [download.html]. I could use 21 | +monospace+, too. 22 | 23 | I could write special characters like 24 | \#, \$ and \+ by just using a backslash 25 | (\\) in front of those characters. Or 26 | automatically detect an 27 | [jacobm@stanford.edu email address]. 28 | 29 | ~~~ 30 | Save the file as +index.jemdoc+, say, and simply 31 | call +jemdoc index+ (after [download.html 32 | downloading jemdoc], of course). 33 | ~~~ 34 | 35 | == Next bit, next heading level two 36 | === Getting into level three now 37 | 38 | Why not use a list 39 | - to explain the way you do lists? 40 | - to demonstrate how a line\n 41 | break might work? 42 | 43 | Or perhaps a 44 | . Multilevel 45 | .. Numbered list 46 | .. Is more 47 | . Useful? 48 | 49 | : {Definition} lists, especially when there are 50 | many definitions 51 | : {Can be useful} for explaining things 52 | 53 | == Finally, a few more blocks 54 | This `section' features "smart quotes". 55 | 56 | ~~~ 57 | {Simple block} 58 | This is a simple text block, with a title. Notice how the previous line has only 59 | one set of braces (\{\}). 60 | ~~~ 61 | 62 | ~~~ 63 | {Interactive Python listing}{pyint} 64 | >>> print 'Interactive Python code.' 65 | 'Interactive Python code.' 66 | ~~~ 67 | 68 | ~~~ 69 | {}{} 70 | Plain code block with no title. 71 | ~~~ 72 | 73 | You might need 2--3 different-sized dashes---they can be useful. Now we're done! 74 | -------------------------------------------------------------------------------- /www/extra.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{extra.html} 2 | = jemdoc -- extra syntax elements 3 | 4 | These are some extended syntax options that may come in useful. 5 | 6 | == Left aligned image blocks 7 | As seen [http://stanford.edu/~jacobm here], for example, 8 | left-aligned image blocks place an image and allow ordinary jemdoc marked-up 9 | text to flow around the right-hand side. 10 | ~~~ 11 | {Left-aligned image block syntax}{} 12 | \~~~ 13 | \{}{img_left}{FILENAME.IMG}{alt text}{WIDTHpx}{HEIGHTpx}{IMGLINKTARGET} 14 | Ordinary jemdoc markup goes here. 15 | \~~~ 16 | ~~~ 17 | 18 | All arguments may be left blank, though you should specify an image filename, 19 | and alt text should be descriptive for reasons like 20 | [http://en.wikipedia.org/wiki/Wikipedia:Alternative_text_for_images those given 21 | by Wikipedia]. 22 | 23 | == Raw blocks 24 | When placing large amounts of raw html, you should use a raw block instead of 25 | +\{\{inline html escaping\}\}+. As well as cleaner syntax, raw blocks will avoid 26 | having +

    + tags in the wrong places. 27 | ~~~ 28 | {Raw block syntax}{} 29 | \~~~ 30 | \{}{raw} 31 | Any text here will be copied straight to the output file without processing. 32 | \~~~ 33 | ~~~ 34 | 35 | == Other character sets 36 | Here's a quick example of how to include text in a language with a different 37 | character set. 38 | 39 | To include Korean ({{}}한국말{{}}), 40 | use something like this: 41 | ~~~ 42 | {}{} 43 | {{}}한국말{{}} 44 | ~~~ 45 | 46 | ([jacobm@stanford.edu Let me know] if you need better support for your 47 | language.) 48 | 49 | == Including other files 50 | The line 51 | ~~~ 52 | {}{} 53 | \#include{otherfile.jemdoc} 54 | ~~~ 55 | will include the contents of +otherfile.jemdoc+ as if the contents were actually 56 | in the ordinary input file (that is, with full jemdoc substitutions). 57 | The line 58 | ~~~ 59 | {}{} 60 | \#includeraw{otherfile.html} 61 | ~~~ 62 | will copy the contents of +otherfile.html+ verbatim to the current position in 63 | the output file (that is, without any jemdoc substitutions). 64 | 65 | == Other packages 66 | - [http://www.polytekniker.dk/about.html Jacob Grunnet] has written 67 | [http://bibover.polytekniker.dk Bibover], a bibtex reference extension for 68 | jemdoc. 69 | - [http://www.seas.upenn.edu/~nghiem/ Truong Nghiem] has written a 70 | [http://www.seas.upenn.edu/~nghiem/software.html filter for exporting 71 | references from JabRef to 72 | jemdoc]. 73 | -------------------------------------------------------------------------------- /www/htmlchanges.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{htmlchanges.html} 2 | = jemdoc -- html changes 3 | 4 | jemdoc has a built-in default configuration. This configuration includes the 5 | particular html tags used when producing html. If you wish to adjust the html 6 | that jemdoc produces, you can provide a configuration file to override the 7 | built-in defaults. 8 | 9 | == Example html change 10 | Suppose you wanted to add [http://www.google.com/analytics/ Google 11 | Analytics] tracking to your website. That requires adding a short section of 12 | html before the ++ tag. 13 | 14 | First, find out which block needs to be changed by using 15 | 16 | ~~~ 17 | {}{} 18 | jemdoc --show-config 19 | ~~~ 20 | 21 | This prints the default html configuration. From this, the relevant 22 | configuration block (the one which includes the ++ tag) has a title 23 | +\[bodyend\]+, and looks like 24 | 25 | ~~~ 26 | {}{} 27 | [bodyend] 28 | 29 | 30 | ~~~ 31 | 32 | Create a new file +mysite.conf+, say, and put a new +\[bodyend\]+ block 33 | inside it. The new file looks like this: 34 | 35 | ~~~ 36 | {}{} 37 | [bodyend] 38 | 40 | 44 | 45 | 46 | ~~~ 47 | 48 | Include your new configuration file, with the +-c+ option ([using.html more 49 | details here]): 50 | ~~~ 51 | {}{} 52 | jemdoc -c mysite.conf index.jemdoc 53 | ~~~ 54 | 55 | This will pull in the new +\[bodyend\]+ block from +mysite.conf+, but otherwise 56 | work as before. 57 | -------------------------------------------------------------------------------- /www/index.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{index.html}, showsource 2 | = jemdoc -- light markup 3 | [http://stanford.edu/~jacobm/ Jacob Mattingley] ([jacobm@stanford.edu]) 4 | 5 | jemdoc is a light text-based markup language designed for creating 6 | websites. It takes a text file written with [example.html jemdoc markup], an 7 | optional configuration file and an optional menu file, and makes static websites 8 | that look something like this one, [http://cvxmod.net/ that one] or 9 | [http://www.stanford.edu/class/ee364a/ another one]. 10 | 11 | jemdoc was inspired by [http://www.methods.co.nz/asciidoc/ AsciiDoc], which is a 12 | text document format. AsciiDoc is great, and lots of the ideas from AsciiDoc are 13 | copied in jemdoc. The main differences are that jemdoc is simpler (you could say 14 | deliberately feature poor) and has more consistent syntax. 15 | 16 | [download.html Download jemdoc.] 17 | 18 | ~~~ 19 | Version +0.7.3+ was released on 2012-11-27 with some small bug fixes. 20 | See the [revision.html release notes]. 21 | ~~~ 22 | 23 | [https://github.com/jem/jemdoc Contribute to jemdoc on github.] 24 | 25 | == Goals 26 | - Simple, consistent syntax. 27 | - $\mbox{\LaTeX}$ [latex.html equation support]. 28 | - [tables.html Table support]. 29 | - Portability. The (single) jemdoc [http://www.python.org/ Python] file \+ 30 | single css file \+ your input file {{→}} html. 31 | - Based on [http://www.w3.org/Style/CSS/ CSS] so formatting specifics are 32 | independent of jemdoc. 33 | - Production of clean, 34 | [http://validator.w3.org/check/referer 35 | standards-compliant] [http://www.w3.org/TR/xhtml11/ XHTML 1.1]. 36 | - Minimal bells and whistles, but simple fallback to raw html if required. 37 | 38 | == License 39 | Copyright \C 2007--2012 Jacob Mattingley. 40 | 41 | jemdoc is free software; you can redistribute it and\/or modify it under the 42 | terms of the [http://www.gnu.org/licenses/gpl-3.0.html GNU General Public 43 | License] as published by the Free Software Foundation; either version 3 of the 44 | License, or (at your option) any later version. 45 | 46 | jemdoc is distributed in the hope that it will be useful, but WITHOUT ANY 47 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 48 | PARTICULAR PURPOSE. See the [http://www.gnu.org/licenses/gpl-3.0.html GNU 49 | General Public License] for more details. 50 | -------------------------------------------------------------------------------- /www/jemdoc.conf: -------------------------------------------------------------------------------- 1 | [defaultcss] 2 | 3 | 4 | 5 | [bodystart] 6 | 7 | 8 | 21 | -------------------------------------------------------------------------------- /www/latex.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{latex.html}, showsource 2 | = jemdoc -- latex equations 3 | 4 | jemdoc includes support for LaTeX equations. LaTeX source embedded in jemdoc 5 | files is processed by calling [http://www.latex-project.org/ +latex+] and 6 | [http://www.nongnu.org/dvipng/ +dvipng+] (which must both be available for this 7 | feature). Resulting PNG images are then placed on the web page. Equations are 8 | typeset using pure LaTeX. 9 | 10 | ~~~ 11 | jemdoc equation support relies on several pieces, any of which may break. No 12 | guarantees! Support may be limited. 13 | ~~~ 14 | 15 | == Inline equations 16 | The conjugate function $f^\star(y) = \sup_{x \in X}(y^Tx - f(x))$ appears here 17 | inline, and is in the variable $y$. Dollar signs (+\$+) surround the LaTeX 18 | equation in the jemdoc source. 19 | 20 | ~~~ 21 | {Syntax}{} 22 | The sample function $f^\star(y) = \sup_{x \in X}(y^Tx - f(x))$ 23 | appears here inline, and is in the variable $y$. 24 | ~~~ 25 | 26 | == Equations on separate lines 27 | To render an equation on its own line, use backslash-escaped round brackets 28 | (+\\(+ and +\\)+). For example, the identity 29 | \( 30 | (I + XY)^{-1} = I - X(I + YX)^{-1}Y 31 | \) 32 | is typeset on its own line. Yes, round brackets instead of square 33 | brackets---this is to avoid a conflict with ordinary square brackets that are 34 | escaped to avoid being a link. Sorry. 35 | 36 | ~~~ 37 | {Syntax}{} 38 | The identity 39 | \( 40 | (I \+ XY)^{-1} = I - X(I \+ YX)^{-1}Y 41 | \) 42 | is typeset on its own line. 43 | ~~~ 44 | 45 | Here, the line breaks (and other whitespace) are ignored. As always, the exact 46 | formatting details can be adjusted using CSS. 47 | 48 | == Notes 49 | - The baseline is carefully adjusted. The sequences m$m$m and y$y$y (+m\$m\$m+ 50 | and +y\$y\$y+), for example, should be neatly aligned (modulo bad browsers). 51 | - Definition by cases will work as expected, for example, $f(x)$, where 52 | \( 53 | f(x) = \left\{ 54 | \begin{array}{ll} 55 | 3, & x \leq 0 \\ 56 | 5, & x > 0. \\ 57 | \end{array}\right. 58 | \) 59 | (You can view the [latex.jemdoc jemdoc source] for this page.) 60 | - A random inequality might look like $3x + 2y^{4k + 6} \geq z$. 61 | - This page takes about 0.7 seconds to process on an average machine, including 62 | making all the equations from scratch. 63 | - There are several configuration options for equations. They are detailed on 64 | the [modelines.html modelines] page. 65 | -------------------------------------------------------------------------------- /www/menu.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{menu.html} 2 | = jemdoc -- add a menu 3 | 4 | jemdoc provides an easy way to add a `menu' like the one you see at the left of 5 | this page. You should create a file called +MENU+, for example, in the current 6 | directory. This website's +MENU+ looks something like this: 7 | 8 | ~~~ 9 | {}{} 10 | jemdoc 11 | home [index.html] 12 | download [download.html] 13 | revision history [revision.html] 14 | contact [contact.html] 15 | 16 | user's guide 17 | cheat sheet [cheatsheet.html] 18 | using [using.html] 19 | 20 | goodies 21 | add a menu [menu.html] 22 | other stuff [stuff.html] 23 | ~~~ 24 | 25 | To use the menu, start the first line of /each/ source file with a special 26 | comment like this one: 27 | 28 | ~~~ 29 | {}{} 30 | # jemdoc: menu{MENU}{index.html} 31 | ~~~ 32 | 33 | (Replace +index.html+ with the name of the relevant html page.) This will add a 34 | menu from the file called +MENU+, and underline and darken the menu entry 35 | corresponding to +index.html+. 36 | 37 | == Relative paths 38 | Optionally, include a +prefix+ which instructs jemdoc where the root of the menu 39 | is located relative to a particular page. 40 | ~~~ 41 | {}{} 42 | # jemdoc: menu{MENU}{pageinsubdir.html}{prefix} 43 | ~~~ 44 | 45 | == A note on menu widths 46 | jemdoc will create menu entries that do not wrap. If you have a particularly 47 | long title, or menu item, insert manual linebreaks using +\\++n+ in your 48 | MENU file. Multi-line menu items will (by default) have their second and 49 | subsequent lines slightly indented. 50 | -------------------------------------------------------------------------------- /www/modelines.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{modelines.html}, showsource, analytics{UA-2725246-3} 2 | = jemdoc -- modelines 3 | 4 | jemdoc includes a mechanism for specifying options inside a source file. It is 5 | called a /modeline/, after the same concept in [http://www.vim.org vim]. To use 6 | a modeline, start your jemdoc source file (on the first line) with the exact 7 | string +\#~jemdoc:+. Follow this string with one or more /modeline options/, 8 | separated with commas (and any amount of white space). 9 | 10 | Multiple modelines can be included if they are all at the beginning of the file, 11 | and start with the same string. The modeline can be omitted altogether. 12 | 13 | == Modeline options 14 | === General 15 | - +menu{MENUFILENAME}{CURRENTFILENAME}+\n 16 | Place a [menu.html menu] at the left of the page. 17 | - +nodefaultcss+\n 18 | Clear the list of CSS stylesheets included by the page. 19 | - +addcss{CSSSHEET}+\n 20 | Explicitly include an additional custom CSS stylesheet. 21 | - +addjs{scriptname}+\n 22 | Explicitly include the javascript file %scriptname.js%. 23 | - +fwtitle+\n 24 | Makes the page title /full width/ so the menu /and/ the body lie underneath 25 | the title. 26 | - +title{NEW TITLE}+\n 27 | Manually sets the titlebar text to +NEW TITLE+. 28 | 29 | === Extras 30 | - +analytics{ANALYTICS KEY}+\n 31 | Adds Google Analytics support. The key is typically in the form 32 | %UA-0000000-0%. Sign up for Google Analytics 33 | [http://www.google.com/analytics/ here]. 34 | 35 | === Footers 36 | - +notime+\n 37 | Withhold the time from the `Page generated' footer. 38 | - +nodate+\n 39 | Withhold the date and the time from the `Page generated' footer. 40 | - +showsource+\n 41 | Include a link, in the footer, to the jemdoc source. 42 | - +nofooter+\n 43 | Withhold the footer altogether (overrides the above options). 44 | 45 | === Equations 46 | - +noeqs+\n 47 | Disable LaTeX equation support. 48 | - +eqsize{SIZE}+\n 49 | Adjust the size of the equations (default +130+). 50 | - +eqdir{EQDIR}+\n 51 | Adjust the equation directory (default +eqs+). 52 | - +noeqcache+\n 53 | Disable equation caching. 54 | - +addpackage{LATEX_PACKAGE_NAME}+\n 55 | Includes support for +LATEX_PACKAGE_NAME+ when compiling the equations. 56 | 57 | == Examples 58 | ~~~ 59 | {This page}{} 60 | # jemdoc: menu{MENU}{modelines.html}, showsource 61 | ~~~ 62 | 63 | ~~~ 64 | {Use a different stylesheet altogether}{} 65 | # jemdoc: nodefaultcss, addcss{custom.css} 66 | ~~~ 67 | 68 | ~~~ 69 | {Combine various options}{} 70 | # jemdoc: nodefaultcss, addcss{custom.css}{another.css} 71 | # jemdoc: showsource, addcss{yetanother.css} 72 | ~~~ 73 | -------------------------------------------------------------------------------- /www/procexample.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | f = open('exampleIN.jemdoc') 4 | outf = open('example.jemdoc', 'w') 5 | 6 | l = f.readline() 7 | while not l.startswith('## jemdoc: start now.'): 8 | outf.write(l) 9 | l = f.readline() 10 | outf.write(l) 11 | 12 | outf.write('~~~\n{}{raw}\n\n') 13 | outf.write('\n') 28 | outf.write('\n\n') 44 | outf.write('
    \n~~~\n') 14 | s = '' 15 | t = '' 16 | l = f.readline() 17 | while l != '': 18 | s += l 19 | if l.startswith('~'): 20 | t += '\\' 21 | t += l 22 | 23 | if not l.strip(): 24 | # First write out real deal. 25 | outf.write(s) 26 | # Separate this from the source. 27 | outf.write('~~~\n{}{raw}\n \n~~~\n~~~\n{}{jemdoc}\n') 29 | # Output the stuff again, but raw. 30 | if not t.splitlines()[-1].strip(): 31 | t = t[:-1] + '\n' 32 | outf.write(t) 33 | # Separate this from the source. 34 | outf.write('~~~\n~~~\n{}{raw}\n
    \n~~~\n') 35 | s = '' 36 | t = '' 37 | 38 | l = f.readline() 39 | 40 | # First write out real deal. 41 | outf.write(s) 42 | # Separate this from the source. 43 | outf.write('~~~\n{}{raw}\n \n~~~\n~~~\n{}{jemdoc}\n') 45 | # Output the stuff again, but raw. 46 | #if not t.splitlines()[-1].strip(): 47 | # t = t[:-1] 48 | outf.write(t) 49 | # Separate this from the source and end the table. 50 | outf.write('~~~\n~~~\n{}{raw}\n
    \n~~~\n') 51 | 52 | f.close() 53 | outf.close() 54 | -------------------------------------------------------------------------------- /www/revision.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{revision.html} 2 | = jemdoc -- version and bug information 3 | 4 | == Open bugs 5 | - Including +\#+ within a +{\{quoted block}}+ will fail. Use instead a +raw+ 6 | block or place the +\#+ outside like in +{\{a~}}\\\#{\{2}}+ workaround. 7 | [jacobm@stanford.edu Tell me] if this becomes annoying. 8 | - You may require an extra line break at the end of your file if it ends with a 9 | raw quoted section like +{\{<\/asdasd>}\}+. 10 | - You may also require an extra line break at the end of your file if it ends 11 | with an equation. (And perhaps only on Windows.) 12 | 13 | == Revision details 14 | === Changes from +v0.7.2+ to +v0.7.3+ (2012-11-27) 15 | . Repaired the handling of whole-line equations written on a single line. 16 | . Enhanced the handling of the current menu link so it works across 17 | subdirectories. 18 | 19 | === Changes from +v0.7.1+ to +v0.7.2+ (2012-04-03) 20 | . Allowed HTML-escaped sequences in menu items. 21 | 22 | === Changes from +v0.7.0+ to +v0.7.1+ (2011-06-14) 23 | . Changed file opening mode to avoid Windows bugs where blank lines failed to 24 | separate sections properly. 25 | 26 | === Changes from +v0.6.8+ to +v0.7.0+ (2011-03-17) 27 | . Added +{filter_through}{external_prog}+ option for code blocks to filter 28 | through an external program. This can be used to customize syntax 29 | highlighting. 30 | . +img.eqwl+s from full-line tex equations are now enclosed in a +div.eqwl+. 31 | This permits alternative CSS styling for full-size tex equations. 32 | . Added an [modelines.html +analytics+] modeline for use with Google Analytics. 33 | . Improved C syntax highlighting. 34 | . Improved Matlab syntax highlighting. 35 | . Various bug fixes, especially for Windows. Thanks to Danilo Silva for helpful 36 | bug reports and fixes. 37 | 38 | === Changes from +v0.6.7+ to +v0.6.8+ (2010-03-22) 39 | . Added binary file identifiers to attempt a Windows fix for +IOError+s. 40 | 41 | === Changes from +v0.6.6+ to +v0.6.7+ (2009-11-17) 42 | . Added more syntax highlighing elements, including for +ruby+ and +c\+\++. 43 | . Added syntax highlighting support for inline comments. 44 | . Improved handling of the apostrophe. 45 | . Added support for the middot (\M), with %\M%. 46 | . Added preliminary support for environment variables (with syntax 47 | %!%+\$ENVIRON_VAR\$+%!%). 48 | 49 | === Changes from +v0.6.5+ to +v0.6.6+ (2009-07-11) 50 | . Fixed the labelling of table rows and columns. 51 | . Added some more syntax highlighing elements (mostly for +sh+). 52 | 53 | === Changes from +v0.6.4+ to +v0.6.5+ (2008-11-19) 54 | . Added some more syntax highlighting elements for Python (+py+). 55 | . Fixed some small bugs. 56 | 57 | === Changes from +v0.6.3+ to +v0.6.4+ (2008-08-06) 58 | . Added more syntax highlighting support. 59 | . Other minor program changes. 60 | . Slight tweaks to the style files. 61 | 62 | === Changes from +v0.6.2+ to +v0.6.3+ (2008-06-18) 63 | . Fixed a bug where double braces in equations caused strange pieces of html to 64 | appear. 65 | 66 | === Changes from +v0.6.1+ to +v0.6.2+ (2008-06-08) 67 | . Fixed a few bugs, including fixing invalid html for +imgtable+s. 68 | 69 | === Changes from +v0.6.0+ to +v0.6.1+ (2008-05-28) 70 | . Fixed minor regression with +img_left+ blocks having borders by accident. 71 | 72 | === Changes from +v0.5.4+ to +v0.6.0+ (2008-05-26) 73 | . Added support for tables. 74 | . Added better syntax highlighting support. 75 | . Added hair space around em dashes. 76 | 77 | === Changes from +v0.5.3+ to +v0.5.4+ (2008-04-14) 78 | . Added equation caching: equations are only regenerated if needed. 79 | 80 | === Changes from +v0.5.2+ to +v0.5.3+ (2008-03-29) 81 | . Percents work properly when inside links; square brackets work properly when 82 | inside percents. 83 | . Quoted hashes work inside URLs. 84 | . Updated +jemdoc.css+ to prevent blue boxes around LaTeX equations. 85 | 86 | === Changes from +v0.5.1+ to +v0.5.2+ (2008-01-24) 87 | . Fixed a bug with equation filenames colliding in edge cases. 88 | . Silenced unnecessary dvipng warnings. 89 | 90 | === Changes from +v0.5.0+ to +v0.5.1+ (2008-01-23) 91 | . Forward slashes instead of backslashes on Windows for equations. 92 | 93 | === Changes from +v0.4.0+ to +v0.5.0+ (2008-01-22) 94 | . Added support for LaTeX equations. 95 | . Added several new modeline options to support LaTeX equations. 96 | . Tweaked CSS for various improvements. 97 | . Fixed a bug with lists not nesting properly. 98 | . Added a +fwtitle+ modeline option for choosing a /full-width/ title. 99 | . Added a +nofooter+ modeline option to more easily turn off the footer. 100 | 101 | === Changes from +v0.3.6+ to +v0.4.0+ (2007-12-02) 102 | . Added new syntax items +\#include{FILE}+ and +\#includeraw{FILE}+. 103 | . Corrected various bugs in link handling. 104 | . Added a +title{Page title}+ modeline option. 105 | . Added a +notime+ modeline option. 106 | . Tweaked CSS for various improvements. 107 | 108 | === Changes from +v0.3.5+ to +0.3.6+ (2007-11-28) 109 | . Changed the way menus are laid out, preventing unwanted wrapping. 110 | . Improved the vim syntax highlighting file. 111 | . Added the command +\\p+ to create a manual paragraph break in lists. 112 | . Added +jemdoc -\-version+ as a command line option. 113 | 114 | === Changes from +v0.3.4+ to +v0.3.5+ (2007-11-26) 115 | . Added a +showsource+ modeline option. 116 | . Corrected a minor bug with whitespace appearing in the titles. 117 | 118 | === Changes from +v0.3.3+ to +v0.3.4+ (2007-11-17) 119 | . Corrected a (Windows) platform specific time-stamp issue. 120 | 121 | === Changes from +v0.3.0+ to +v0.3.3+ (2007-11-16) 122 | . Added support for image blocks. 123 | . Added support for raw blocks. 124 | . Fixed handling of ampersands (&). 125 | . Changed footer message to `Page generated ...' instead of `Last updated ...'. 126 | . Fixed handling of comments within lists. 127 | . Several other minor bug fixes. 128 | 129 | === Changes from +v0.2.0+ to +v0.3.0+ (2007-11-09) 130 | . Added per-file css specification. Use\n 131 | +\# jemdoc addcss{file1}{file2}.\.., +\n as the 132 | first line. To prevent loading the +\[defaultcss\]+ configuration section, 133 | use\n 134 | +\# jemdoc nodefaultcss, +. 135 | . Added +jemdoc filename+ as an implicit alternative for +jemdoc filename.jemdoc+. 136 | . Added the ability to process mutliple files, as in +jemdoc *.jemdoc+. 137 | . Added the syntax\n +\[img{width}{height}{alt text} img.jpg\]+\n for 138 | inserting pictures. The width, height, and alt text parameters are all 139 | optional. 140 | . Deprecated the +\$quoted tt\$+ syntax, replacing it with +\%quoted tt\%+. 141 | 142 | === Changes from +v0.1.0+ to +v0.2.0+ (2007-10-19) 143 | . Embedded default configuration file within jemdoc, to eliminate the need for a 144 | default configuration file. 145 | . Rearranged the arguments to +{{jemdoc [OPTIONS] [INFILE]}}+. 146 | . Added better formatting to document titles. 147 | . Added support for definintion lists via +{{: {item} definition}}+. 148 | . Added +\$quoted tt\$+ as an alias for +\+\{\{quoted tt\}\}\++. 149 | -------------------------------------------------------------------------------- /www/stuff.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{stuff.html} 2 | = jemdoc -- vim, make 3 | 4 | == Vim syntax highlighting 5 | Here is a vim syntax file {{jemdoc.vim}}. 7 | You should download it to 8 | +\~\/.vim\/syntax\/+. You may also need to add the following lines in your 9 | +\~\/.vimrc+: 10 | 11 | ~~~ 12 | {Additional +\~\/.vimrc+ lines}{} 13 | filetype plugin on 14 | augroup filetypedetect 15 | au! BufNewFile,BufRead *.jemdoc setf jemdoc 16 | augroup END 17 | 18 | " Last line is for proper wrapping of jemdoc lists, etc. 19 | autocmd Filetype jemdoc setlocal comments=:#,fb:-,fb:.,fb:--,fb:..,fb:\: 20 | ~~~ 21 | 22 | == Makefile 23 | Here's a small example of a {{Makefile}}. 25 | A listing of it follows. 26 | 27 | This file would be used as follows: 28 | - Edit +index.jemdoc+ and +otherpage.jemdoc+ at will. 29 | - Type +make+ in the same directory, and files +html\/index.html+ and 30 | +html\/otherpage.html+ will be updated as necessary. 31 | - Type +make update+ and your files will be copied to the server. 32 | - Type +make clean+ and old +html+ files in +html\/+ will be removed. 33 | 34 | Rinse and repeat. 35 | 36 | ~~~ 37 | {Makefile example}{} 38 | DOCS=index otherpage 39 | 40 | HDOCS=$(addsuffix .html, $(DOCS)) 41 | PHDOCS=$(addprefix html/, $(HDOCS)) 42 | 43 | .PHONY : docs 44 | docs : $(PHDOCS) 45 | 46 | .PHONY : update 47 | update : $(PHDOCS) 48 | @echo -n 'Copying to server...' 49 | # insert code for copying to server here. 50 | @echo ' done.' 51 | 52 | html/%.html : %.jemdoc MENU 53 | jemdoc -o $@ $< 54 | 55 | .PHONY : clean 56 | clean : 57 | -rm -f html/*.html 58 | ~~~ 59 | -------------------------------------------------------------------------------- /www/tables.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{tables.html}, showsource, addcss{table} 2 | = jemdoc -- tables 3 | 4 | jemdoc includes preliminary support for tables. 5 | 6 | ~~~ 7 | {Table syntax}{} 8 | \~~~ 9 | {}{table}{TABLENAME} 10 | first entry | another entry || 11 | as many rows | as you like || 12 | bottom row | last entry 13 | \~~~ 14 | ~~~ 15 | 16 | +TABLENAME+ should either be replaced with a name---which becomes the table's 17 | +css+ +id+---or be omitted. 18 | 19 | 20 | == Notes 21 | - There is no need to line up the +|+ symbols. Extra whitespace is ignored. 22 | - The last row does not need a terminating +||+. 23 | - Individual tables can be customised by replacing +TABLENAME+ with a unique 24 | name, and using custom css. For example, within 25 | a css file, +\#countries { background: gray; }+ will make the background of 26 | the +countries+ table gray. 27 | - Rows in a table are numbered sequentially for easy formatting with css. For 28 | example, to make the entries in the first row of a table called +countries+ 29 | bold, use +\#countries tr.r1 { font-weight: bold; }+. 30 | 31 | == Example 32 | 33 | ~~~ 34 | {}{table}{countries} 35 | country | population | people per square km || 36 | Canada | 33 million | 3.2 || 37 | {{中华人民共和国}}\n | 38 | 1300 million | 140 || 39 | Kingdom of Denmark | 5.5 million | 130 || 40 | New Zealand | 4.3 million | 15 || 41 | United States of America | 300 million | 31 42 | ~~~ 43 | -------------------------------------------------------------------------------- /www/using.jemdoc: -------------------------------------------------------------------------------- 1 | # jemdoc: menu{MENU}{using.html} 2 | = jemdoc -- running jemdoc 3 | 4 | Make sure 5 | [http://www.python.org/ Python] is installed, put jemdoc in your path somewhere, 6 | type in your file, and run 7 | 8 | ~~~ 9 | {}{} 10 | jemdoc index.jemdoc 11 | ~~~ 12 | 13 | This will use a default configuration for the html elements, and create an 14 | +index.html+. 15 | 16 | Even simpler, you can omit the extension, and jemdoc will still 17 | process the +index.jemdoc+ file, as in 18 | ~~~ 19 | {}{} 20 | jemdoc index 21 | ~~~ 22 | 23 | == CSS 24 | You will need to provide a [http://www.w3.org/Style/CSS/ CSS] file on your 25 | server. By default it should be called +jemdoc.css+. Here is an example 26 | [dist/jemdoc.css jemdoc.css] file: download it and place it in the same 27 | directory as your html files. (Or customize it, or start from scratch!) 28 | 29 | == Change the configuration 30 | To choose a different output file, use +-o+: 31 | 32 | ~~~ 33 | {}{} 34 | jemdoc -o html/index.html index 35 | ~~~ 36 | 37 | You can specify a different output directory with +-o+: 38 | ~~~ 39 | {}{} 40 | jemdoc -o html/ index 41 | ~~~ 42 | 43 | This will instead output to +html\/index.html+. 44 | 45 | To change the html configuration ([htmlchanges.html details here]), use +-c+: 46 | ~~~ 47 | {}{} 48 | jemdoc -c mysite.conf index 49 | ~~~ 50 | 51 | Command line options may be combined. For example, the following command will 52 | use +mysite.conf+, reading syntax from +index.jemdoc+ and outputting to 53 | +html\/index.html+: 54 | ~~~ 55 | {}{} 56 | jemdoc -c mysite.conf -o html/ index 57 | ~~~ 58 | 59 | == Other command line options 60 | To check which version of jemdoc you are using, run the command 61 | ~~~ 62 | {}{} 63 | jemdoc --version 64 | ~~~ 65 | 66 | To get simple command-line help, you can run +jemdoc+ without arguments, or 67 | ~~~ 68 | {}{} 69 | jemdoc --help 70 | ~~~ 71 | 72 | To show the html configuration ([htmlchanges.html details here]), run 73 | ~~~ 74 | {}{} 75 | jemdoc --show-config 76 | ~~~ 77 | 78 | --------------------------------------------------------------------------------