|
18 | 18 | import atexit |
19 | 19 | import collections |
20 | 20 | import glob |
| 21 | +import html |
21 | 22 | import itertools |
22 | 23 | import os |
23 | 24 | import platform |
@@ -63,15 +64,16 @@ def addboolarg(key,help,parser=parser,shortkey=None): |
63 | 64 | addboolarg('prc','Update 3D html.') |
64 | 65 | addboolarg('instructor','Create instructor solution manual.') |
65 | 66 | addboolarg('internet','Create interNet version (options x & w).',shortkey='n') |
66 | | -addboolarg('xml','Create xml version. (2 or 5 hours)'); # 120, 90, 107 |
67 | | -addboolarg('web','Convert xml version to html. (5 min)'); |
| 67 | +addboolarg('xml','Create xml version. (2 or 5 hours)') # 120, 90, 107 |
| 68 | +addboolarg('web','Convert xml version to html. (5 min)') |
68 | 69 | parser.add_argument('--standalonen',action='store_true', |
69 | 70 | help='Create interNet version for standalone.tex') |
70 | 71 | parser.add_argument('--standalonex',action='store_true', |
71 | 72 | help='Create xml version for standalone.tex') |
72 | 73 | parser.add_argument('--standalonew',action='store_true', |
73 | 74 | help='Convert xml version to html for standalone.tex') |
74 | | -addboolarg('todo','Update todo lists.'); |
| 75 | +addboolarg('todo','Update todo lists.') |
| 76 | +addboolarg('overview','Create overview file.') |
75 | 77 | addboolarg('quit','Write options.tex and quit.') |
76 | 78 | parser.add_argument('--spelling',action='store_true',help='Run spellcheck') |
77 | 79 | parser.add_argument('--justprint',action='store_true', |
@@ -158,6 +160,106 @@ def makefigs(): |
158 | 160 | finally: |
159 | 161 | os.chdir('..') |
160 | 162 |
|
| 163 | +labeltypes = ('definition','example','figure','keyidea','theorem') |
| 164 | +depths = { |
| 165 | + 'Calc': 0, |
| 166 | + 'C': 1, |
| 167 | + 'S': 2 |
| 168 | +} |
| 169 | + |
| 170 | +def get_depth(overview): |
| 171 | + for start,depth in depths.items(): |
| 172 | + if overview.startswith(start): |
| 173 | + return depth |
| 174 | + return 3 |
| 175 | + |
| 176 | +def create_overview(): |
| 177 | + overviewlist = shuffle_prereqs(overviewfromfile('Calculus.aux')) |
| 178 | + previous,previous_depth = None,-1 |
| 179 | + with open('overview.html','w+') as overviewhtml: |
| 180 | + overviewhtml.write('<!doctype html>\n' |
| 181 | + '<html lang="en-US">\n' |
| 182 | + ' <head>\n' |
| 183 | + ' <meta charset="utf-8">\n' |
| 184 | + ' <title>Calculus Overview</title>\n' |
| 185 | + ' <style>\n' |
| 186 | + ' li { list-style-type: none; }\n' |
| 187 | + ' ul ul { display: none; }\n' |
| 188 | + ' li input:checked ~ ul { display: block; }\n' |
| 189 | + ' .overviewitem { display: none; }\n' |
| 190 | + +'\n'.join(f' #{labeltype[0].upper()}:checked ~ ul .{labeltype[0].upper()} {{ display: block; }}' |
| 191 | + for labeltype in labeltypes ) |
| 192 | + +'\n </style>\n' |
| 193 | + ' </head>\n' |
| 194 | + ' <body>\n' |
| 195 | + ' <h1>Calculus Overview</h1>\n' |
| 196 | + +'\n'.join(f' <input type="checkbox" value="{labeltype}" id="{labeltype[0].upper()}" />' |
| 197 | + f'<label for="{labeltype[0].upper()}">{labeltype.title()}</label>' |
| 198 | + for labeltype in labeltypes) ) |
| 199 | + for overview in overviewlist: |
| 200 | + depth = get_depth(overview) |
| 201 | + if depth <= previous_depth: |
| 202 | + overviewhtml.write('</li>\n'+('</ul>\n</li>\n'*(previous_depth-depth))) |
| 203 | + else: #if previous_depth < depth: |
| 204 | + overviewhtml.write('<ul>\n'+('<li><input type="checkbox"><ul>\n'*(depth-previous_depth-1))) |
| 205 | + if depth == 3: |
| 206 | + overviewhtml.write(f'<li class="overviewitem {overview[0]}">\n{overview}') |
| 207 | + elif depth == 0: |
| 208 | + overviewhtml.write('<li>\n' |
| 209 | + f'<input type="checkbox" id="{overview.replace(" ","_")}">' |
| 210 | + f'<label for="{overview.replace(" ","_")}">{overview}</label>') |
| 211 | + else: |
| 212 | + overviewhtml.write('<li>\n' |
| 213 | + f'<input type="checkbox" id="{overview.split()[0]}">' |
| 214 | + f'<label for="{overview.split()[0]}">{overview}</label>') |
| 215 | + previous,previous_depth = overview,depth |
| 216 | + overviewhtml.write('</ul></li></ul></li></ul></li></ul></body></html>') |
| 217 | + |
| 218 | +def shuffle_prereqs(overviewlist): |
| 219 | + ret = [] |
| 220 | + delayqueue = [] |
| 221 | + while overviewlist: |
| 222 | + nextitem = overviewlist.pop(0) |
| 223 | + if 'Chapter Prerequisites' in nextitem: |
| 224 | + while not nextitem.startswith('C'): |
| 225 | + delayqueue.append(nextitem) |
| 226 | + nextitem = overviewlist.pop(0) |
| 227 | + ret.append(nextitem) |
| 228 | + if delayqueue: |
| 229 | + ret.extend(delayqueue) |
| 230 | + delayqueue = [] |
| 231 | + return ret |
| 232 | + |
| 233 | +def overviewfromfile(filename): |
| 234 | + with open(filename) as filein: |
| 235 | + overviewlist = [] |
| 236 | + for line in filein: |
| 237 | + linepieces = re.split(r'\s*(?:{|})\s*',line) |
| 238 | + # I'm not sure why ?: is needed. Without it, the { } show up in the matches |
| 239 | + if line.startswith(r'\@input{'): # } |
| 240 | + overviewlist.extend(overviewfromfile(linepieces[1])) |
| 241 | + if line.startswith(r'\@writefile{toc}{\contentsline {'): # } } |
| 242 | + if linepieces[4]=='part': |
| 243 | + # eg: \@writefile {toc} |
| 244 | + # { \contentsline {part}{Calculus I}{1}{part*.10}\protected@file@percent } |
| 245 | + overviewlist.append( f'{linepieces[6]}: p{linepieces[8]}' ) |
| 246 | + elif linepieces[4] in ('section','chapter') and 'numberline' in line: |
| 247 | + # eg: \@writefile {toc} |
| 248 | + # { \contentsline {section}{\numberline {8.7}Numerical Integration}{447}{section.8.7}\protected@file@percent } |
| 249 | + overviewlist.append( f'{linepieces[4][0].upper()}{linepieces[7]}: p{linepieces[10]}: {linepieces[8]}' ) |
| 250 | + if line.startswith(r'\newlabel{') and any( linepieces[-5].startswith(labeltype) for labeltype in labeltypes ): # } |
| 251 | + # eg: \newlabel {ex_der_num_approx} |
| 252 | + # { {2.1.3}{84}{Numerical Approximation of the Tangent Line}{example.2.1.3}{} } |
| 253 | + resplit = re.split(r'\s*(?:{|})\s*',line,maxsplit=8) # split again, with maxsplit |
| 254 | + rightsplit = [ piece.strip(' {') for piece in resplit[-1].rsplit('}',maxsplit=4) ] |
| 255 | + text = rightsplit[0] |
| 256 | + if text.endswith(r'\relax'): |
| 257 | + text = text.rstrip('relax').rstrip('\\') |
| 258 | + overviewlist.append( f'{rightsplit[1][0].upper()}{resplit[4]}: p{resplit[6]}: {html.escape(rightsplit[0])}' ) |
| 259 | + #elif line.startswith(r'\newlabel{'): |
| 260 | + # breakpoint() |
| 261 | + return overviewlist |
| 262 | + |
161 | 263 | Figure = collections.namedtuple('Figure',['num','file']) |
162 | 264 |
|
163 | 265 | def updateprc(): |
@@ -446,28 +548,26 @@ def writemisspellings(): |
446 | 548 | for word,count in runningTotal.most_common(10): |
447 | 549 | print(word+':',count,'time(s)',file=misspellings) |
448 | 550 |
|
| 551 | +option_func = { |
| 552 | + 'figures': makefigs, |
| 553 | + 'matrices': makematrices, |
| 554 | + 'todo': updatetodo, |
| 555 | + 'prc': updateprc, |
| 556 | + 'spelling': writemisspellings, |
| 557 | + 'overview': create_overview |
| 558 | +} |
| 559 | + |
449 | 560 | def compilewith(commands=False): |
450 | 561 | print('running:',commands) |
451 | 562 | #quit() |
452 | 563 | if commands: |
453 | 564 | args = parser.parse_args([''.join(commands)]) |
454 | 565 | else: |
455 | 566 | args = parser.parse_args() |
456 | | - if args.figures: |
457 | | - makefigs() |
458 | | - return |
459 | | - if args.matrices: |
460 | | - makematrices() |
461 | | - return |
462 | | - if args.todo: |
463 | | - updatetodo() |
464 | | - return |
465 | | - if args.prc: |
466 | | - updateprc() |
467 | | - return |
468 | | - if args.spelling: |
469 | | - writemisspellings() |
470 | | - return |
| 567 | + for option,func in option_func.items(): |
| 568 | + if getattr(args,option): |
| 569 | + func() |
| 570 | + return |
471 | 571 | if args.calculus == 4: |
472 | 572 | args.calculus = 0 |
473 | 573 | writeoptions(args) |
|
0 commit comments