#!/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}')