-
Notifications
You must be signed in to change notification settings - Fork 11
/
asciinema.py
120 lines (101 loc) · 3.79 KB
/
asciinema.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
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
import os
from docutils import nodes
from docutils.parsers.rst import directives
from sphinx.util.fileutil import copy_asset
from sphinx.util.docutils import SphinxDirective
from sphinx.util import logging
logger = logging.getLogger(__name__)
def copy_asset_files(app, exc):
asset_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),
'_static')
if exc is None: # build succeeded
for file in os.listdir(asset_dir):
copy_asset(os.path.join(asset_dir, file),
os.path.join(app.outdir, '_static'))
class Asciinema(nodes.General, nodes.Element):
pass
def visit_html(self, node):
if node['type'] == 'local':
template = (
'<asciinema-player {options} '
'src="data:application/json;base64,{src}"></asciinema-player>')
option_template = '{}="{}" '
src = node['content']
else:
template = ('<script id="asciicast-{src}" {options} '
'src="https://asciinema.org/a/{src}.js" async></script>')
option_template = 'data-{}="{}" '
src = node['content']
options = ''
for n, v in node['options'].items():
options += option_template.format(n, v)
tag = (template.format(options=options, src=src))
self.body.append(tag)
def visit_unsupported(self, node):
logger.warning('asciinema: unsupported output format (node skipped)')
raise nodes.SkipNode
def depart(self, node):
pass
class ASCIINemaDirective(SphinxDirective):
has_content = True
final_argument_whitespace = False
option_spec = {
'cols': directives.positive_int,
'rows': directives.positive_int,
'autoplay': directives.unchanged,
'preload': directives.unchanged,
'loop': directives.unchanged,
'start-at': directives.unchanged,
'speed': directives.unchanged,
'idle-time-limit': directives.unchanged,
'poster': directives.unchanged,
'font-size': directives.unchanged,
'font-family': directives.unchanged,
'size': directives.unchanged,
'theme': directives.unchanged,
'title': directives.unchanged,
't': directives.unchanged,
'author': directives.unchanged,
'author-url': directives.unchanged,
'author-img-url': directives.unchanged,
'path': directives.unchanged,
}
required_arguments = 1
optional_arguments = len(option_spec)
def run(self):
arg = self.arguments[0]
options = dict(self.env.config['sphinxcontrib_asciinema_defaults'])
options.update(self.options)
kw = {'options': options}
path = options.get('path', '')
if path and not path.endswith('/'):
path += '/'
fname = arg if arg.startswith('./') else path + arg
if self.is_file(fname):
kw['content'] = self.to_b64(fname)
kw['type'] = 'local'
logger.debug('asciinema: added cast file %s' % fname)
else:
kw['content'] = arg
kw['type'] = 'remote'
logger.debug('asciinema: added cast id %s' % arg)
if 'path' in kw['options']:
del kw['options']['path']
return [Asciinema(**kw)]
def is_file(self, rel_file):
file_path = self.env.relfn2path(rel_file)[1]
return os.path.isfile(file_path)
def to_b64(self, filename):
import base64
file_path = self.env.relfn2path(filename)[1]
with open(file_path, 'rb') as file:
content = file.read()
b64encoded = base64.b64encode(content)
return b64encoded.decode()
_NODE_VISITORS = {
'html': (visit_html, depart),
'latex': (visit_unsupported, None),
'man': (visit_unsupported, None),
'texinfo': (visit_unsupported, None),
'text': (visit_unsupported, None)
}