Description


markdown2html.py is a Python script that converts a Markdown file to HTML.


Usage


Create a directory with the files markdown2html.py, markdown2html.css, markdown.css
Run the Python file with your Markdown file:
python3 markdown2html.py my_file.md
A directory my_file is created, with 3 files inside:
article.html: the main HTML file.
article.md: a copy of the Markdown file.
sections.html: an index of links created with the tags ### and [-...]() .
You can optionally modify the CSS files.


Dependencies


Pygments:
Download and install or with pip install Pygments
(Usage example: pygmentize -S paraiso-dark -f html -a .codehilite)


Source code


markdown2html.py : converts the Markdown file to HTML
markdown2html.css : defines the style of the HTML page
markdown.css : defines styles for the markdown file
(Theme code: Dracula)


Program tags


Attributes must be placed between 2 tags <!-- program> <program -->
The first set of number-... attributes customizes the line numbers.
The series box-... the box and the code.
the last attributes in the list language and theme correspond to the options
from pygmentize , languages and styles .
In the <Program> tags section, when specifying the code attribute,
you can either provide the name of an existing file or write the code directly.
For example, code: code_example_1.py assumes that code_example_1.py
is an existing file in the same directory.
If you want to write the code directly, you can do so as follows:

<!-- program>
...
language: python
theme: fruity
code:
print("Hello")
print("World!")
<program -->
or
<!-- program>
...
language: js
theme: github-dark
code: script.js
<program -->

In the "Examples" section, many attributes are listed without values.
These attributes are optional and are used to customize the appearance of the code block.
If an attribute is not specified, the program will use default values.
You can experiment with different values to achieve the desired look for your code block.


Some examples


1 )

box-shadow: inset 10px 10px 10px rgba(0,0,0,.7);
box-font-size: 10px
box-font-family: Source Code Pro
theme: fruity


number: 0
number-color:
number-background-color:
number-border:
number-border-radius:
number-padding-left-right:
number-margin-left:
number-margin-right:
number-font-weight:
box-background: #171932;
box-border:
box-border-radius: 10px
box-shadow: inset 10px 10px 10px rgba(0,0,0,.7);
box-font-size: 10px
box-font-family: Source Code Pro
box-line-height: 120%
box-width: 80%
box-height: 300px
box-margin-top: 10px
box-margin-bottom: 10px
box-margin-left: 10px
box-margin-right: 10px
language: python
theme: fruity
code: code_example_1.py


def find_programs_format_html_code(program_param, html_code):

    div_highlight_style =\
        "overflow: auto;"+\
        f"height: {program_param['box-height:']};"+\
        f"border-radius: {program_param['box-border-radius:']};"+\
        f"width: {program_param['box-width:']};"+\
        "margin: auto;"+\
        f"border: {program_param['box-border:']};"+\
        f"background: {program_param['box-background:']};"+\
        f"box-shadow: {program_param['box-shadow:']};"

    td_linenos_style = "td.linenos .normal-e25491d6-6115-4063-878b-90eff34b9b3d {"+\
                        f"color: {program_param['number-color:']};"+\
                        f"background-color: {program_param['number-background-color:']};"+\
                        f"border: {program_param['number-border:']};"+\
                        f"border-radius: {program_param['number-border-radius:']};"+\
                        f"padding-left: {program_param['number-padding-left-right:']};"+\
                        f"padding-right: {program_param['number-padding-left-right:']};"+\
                        f"margin-left: {program_param['number-margin-left:']};"+\
                        f"margin-right: {program_param['number-margin-right:']};"+\
                        f"font-weight: {program_param['number-font-weight:']};"+\
                        "}"

    html_lignes = html_code.splitlines()

    for i, ligne in enumerate(html_lignes):
        if ligne.startswith('pre {'):
            del html_lignes[:i]
            break

    html_lignes[0] = "<style>"

    html_lignes[1] = td_linenos_style
    html_code = "\n".join(html_lignes)

    soup = BeautifulSoup(html_code, 'html.parser')

    highlight_div = soup.find('div', attrs={'class': 'highlight'})

    if highlight_div:
        highlight_div['style'] = div_highlight_style

    html_code = soup.prettify()

    soup = BeautifulSoup(html_code, 'html.parser')

    balises_pre = soup.find_all('pre')

    for balise in balises_pre:

        balise['style'] = f"line-height: {program_param['box-line-height:']};"+\
                            f"margin-top: {program_param['box-margin-top:']};"+\
                            f"margin-bottom: {program_param['box-margin-bottom:']};"+\
                            f"margin-left: {program_param['box-margin-left:']};"+\
                            f"margin-right: {program_param['box-margin-right:']};"+\
                            f"font-family: {program_param['box-font-family:']};"+\
                            f"font-size: {program_param['box-font-size:']};"+\
                            "padding: 0;"

        if program_param['number:'] == '1':
            balise['style'] += "width: max-content;"

    html_code = soup.prettify()

    return(html_code)


