#!/usr/bin/python3 # =============================================================== # convert MD file to HTML file # =============================================================== import os import re import sys import datetime as dt from markdown_my_lifo_queue import my_lifo_queue import markdown_start_end_web_page as wp REGX01 = re.compile(r"(__" r"|//" r"|\*\*" r"|\\\\$" r"|\\\\\s" r"|##" r"|#)") # ---- global flags --------------------------------------------- # ---- NODELETE true = output file is not deleted # ---- if an error occures # ---- HTMLFILEOUT true = output HTML file # ---- VERBOSE true = print "what am i doing now" # ---- messages NODELETE = True HTMLFILEOUT = True VERBOSE = False # --------------------------------------------------------------- # ---- terminate output file # --------------------------------------------------------------- def terminate_output(fout,outfile): if fout: fout.close() if not NODELETE: delete_file(outfile) # --------------------------------------------------------------- # ---- delete file # --------------------------------------------------------------- def delete_file(filename): if os.path.exists(filename): os.remove(filename) if VERBOSE: print(f'File {filename} deleted') else: if VERBOSE: print(f'File {filename} does not exist') # --------------------------------------------------------------- # ---- print list of tuples # --------------------------------------------------------------- def print_list(lst,title=None): if title is not None: print(title) print(f'list length is {len(lst)}') for tup in lst: print(tup) # --------------------------------------------------------------- # ---- print queue/stack # ---- This function is here because you may not be using # ---- 'my_lifo_queue'. Modify it to translate 'print_cue' # ---- to which ever queue/stack you are using. # --------------------------------------------------------------- def print_que(que,title=None): que.dump(title) # --------------------------------------------------------------- # ---- process line looking for md tokens # --------------------------------------------------------------- def process_line(line,lst): ##print(f'process_line({line})') while True: if VERBOSE: print() print(f'processing line "{line}"') ## --- end of line (no md tag found) if not line: lst.append((1,'')) return True # ---- search for md tag res = re.search(REGX01,line) if not res: lst.append((0,line)) return True # ---- extract info from search results ln = len(line) end = res.end() start = res.start() tag = res.groups()[0] if VERBOSE: print(f'ln={ln},start={start},end={end},tag="{tag}"') ## --- bold if tag == r'**': if ln > 2: lst.append((0,line[0:end-2])) lst.append((4,'bold')) ## --- italic elif tag == r'//': if ln > 2: lst.append((0,line[0:end-2])) lst.append((5,'italic')) ## --- underline elif tag == r'__': if ln > 2: lst.append((0,line[0:end-2])) lst.append((6,'underline')) ## --- h2 elif tag == r'##': lst.append((3,'H2')) lst.append((0,line[end:].strip())) lst.append((3,'H2')) return True ## --- h1 elif tag == r'#': lst.append((2,'H1')) lst.append((0,line[end:].strip())) lst.append((2,'H1')) return True ## --- line break elif tag == r'\\ ': lst.append((0,line[0:end-3])) lst.append((7,'br')) elif tag == r'\\': lst.append((0,line[0:end-2])) lst.append((7,'br')) break ## --- unknown tag else: print(f'internal error - unknown tag "{tag}"') print_list(lst) return False #---- make the line shorter skipping # ---- the stuff we have already seen line = line[end:] return True # --------------------------------------------------------------- # ---- process md file # --------------------------------------------------------------- def process_md_file(infile): ##print(f'process_file({infile})') lst = [] line_number = 1 with open(infile,'r') as fin: for line in fin: ## ---- remove leading/trailing spaces and \n ## ---- convert to raw string line = line.strip().strip('\n') # ---- process the text and md tags tf = process_line(line,lst) # ---- validate line processing if not tf: print(f'processing line {line_number} failed') print(f'line: "{line}"') print() sys.exit() # ---- increment line number line_number += 1 return lst # --------------------------------------------------------------- # ---- generate HTML code from the list of tokens # --------------------------------------------------------------- def generate_html_code(lst,outfile): ##print(f'generate_html_code({outfile})') ##print_list(lst,'---- tuple list ----') que = my_lifo_queue() if VERBOSE: print('======== generate HTML code ========') if HTMLFILEOUT: print(f'output file name is {outfile}') # ---- open output file? fout = None if HTMLFILEOUT: fout = open(outfile,'w') if VERBOSE: print(f'output file {outfile} opened') # ---- write start web page? if HTMLFILEOUT: mystyle='''\ <style> body { font-size: 1.2em; } </style>''' sw = wp.fstr(wp.start_of_web_page, {'pagetitle' :'MD Conversion', 'author' :'George of the Jungle', 'css1' :'style1.css', 'css2' :'style2.css', 'style' :mystyle, 'headertitle':'Converted from MD file'}) # ---- output start-of-web-page to HTML file if HTMLFILEOUT: fout.write(sw + '\n') # ---- print start web page if VERBOSE: print(sw) # ---- fill in the web page for tok in lst: state = tok[0] # ---- plain text if state == 0: if fout : fout.write(tok[1] + '\n') if VERBOSE: print(tok[1]) continue # ---- line break elif state == 7: if fout : fout.write('<br>' + '\n') if VERBOSE: print('<br>') continue elif state == 1: if que.state() == 1: if fout: fout.write('</p>' + '\n') fout.write('<p>' + '\n') if VERBOSE: print('</p>') print('<p>') else: if fout : fout.write('<p>' + '\n') if VERBOSE: print('<p>') que.push(tok) continue # ---- header 1 elif state == 2: if que.state() == 2: if fout : fout.write('</h1>' + '\n') if VERBOSE: print('</h1>') que.pop() else: if fout : fout.write('<h1>' + '\n') if VERBOSE: print('<h1>') que.push(tok) continue # ---- header 2 elif state == 3: if que.state() == 3: if fout : fout.write('</h2>' + '\n') if VERBOSE: print('</h2>') que.pop() else: if fout : fout.write('<h2>' + '\n') if VERBOSE: print('<h2>') que.push(tok) continue # ---- bold elif state == 4: if que.state() == 4: if fout : fout.write('</b>' + '\n') if VERBOSE: print('</b>') que.pop() else: if fout : fout.write('<b>' + '\n') if VERBOSE: print('<b>') que.push(tok) continue # ----- italic elif state == 5: if que.state() == 5: if fout : fout.write('</i>' + '\n') if VERBOSE: print('</i>') que.pop() else: if fout : fout.write('<i>' + '\n') if VERBOSE: print('<i>') que.push(tok) continue # ---- underline elif state == 6: if que.state() == 6: if fout : fout.write('</u>' + '\n') if VERBOSE: print('</u>') que.pop() else: if fout : fout.write('<u>' + '\n') if VERBOSE: print('<u>') que.push(tok) continue # ---- unknown else: print() print(f'unknown token/state {tok}') print(f'delete output file - exit program') terminate_output(fout,outfile) sys.exit() # ---- a final </p> required? if que.state() == 1: if fout : fout.write('</p>' + '\n') if VERBOSE: print('</p>') que.pop() # ---- queue/stack should have zero entries? if que.length() > 0: # ---- close and delete output file print() print(f'Error: state queue is not empty') print(' MD tag error - exit program') print_que(que,'-------------- queue/stack -------------') terminate_output(fout,outfile) sys.exit() # ---- end web page? if HTMLFILEOUT: dtstr = dt.datetime.now().strftime("%B %d,%Y %I:%M:%S%p") ew = wp.fstr(wp.end_of_web_page, {'today': dtstr}) # ---- output end-of-web-page to HTML file fout.write(ew) # ---- print end web page if VERBOSE: print(ew) # ---- sucess - return True return True # --------------------------------------------------------------- # ---- configure runtime flags # --------------------------------------------------------------- def config_runtime(nodelete=True,htmlfileout=True,verbose=False): global NODELETE global HTMLFILEOUT global VERBOSE NODELETE = nodelete HTMLFILEOUT = htmlfileout VERBOSE = verbose print(f'Runtime: nodelete={NODELETE}, htmlfileout={HTMLFILEOUT}, verbose={VERBOSE}')