File: hidden_code_block.py

package info (click to toggle)
simgrid 3.21%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 21,972 kB
  • sloc: cpp: 88,193; ansic: 69,244; fortran: 6,089; f90: 5,162; xml: 4,861; java: 4,250; perl: 2,056; python: 1,193; sh: 1,159; makefile: 57; sed: 6
file content (128 lines) | stat: -rw-r--r-- 3,687 bytes parent folder | download
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
"""Simple, inelegant Sphinx extension which adds a directive for a
highlighted code-block that may be toggled hidden and shown in HTML.  
This is possibly useful for teaching courses.

The directive, like the standard code-block directive, takes
a language argument and an optional linenos parameter.  The
hidden-code-block adds starthidden and label as optional 
parameters.

Examples:

.. hidden-code-block:: python
    :starthidden: False

    a = 10
    b = a + 5

.. hidden-code-block:: python
    :label: --- SHOW/HIDE ---

    x = 10
    y = x + 5

Thanks to http://www.javascriptkit.com/javatutors/dom3.shtml for 
inspiration on the javascript.  

Thanks to Milad 'animal' Fatenejad for suggesting this extension 
in the first place.

Written by Anthony 'el Scopz' Scopatz, January 2012.
https://github.com/scopatz/hiddencode

Released under the WTFPL (http://sam.zoy.org/wtfpl/).
"""

from docutils import nodes
from docutils.parsers.rst import directives
from sphinx.directives.code import CodeBlock

HCB_COUNTER = 0

js_showhide = """\
<script type="text/javascript">
    function showhide(element){
        if (!document.getElementById)
            return

        if (element.style.display == "block")
            element.style.display = "none"
        else
            element.style.display = "block"
    };
</script>
"""

def nice_bool(arg):
    tvalues = ('true',  't', 'yes', 'y')
    fvalues = ('false', 'f', 'no',  'n')
    arg = directives.choice(arg, tvalues + fvalues)
    return arg in tvalues


class hidden_code_block(nodes.General, nodes.FixedTextElement):
    pass


class HiddenCodeBlock(CodeBlock):
    """Hidden code block is Hidden"""

    option_spec = dict(starthidden=nice_bool, 
                       label=str,
                       **CodeBlock.option_spec)

    def run(self):
        # Body of the method is more or less copied from CodeBlock
        code = u'\n'.join(self.content)
        hcb = hidden_code_block(code, code)
        hcb['language'] = self.arguments[0]
        hcb['linenos'] = 'linenos' in self.options
        hcb['starthidden'] = self.options.get('starthidden', True)
        hcb['label'] = self.options.get('label', '+ show/hide code')
        hcb.line = self.lineno
        return [hcb]


def visit_hcb_html(self, node):
    """Visit hidden code block"""
    global HCB_COUNTER
    HCB_COUNTER += 1

    # We want to use the original highlighter so that we don't
    # have to reimplement it.  However it raises a SkipNode 
    # error at the end of the function call.  Thus we intercept
    # it and raise it again later.
    try: 
        self.visit_literal_block(node)
    except nodes.SkipNode:
        pass

    # The last element of the body should be the literal code 
    # block that was just made.
    code_block = self.body[-1]

    fill_header = {'divname': 'hiddencodeblock{0}'.format(HCB_COUNTER), 
                   'startdisplay': 'none' if node['starthidden'] else 'block', 
                   'label': node.get('label'), 
                   }

    divheader = ("""<a href="javascript:showhide(document.getElementById('{divname}'))">"""
                 """{label}</a><br />"""
                 '''<div id="{divname}" style="display: {startdisplay}">'''
                 ).format(**fill_header)

    code_block = js_showhide + divheader + code_block + "</div>"

    # reassign and exit
    self.body[-1] = code_block
    raise nodes.SkipNode


def depart_hcb_html(self, node):
    """Depart hidden code block"""
    # Stub because of SkipNode in visit


def setup(app):
    app.add_directive('hidden-code-block', HiddenCodeBlock)
    app.add_node(hidden_code_block, html=(visit_hcb_html, depart_hcb_html))