2 )

box-shadow: rgba(0, 0, 0, 0.25) 0px 54px 55px, rgba(0, 0, 0, 0.12) 0px -12px 30px, rgba(0, 0, 0, 0.12) 0px 4px 6px, rgba(0, 0, 0, 0.17) 0px 12px 13px, rgba(0, 0, 0, 0.09) 0px -3px 5px;
box-font-size: 10px
box-font-family: Source Code Pro
theme: nord-darker


number: 1
number-color:
number-background-color:
number-border:
number-border-radius:
number-padding-left-right:
number-margin-left:
number-margin-right:
number-font-weight:
box-background:
box-border:
box-border-radius: 10px;
box-shadow: rgba(0, 0, 0, 0.25) 0px 54px 55px, rgba(0, 0, 0, 0.12) 0px -12px 30px, rgba(0, 0, 0, 0.12) 0px 4px 6px, rgba(0, 0, 0, 0.17) 0px 12px 13px, rgba(0, 0, 0, 0.09) 0px -3px 5px;
box-font-size: 10px
box-font-family: Source Code Pro
box-line-height: 120%
box-width: 80%
box-height: 300px
box-margin-top: 10px
box-margin-bottom: 10px
box-margin-left: 10px
box-margin-right: 10px
language: python
theme: nord-darker
code: code_example_1.py


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def find_programs_format_html_code(program_param, html_code):

    div_highlight_style =\
        "overflow: auto;"+\
        f"height: {program_param['box-height:']};"+\
        f"border-radius: {program_param['box-border-radius:']};"+\
        f"width: {program_param['box-width:']};"+\
        "margin: auto;"+\
        f"border: {program_param['box-border:']};"+\
        f"background: {program_param['box-background:']};"+\
        f"box-shadow: {program_param['box-shadow:']};"

    td_linenos_style = "td.linenos .normal-d18bfb5a-f4c1-433a-8606-8da578c5eb6d {"+\
                        f"color: {program_param['number-color:']};"+\
                        f"background-color: {program_param['number-background-color:']};"+\
                        f"border: {program_param['number-border:']};"+\
                        f"border-radius: {program_param['number-border-radius:']};"+\
                        f"padding-left: {program_param['number-padding-left-right:']};"+\
                        f"padding-right: {program_param['number-padding-left-right:']};"+\
                        f"margin-left: {program_param['number-margin-left:']};"+\
                        f"margin-right: {program_param['number-margin-right:']};"+\
                        f"font-weight: {program_param['number-font-weight:']};"+\
                        "}"

    html_lignes = html_code.splitlines()

    for i, ligne in enumerate(html_lignes):
        if ligne.startswith('pre {'):
            del html_lignes[:i]
            break

    html_lignes[0] = "<style>"

    html_lignes[1] = td_linenos_style
    html_code = "\n".join(html_lignes)

    soup = BeautifulSoup(html_code, 'html.parser')

    highlight_div = soup.find('div', attrs={'class': 'highlight'})

    if highlight_div:
        highlight_div['style'] = div_highlight_style

    html_code = soup.prettify()

    soup = BeautifulSoup(html_code, 'html.parser')

    balises_pre = soup.find_all('pre')

    for balise in balises_pre:

        balise['style'] = f"line-height: {program_param['box-line-height:']};"+\
                            f"margin-top: {program_param['box-margin-top:']};"+\
                            f"margin-bottom: {program_param['box-margin-bottom:']};"+\
                            f"margin-left: {program_param['box-margin-left:']};"+\
                            f"margin-right: {program_param['box-margin-right:']};"+\
                            f"font-family: {program_param['box-font-family:']};"+\
                            f"font-size: {program_param['box-font-size:']};"+\
                            "padding: 0;"

        if program_param['number:'] == '1':
            balise['style'] += "width: max-content;"

    html_code = soup.prettify()

    return(html_code)


