|
1 | | -#!/usr/bin/env python |
2 | | -from __future__ import print_function |
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
3 | 3 | import argparse |
4 | | -import markdown |
5 | | -import os |
6 | 4 | import sys |
| 5 | +import markdown |
7 | 6 |
|
8 | | -def convert_markdown(in_fn): |
9 | | - input_md = open(in_fn, mode="r", encoding="utf-8").read() |
| 7 | +def convert_markdown(md_file): |
| 8 | + """Convert markdown to HTML with basic extensions only.""" |
| 9 | + with open(md_file, 'r') as f: |
| 10 | + md_content = f.read() |
| 11 | + |
| 12 | + # Use only basic extensions that come with markdown |
10 | 13 | html = markdown.markdown( |
11 | | - "[TOC]\n" + input_md, |
12 | | - extensions = [ |
13 | | - 'pymdownx.extra', |
14 | | - 'pymdownx.b64', |
15 | | - 'pymdownx.highlight', |
16 | | - 'pymdownx.emoji', |
17 | | - 'pymdownx.tilde', |
18 | | - 'toc' |
19 | | - ], |
20 | | - extension_configs = { |
21 | | - 'pymdownx.b64': { |
22 | | - 'base_path': os.path.dirname(in_fn) |
23 | | - }, |
24 | | - 'pymdownx.highlight': { |
25 | | - 'noclasses': True |
26 | | - }, |
27 | | - 'toc': { |
28 | | - 'title': 'Table of Contents' |
29 | | - } |
30 | | - } |
| 14 | + md_content, |
| 15 | + extensions=[ |
| 16 | + 'markdown.extensions.tables', |
| 17 | + 'markdown.extensions.fenced_code', |
| 18 | + 'markdown.extensions.codehilite', |
| 19 | + 'markdown.extensions.toc' |
| 20 | + ] |
31 | 21 | ) |
32 | 22 | return html |
33 | 23 |
|
34 | | -def wrap_html(contents): |
35 | | - header = """<!DOCTYPE html><html> |
36 | | - <head> |
37 | | - <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> |
38 | | - <style> |
39 | | - body { |
40 | | - font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; |
41 | | - padding: 3em; |
42 | | - margin-right: 350px; |
43 | | - max-width: 100%; |
44 | | - } |
45 | | - .toc { |
46 | | - position: fixed; |
47 | | - right: 20px; |
48 | | - width: 300px; |
49 | | - padding-top: 20px; |
50 | | - overflow: scroll; |
51 | | - height: calc(100% - 3em - 20px); |
52 | | - } |
53 | | - .toctitle { |
54 | | - font-size: 1.8em; |
55 | | - font-weight: bold; |
56 | | - } |
57 | | - .toc > ul { |
58 | | - padding: 0; |
59 | | - margin: 1rem 0; |
60 | | - list-style-type: none; |
61 | | - } |
62 | | - .toc > ul ul { padding-left: 20px; } |
63 | | - .toc > ul > li > a { display: none; } |
64 | | - img { max-width: 800px; } |
65 | | - pre { |
66 | | - padding: 0.6em 1em; |
67 | | - } |
68 | | - h2 { |
| 24 | +def wrap_html(body_html, title="Analysis Results"): |
| 25 | + """Wrap the converted markdown in a complete HTML document.""" |
| 26 | + return f"""<!DOCTYPE html> |
| 27 | +<html lang="en"> |
| 28 | +<head> |
| 29 | + <meta charset="UTF-8"> |
| 30 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 31 | + <title>{title}</title> |
| 32 | + <style> |
| 33 | + body {{ |
| 34 | + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; |
| 35 | + line-height: 1.6; |
| 36 | + color: #333; |
| 37 | + max-width: 1200px; |
| 38 | + margin: 0 auto; |
| 39 | + padding: 20px; |
| 40 | + }} |
| 41 | + h1, h2, h3 {{ color: #2c3e50; }} |
| 42 | + code {{ |
| 43 | + background-color: #f4f4f4; |
| 44 | + padding: 2px 4px; |
| 45 | + border-radius: 3px; |
| 46 | + font-family: 'Courier New', monospace; |
| 47 | + }} |
| 48 | + pre {{ |
| 49 | + background-color: #f4f4f4; |
| 50 | + padding: 10px; |
| 51 | + border-radius: 5px; |
| 52 | + overflow-x: auto; |
| 53 | + }} |
| 54 | + table {{ |
| 55 | + border-collapse: collapse; |
| 56 | + width: 100%; |
| 57 | + margin: 20px 0; |
| 58 | + }} |
| 59 | + th, td {{ |
| 60 | + border: 1px solid #ddd; |
| 61 | + padding: 8px; |
| 62 | + text-align: left; |
| 63 | + }} |
| 64 | + th {{ background-color: #f2f2f2; }} |
| 65 | + .toc {{ background-color: #f9f9f9; padding: 15px; border-radius: 5px; }} |
| 66 | + </style> |
| 67 | +</head> |
| 68 | +<body> |
| 69 | +{body_html} |
| 70 | +</body> |
| 71 | +</html>""" |
| 72 | + |
| 73 | +def main(): |
| 74 | + parser = argparse.ArgumentParser(description='Convert Markdown to HTML') |
| 75 | + parser.add_argument('mdfile', type=argparse.FileType('r'), help='Input markdown file') |
| 76 | + parser.add_argument('-o', '--output', required=True, help='Output HTML file') |
| 77 | + parser.add_argument('--title', default='Analysis Results', help='HTML page title') |
69 | 78 |
|
70 | | - } |
71 | | - </style> |
72 | | - </head> |
73 | | - <body> |
74 | | - <div class="container"> |
75 | | - """ |
76 | | - footer = """ |
77 | | - </div> |
78 | | - </body> |
79 | | - </html> |
80 | | - """ |
81 | | - return header + contents + footer |
| 79 | + args = parser.parse_args() |
82 | 80 |
|
| 81 | + try: |
| 82 | + converted_md = convert_markdown(args.mdfile.name) |
| 83 | + full_html = wrap_html(converted_md, args.title) |
83 | 84 |
|
84 | | -def parse_args(args=None): |
85 | | - parser = argparse.ArgumentParser() |
86 | | - parser.add_argument('mdfile', type=argparse.FileType('r'), nargs='?', |
87 | | - help='File to convert. Defaults to stdin.') |
88 | | - parser.add_argument('-o', '--out', type=argparse.FileType('w'), |
89 | | - default=sys.stdout, |
90 | | - help='Output file name. Defaults to stdout.') |
91 | | - return parser.parse_args(args) |
| 85 | + with open(args.output, 'w') as f: |
| 86 | + f.write(full_html) |
92 | 87 |
|
93 | | -def main(args=None): |
94 | | - args = parse_args(args) |
95 | | - converted_md = convert_markdown(args.mdfile.name) |
96 | | - html = wrap_html(converted_md) |
97 | | - args.out.write(html) |
| 88 | + print(f"Successfully converted {args.mdfile.name} to {args.output}") |
| 89 | + |
| 90 | + except Exception as e: |
| 91 | + print(f"Error converting markdown: {e}", file=sys.stderr) |
| 92 | + return 1 |
| 93 | + |
| 94 | + finally: |
| 95 | + args.mdfile.close() |
| 96 | + |
| 97 | + return 0 |
98 | 98 |
|
99 | 99 | if __name__ == '__main__': |
100 | 100 | sys.exit(main()) |
| 101 | + |
0 commit comments