summaryrefslogtreecommitdiff
path: root/hack/rst2html
blob: f9c9146bb214f1216ed7968d867fc003fff3eb81 (plain)
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
#!/usr/bin/env python3
# Based on https://gist.github.com/mastbaum/2655700 for the basic plugin scaffolding

import sys
import re

import docutils.core
from docutils.transforms import Transform
from docutils.nodes import TextElement, Inline, Text
from docutils.parsers.rst import Directive, directives
from docutils.writers.html4css1 import Writer, HTMLTranslator


class UnfuckedHTMLTranslator(HTMLTranslator):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.in_literal_block = False

    def visit_literal_block(self, node):
        # Insert an empty "lineno" span before each line. We insert the line numbers using pure CSS in a ::before
        # pseudo-element. This has the added advantage that the line numbers don't get included in text selection.
        # These line number spans are also used to show line continuation markers when a line is wrapped.
        self.in_literal_block = True
        self.body.append(self.starttag(node, 'pre', CLASS='literal-block'))
        self.body.append('<span class="lineno"></span><span class="line">')

    def depart_literal_block(self, node):
        self.in_literal_block = False
        self.body.append('\n</span></pre>\n')

    def visit_Text(self, node):
        if self.in_literal_block:
            for match in re.finditer('([^\n]*)(\n|$)', node.astext()):
                text, end = match.groups()

                if text:
                    super().visit_Text(Text(text))

                if end == '\n':
                    if isinstance(node.parent, Inline):
                        self.depart_inline(node.parent)
                    self.body.append(f'</span>\n<span class="lineno"></span><span class="line">')
                    if isinstance(node.parent, Inline):
                        self.visit_inline(node.parent)

        else:
            super().visit_Text(node)


html_writer = Writer()
html_writer.translator_class = UnfuckedHTMLTranslator
docutils.core.publish_cmdline(writer=html_writer)