3 )

box-shadow: rgba(6, 24, 44, 0.4) 0px 0px 0px 2px, rgba(6, 24, 44, 0.65) 0px 4px 6px -1px, rgba(255, 255, 255, 0.08) 0px 1px 0px inset;
box-font-size: 16px
box-font-family: Play
theme: monokai


number: 0
number-color:
number-background-color:
number-border:
number-border-radius:
number-padding-left-right:
number-margin-left:
number-margin-right:
number-font-weight:
box-background:
box-border:
box-border-radius:
box-shadow: rgba(6, 24, 44, 0.4) 0px 0px 0px 2px, rgba(6, 24, 44, 0.65) 0px 4px 6px -1px, rgba(255, 255, 255, 0.08) 0px 1px 0px inset;
box-font-size: 16px
box-font-family: Play
box-line-height: 120%
box-width: 80%
box-height: 300px
box-margin-top: 10px
box-margin-bottom: 10px
box-margin-left: 10px
box-margin-right: 10px
language: python
theme: monokai
code: code_example_1.py


def find_programs_format_html_code(program_param, html_code):

    div_highlight_style =\
        "overflow: auto;"+\
        f"height: {program_param['box-height:']};"+\
        f"border-radius: {program_param['box-border-radius:']};"+\
        f"width: {program_param['box-width:']};"+\
        "margin: auto;"+\
        f"border: {program_param['box-border:']};"+\
        f"background: {program_param['box-background:']};"+\
        f"box-shadow: {program_param['box-shadow:']};"

    td_linenos_style = "td.linenos .normal-e6ddc347-ed79-4f49-841d-5087187fdf5b {"+\
                        f"color: {program_param['number-color:']};"+\
                        f"background-color: {program_param['number-background-color:']};"+\
                        f"border: {program_param['number-border:']};"+\
                        f"border-radius: {program_param['number-border-radius:']};"+\
                        f"padding-left: {program_param['number-padding-left-right:']};"+\
                        f"padding-right: {program_param['number-padding-left-right:']};"+\
                        f"margin-left: {program_param['number-margin-left:']};"+\
                        f"margin-right: {program_param['number-margin-right:']};"+\
                        f"font-weight: {program_param['number-font-weight:']};"+\
                        "}"

    html_lignes = html_code.splitlines()

    for i, ligne in enumerate(html_lignes):
        if ligne.startswith('pre {'):
            del html_lignes[:i]
            break

    html_lignes[0] = "<style>"

    html_lignes[1] = td_linenos_style
    html_code = "\n".join(html_lignes)

    soup = BeautifulSoup(html_code, 'html.parser')

    highlight_div = soup.find('div', attrs={'class': 'highlight'})

    if highlight_div:
        highlight_div['style'] = div_highlight_style

    html_code = soup.prettify()

    soup = BeautifulSoup(html_code, 'html.parser')

    balises_pre = soup.find_all('pre')

    for balise in balises_pre:

        balise['style'] = f"line-height: {program_param['box-line-height:']};"+\
                            f"margin-top: {program_param['box-margin-top:']};"+\
                            f"margin-bottom: {program_param['box-margin-bottom:']};"+\
                            f"margin-left: {program_param['box-margin-left:']};"+\
                            f"margin-right: {program_param['box-margin-right:']};"+\
                            f"font-family: {program_param['box-font-family:']};"+\
                            f"font-size: {program_param['box-font-size:']};"+\
                            "padding: 0;"

        if program_param['number:'] == '1':
            balise['style'] += "width: max-content;"

    html_code = soup.prettify()

    return(html_code)


