diff --git a/problemtools/md2html.py b/problemtools/md2html.py index 62a8e15..7b834d2 100644 --- a/problemtools/md2html.py +++ b/problemtools/md2html.py @@ -66,7 +66,7 @@ def convert(problem: str, options: argparse.Namespace) -> bool: with open("problem.css", "w") as output_file: with open(os.path.join(templatepath, "problem.css"), "r") as input_file: output_file.write(input_file.read()) - + return True diff --git a/problemtools/problem2pdf.py b/problemtools/problem2pdf.py index 911c5cb..09ed596 100644 --- a/problemtools/problem2pdf.py +++ b/problemtools/problem2pdf.py @@ -12,80 +12,93 @@ def convert(options: argparse.Namespace) -> bool: problem_root = os.path.realpath(options.problem) + + if statement_common.find_statement_extension(problem_root, language=options.language) == "md": + return md2pdf(options) + else: + return latex2pdf(options) + + +def md2pdf(options: argparse.Namespace) -> bool: + problem_root = os.path.realpath(options.problem) problembase = os.path.splitext(os.path.basename(problem_root))[0] destfile = string.Template(options.destfile).safe_substitute(problem=problembase) - if statement_common.find_statement_extension(problem_root, language=options.language) == "md": - statement_path = statement_common.find_statement(problem_root, extension="md", language=options.language) + statement_path = statement_common.find_statement(problem_root, extension="md", language=options.language) - if not os.path.isfile(statement_path): - raise Exception(f"Error! {statement_path} is not a file") + if not os.path.isfile(statement_path): + raise Exception(f"Error! {statement_path} is not a file") - templatepaths = [os.path.join(os.path.dirname(__file__), 'templates/markdown_pdf'), - os.path.join(os.path.dirname(__file__), '../templates/markdown_pdf'), - '/usr/lib/problemtools/templates/markdown_pdf'] - templatepath = next((p for p in templatepaths - if os.path.isdir(p) and os.path.isfile(os.path.join(p, "fix_tables.md"))), - None) - table_fix_path = os.path.join(templatepath, "fix_tables.md") - if not os.path.isfile(table_fix_path): - raise Exception("Could not find markdown pdf template") + templatepaths = [os.path.join(os.path.dirname(__file__), 'templates/markdown_pdf'), + os.path.join(os.path.dirname(__file__), '../templates/markdown_pdf'), + '/usr/lib/problemtools/templates/markdown_pdf'] + templatepath = next((p for p in templatepaths + if os.path.isdir(p) and os.path.isfile(os.path.join(p, "fix_tables.md"))), + None) + table_fix_path = os.path.join(templatepath, "fix_tables.md") + if not os.path.isfile(table_fix_path): + raise Exception("Could not find markdown pdf template") - with open(table_fix_path, "r") as file: - table_fix = file.read() + with open(table_fix_path, "r") as file: + table_fix = file.read() - statement_dir = os.path.join(problem_root, "problem_statement") - with open(statement_path, "r") as file: - statement_md = file.read() + statement_dir = os.path.join(problem_root, "problem_statement") + with open(statement_path, "r") as file: + statement_md = file.read() - problem_name = statement_common.get_problem_name(problem_root, options.language) + problem_name = statement_common.get_problem_name(problem_root, options.language) - # Add code that adds vertical and horizontal lines to all tables - statement_md = r'\centerline{\huge %s}' % problem_name + statement_md - statement_md = table_fix + statement_md + # Add code that adds vertical and horizontal lines to all tables + statement_md = r'\centerline{\huge %s}' % problem_name + statement_md + statement_md = table_fix + statement_md - # Hacky: html samples -> md. Then we append to the markdown document - samples = "\n".join(statement_common.format_samples(problem_root, to_pdf=True)) + samples = "\n".join(statement_common.format_samples(problem_root, to_pdf=True)) - # If we don't add newline, the table might get attached to a footnote - statement_md += "\n" + samples + # If we don't add newline, the topmost table might get attached to a footnote + statement_md += "\n" + samples - with tempfile.NamedTemporaryFile(mode='w', suffix=".md") as temp_file: - temp_file.write(statement_md) - temp_file.flush() - command = ["pandoc", temp_file.name, "-o", f"{problembase}.pdf", f"--resource-path={statement_dir}"] - return subprocess.run(command, capture_output=True, text=True, shell=False, check=True) + with tempfile.NamedTemporaryFile(mode='w', suffix=".md") as temp_file: + temp_file.write(statement_md) + temp_file.flush() + command = ["pandoc", temp_file.name, "-o", destfile, f"--resource-path={statement_dir}"] + return subprocess.run(command, capture_output=True, text=True, shell=False, check=True) - else: - # Set up template if necessary - with template.Template(problem_root, language=options.language) as templ: - texfile = templ.get_file_name() - origcwd = os.getcwd() +def latex2pdf(options: argparse.Namespace) -> bool: + problem_root = os.path.realpath(options.problem) + problembase = os.path.splitext(os.path.basename(problem_root))[0] + destfile = string.Template(options.destfile).safe_substitute(problem=problembase) - os.chdir(os.path.dirname(texfile)) - params = ['pdflatex', '-interaction=nonstopmode'] - output = None - if options.quiet: - output = open(os.devnull, 'w') - if options.nopdf: - params.append('-draftmode') + # Set up template if necessary + with template.Template(problem_root, language=options.language) as templ: + texfile = templ.get_file_name() - params.append(texfile) + origcwd = os.getcwd() + os.chdir(os.path.dirname(texfile)) + params = ['pdflatex', '-interaction=nonstopmode'] + output = None + if options.quiet: + output = open(os.devnull, 'w') + if options.nopdf: + params.append('-draftmode') + + params.append(texfile) + + status = subprocess.call(params, stdout=output) + if status == 0: status = subprocess.call(params, stdout=output) - if status == 0: - status = subprocess.call(params, stdout=output) - if output is not None: - output.close() + if output is not None: + output.close() + + os.chdir(origcwd) - os.chdir(origcwd) + if status == 0 and not options.nopdf: + shutil.move(os.path.splitext(texfile)[0] + '.pdf', destfile) - if status == 0 and not options.nopdf: - shutil.move(os.path.splitext(texfile)[0] + '.pdf', destfile) + return status == 0 - return status == 0 def get_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) diff --git a/problemtools/statement_common.py b/problemtools/statement_common.py index 97b7117..66a6c67 100644 --- a/problemtools/statement_common.py +++ b/problemtools/statement_common.py @@ -82,55 +82,7 @@ def format_samples(problem_root: str, to_pdf: bool = False) -> List[str]: casenum = 1 for sample in sorted(os.listdir(sample_path)): if sample.endswith(".interaction"): - if to_pdf: - line = r"""\begin{tabular}{p{0.3\textwidth} p{0.5\textwidth} p{0.0\textwidth}} -\textbf{Read} & \textbf{Sample Interaction %i} & \textbf{Write} \\ -\end{tabular}""" % casenum - else: - line = f""" - - - - - - -
ReadSample Interaction {casenum}Write
""" - - with open(os.path.join(sample_path, sample), "r", encoding="utf-8") as infile: - sample_interaction = infile.readlines() - lines = [] - for interaction in sample_interaction: - data = interaction[1:] - if to_pdf: - if interaction[0] == '>': - left = True - elif interaction[0] == '<': - left = False - else: - print(f"Warning: Interaction had unknown prefix {interaction[0]}") - lines.append(r""" - \begin{table}[H] - %(justify)s\begin{tabular}{|p{0.6\textwidth}|} - \hline - %(text)s \\ - \hline - \end{tabular} - \end{table}""" % {"justify": "" if left else "\\hspace*{\\fill}\n", - "text": data}) - else: - line_type = "" - if interaction[0] == '>': - line_type = "sampleinteractionwrite" - elif interaction[0] == '<': - line_type = "sampleinteractionread" - else: - print(f"Warning: Interaction had unknown prefix {interaction[0]}") - lines.append(f"""
{data}
""") - - if to_pdf: - samples.append(line + '\\vspace{-15pt}'.join(lines)) - else: - samples.append(line + ''.join(lines)) + samples.append(format_interactive_sample(sample_path, sample, casenum, to_pdf)) casenum += 1 continue @@ -140,35 +92,118 @@ def format_samples(problem_root: str, to_pdf: bool = False) -> List[str]: outpath = os.path.join(sample_path, sample_name + ".ans") if not os.path.isfile(outpath): continue - with open(os.path.join(sample_path, sample), "r", encoding="utf-8") as infile: - sample_input = infile.read() - with open(outpath, "r", encoding="utf-8") as outfile: - sample_output = outfile.read() - samples.append(""" + samples.append(format_normal_sample(sample_path, sample, casenum, to_pdf)) + casenum += 1 + + return samples + + +def format_normal_sample(sample_root: str, sample: str, casenum: int, to_pdf: bool) -> str: + """ + + Args: + sample_root: root of the sample folder + sample: file name of the sample + casenum: which sample is this? (1, 2, 3...) + to_pdf: do we target pdf or html output + + Returns: + str: the sample, ready to be pasted into a markdown doc and fed to pandoc + """ + + with open(os.path.join(sample_root, sample), "r", encoding="utf-8") as infile: + sample_input = infile.read() + sample_name = sample[:-3] + outpath = os.path.join(sample_root, sample_name + ".ans") + with open(outpath, "r", encoding="utf-8") as outfile: + sample_output = outfile.read() + + sample = """ + + + + + + + + + + + +
Sample Input %(case)dSample Output %(case)d
%(input)s
%(output)s
""" % ({"case": casenum, "input": html.escape(sample_input), + "output": html.escape(sample_output)}) + + if to_pdf: + # If pdf, convert to markdown + with tempfile.NamedTemporaryFile(mode='w', suffix=".html") as temp_file: + temp_file.write(sample) + temp_file.flush() + command = ["pandoc", temp_file.name, "-t" , "markdown"] + return subprocess.run(command, capture_output=True, text=True, + shell=False, check=True).stdout + else: + return sample + + +def format_interactive_sample(sample_root: str, sample: str, casenum: int, to_pdf: bool) -> str: + """ + + Args: + sample_root: root of the sample folder + sample: file name of the sample + casenum: which sample is this? (1, 2, 3...) + to_pdf: do we target pdf or html output + + Returns: + str: the sample, ready to be pasted into a markdown doc and fed to pandoc + """ + if to_pdf: + line = r"""\begin{tabular}{p{0.3\textwidth} p{0.5\textwidth} p{0.0\textwidth}} +\textbf{Read} & \textbf{Sample Interaction %i} & \textbf{Write} \\ +\end{tabular}""" % casenum + else: + line = f""" - - - + + + - - - - -
Sample Input %(case)dSample Output %(case)dReadSample Interaction {casenum}Write
%(input)s
%(output)s
""" - % ({"case": casenum, "input": html.escape(sample_input), "output": html.escape(sample_output)})) + with open(os.path.join(sample_root, sample), "r", encoding="utf-8") as infile: + sample_interaction = infile.readlines() + lines = [] + for interaction in sample_interaction: + data = interaction[1:] if to_pdf: - # If pdf, convert to markdown - with tempfile.NamedTemporaryFile(mode='w', suffix=".html") as temp_file: - temp_file.write(samples[-1]) - temp_file.flush() - command = ["pandoc", temp_file.name, "-t" , "markdown"] - samples[-1] = subprocess.run(command, capture_output=True, text=True, - shell=False, check=True).stdout - - casenum += 1 + if interaction[0] == '>': + left = True + elif interaction[0] == '<': + left = False + else: + print(f"Warning: Interaction had unknown prefix {interaction[0]}") + lines.append(r""" + \begin{table}[H] + %(justify)s\begin{tabular}{|p{0.6\textwidth}|} + \hline + %(text)s \\ + \hline + \end{tabular} + \end{table}""" % {"justify": "" if left else "\\hspace*{\\fill}\n", + "text": data}) + else: + line_type = "" + if interaction[0] == '>': + line_type = "sampleinteractionwrite" + elif interaction[0] == '<': + line_type = "sampleinteractionread" + else: + print(f"Warning: Interaction had unknown prefix {interaction[0]}") + lines.append(f"""
{data}
""") - return samples + if to_pdf: + return line + '\\vspace{-15pt}'.join(lines) + else: + return line + ''.join(lines)