4 )

box-shadow: rgba(0, 0, 0, 0.0) 0px 2px 1px, rgba(0, 0, 0, 0.09) 0px 4px 2px, rgba(0, 0, 0, 0.09) 0px 8px 4px, rgba(0, 0, 0, 0.09) 0px 16px 8px, rgba(0, 0, 0, 0.09) 0px 32px 16px;
box-font-size: 12px
box-font-family: Ubuntu Mono
theme: fruity


number: 0
number-color:
number-background-color:
number-border:
number-border-radius:
number-padding-left-right:
number-margin-left:
number-margin-right:
number-font-weight:
box-background: #1B1E3B;
box-border:
box-border-radius: 10px
box-shadow: rgba(0, 0, 0, 0.0) 0px 2px 1px, rgba(0, 0, 0, 0.09) 0px 4px 2px, rgba(0, 0, 0, 0.09) 0px 8px 4px, rgba(0, 0, 0, 0.09) 0px 16px 8px, rgba(0, 0, 0, 0.09) 0px 32px 16px;
box-font-size: 12px
box-font-family: Ubuntu Mono
box-line-height: 120%
box-width: 60%
box-height: 297px
box-margin-top: 10px
box-margin-bottom: 10px
box-margin-left: 10px
box-margin-right: 10px
language: python
theme: fruity
code: code_example_1.py


def find_programs_format_html_code(program_param, html_code):

    div_highlight_style =\
        "overflow: auto;"+\
        f"height: {program_param['box-height:']};"+\
        f"border-radius: {program_param['box-border-radius:']};"+\
        f"width: {program_param['box-width:']};"+\
        "margin: auto;"+\
        f"border: {program_param['box-border:']};"+\
        f"background: {program_param['box-background:']};"+\
        f"box-shadow: {program_param['box-shadow:']};"

    td_linenos_style = "td.linenos .normal-36382d8b-372f-4c7d-adc3-01af12d6c968 {"+\
                        f"color: {program_param['number-color:']};"+\
                        f"background-color: {program_param['number-background-color:']};"+\
                        f"border: {program_param['number-border:']};"+\
                        f"border-radius: {program_param['number-border-radius:']};"+\
                        f"padding-left: {program_param['number-padding-left-right:']};"+\
                        f"padding-right: {program_param['number-padding-left-right:']};"+\
                        f"margin-left: {program_param['number-margin-left:']};"+\
                        f"margin-right: {program_param['number-margin-right:']};"+\
                        f"font-weight: {program_param['number-font-weight:']};"+\
                        "}"

    html_lignes = html_code.splitlines()

    for i, ligne in enumerate(html_lignes):
        if ligne.startswith('pre {'):
            del html_lignes[:i]
            break

    html_lignes[0] = "<style>"

    html_lignes[1] = td_linenos_style
    html_code = "\n".join(html_lignes)

    soup = BeautifulSoup(html_code, 'html.parser')

    highlight_div = soup.find('div', attrs={'class': 'highlight'})

    if highlight_div:
        highlight_div['style'] = div_highlight_style

    html_code = soup.prettify()

    soup = BeautifulSoup(html_code, 'html.parser')

    balises_pre = soup.find_all('pre')

    for balise in balises_pre:

        balise['style'] = f"line-height: {program_param['box-line-height:']};"+\
                            f"margin-top: {program_param['box-margin-top:']};"+\
                            f"margin-bottom: {program_param['box-margin-bottom:']};"+\
                            f"margin-left: {program_param['box-margin-left:']};"+\
                            f"margin-right: {program_param['box-margin-right:']};"+\
                            f"font-family: {program_param['box-font-family:']};"+\
                            f"font-size: {program_param['box-font-size:']};"+\
                            "padding: 0;"

        if program_param['number:'] == '1':
            balise['style'] += "width: max-content;"

    html_code = soup.prettify()

    return(html_code)


5 )

box-shadow: rgba(0, 0, 0, 0.4) 0px 2px 4px, rgba(0, 0, 0, 0.3) 0px 7px 13px -3px, rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
box-font-size: 14px
box-font-family: Outfit
box-height: auto
theme: nord


number: 0
number-color:
number-background-color:
number-border:
number-border-radius:
number-padding-left-right:
number-margin-left:
number-margin-right:
number-font-weight:
box-background:
box-border:
box-border-radius: 25px
box-shadow: rgba(0, 0, 0, 0.4) 0px 2px 4px, rgba(0, 0, 0, 0.3) 0px 7px 13px -3px, rgba(0, 0, 0, 0.2) 0px -3px 0px inset;
box-font-size: 14px
box-font-family: Outfit
box-line-height: 110%
box-width: 70%
box-height: auto
box-margin-top: 10px
box-margin-bottom: 10px
box-margin-left: 10px
box-margin-right: 10px
language: python
theme: nord
code: code_example_1.py


def find_programs_format_html_code(program_param, html_code):

    div_highlight_style =\
        "overflow: auto;"+\
        f"height: {program_param['box-height:']};"+\
        f"border-radius: {program_param['box-border-radius:']};"+\
        f"width: {program_param['box-width:']};"+\
        "margin: auto;"+\
        f"border: {program_param['box-border:']};"+\
        f"background: {program_param['box-background:']};"+\
        f"box-shadow: {program_param['box-shadow:']};"

    td_linenos_style = "td.linenos .normal-9c991dc1-387c-437c-885e-8f230db2a6df {"+\
                        f"color: {program_param['number-color:']};"+\
                        f"background-color: {program_param['number-background-color:']};"+\
                        f"border: {program_param['number-border:']};"+\
                        f"border-radius: {program_param['number-border-radius:']};"+\
                        f"padding-left: {program_param['number-padding-left-right:']};"+\
                        f"padding-right: {program_param['number-padding-left-right:']};"+\
                        f"margin-left: {program_param['number-margin-left:']};"+\
                        f"margin-right: {program_param['number-margin-right:']};"+\
                        f"font-weight: {program_param['number-font-weight:']};"+\
                        "}"

    html_lignes = html_code.splitlines()

    for i, ligne in enumerate(html_lignes):
        if ligne.startswith('pre {'):
            del html_lignes[:i]
            break

    html_lignes[0] = "<style>"

    html_lignes[1] = td_linenos_style
    html_code = "\n".join(html_lignes)

    soup = BeautifulSoup(html_code, 'html.parser')

    highlight_div = soup.find('div', attrs={'class': 'highlight'})

    if highlight_div:
        highlight_div['style'] = div_highlight_style

    html_code = soup.prettify()

    soup = BeautifulSoup(html_code, 'html.parser')

    balises_pre = soup.find_all('pre')

    for balise in balises_pre:

        balise['style'] = f"line-height: {program_param['box-line-height:']};"+\
                            f"margin-top: {program_param['box-margin-top:']};"+\
                            f"margin-bottom: {program_param['box-margin-bottom:']};"+\
                            f"margin-left: {program_param['box-margin-left:']};"+\
                            f"margin-right: {program_param['box-margin-right:']};"+\
                            f"font-family: {program_param['box-font-family:']};"+\
                            f"font-size: {program_param['box-font-size:']};"+\
                            "padding: 0;"

        if program_param['number:'] == '1':
            balise['style'] += "width: max-content;"

    html_code = soup.prettify()

    return(html_code)