Skip to content

Commit 3547548

Browse files
committed
Add forkme on gh tag. Try to update to latest sphinx by vendorizing sphinxcontrib-aafig
1 parent 01c504c commit 3547548

File tree

5 files changed

+230
-9
lines changed

5 files changed

+230
-9
lines changed

doc/_ext/__init__.py

Whitespace-only changes.

doc/_ext/aafig.py

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
sphinxcontrib.aafig
4+
~~~~~~~~~~~~~~~~~~~
5+
6+
Allow embeded ASCII art to be rendered as nice looking images
7+
using the aafigure reStructuredText extension.
8+
9+
See the README file for details.
10+
11+
:author: Leandro Lucarella <llucax@gmail.com>
12+
:license: BOLA, see LICENSE for details
13+
"""
14+
15+
import posixpath
16+
from os import path
17+
try:
18+
from hashlib import sha1 as sha
19+
except ImportError:
20+
from sha import sha
21+
22+
from docutils import nodes
23+
from docutils.parsers.rst.directives import images, nonnegative_int, flag
24+
25+
from sphinx.errors import SphinxError
26+
from sphinx.util import ensuredir, relative_uri
27+
from sphinx.util.compat import Directive
28+
29+
try:
30+
import aafigure
31+
except ImportError:
32+
aafigure = None
33+
34+
35+
DEFAULT_FORMATS = dict(html='svg', latex='pdf', text=None)
36+
37+
38+
def merge_dict(dst, src):
39+
for (k, v) in src.items():
40+
if k not in dst:
41+
dst[k] = v
42+
return dst
43+
44+
45+
def get_basename(text, options, prefix='aafig'):
46+
options = options.copy()
47+
if 'format' in options:
48+
del options['format']
49+
hashkey = text.encode('utf-8') + str(options)
50+
id = sha(hashkey).hexdigest()
51+
return '%s-%s' % (prefix, id)
52+
53+
54+
class AafigError(SphinxError):
55+
category = 'aafig error'
56+
57+
58+
class AafigDirective(images.Image):
59+
"""
60+
Directive to insert an ASCII art figure to be rendered by aafigure.
61+
"""
62+
has_content = True
63+
required_arguments = 0
64+
own_option_spec = dict(
65+
line_width = float,
66+
background = str,
67+
foreground = str,
68+
fill = str,
69+
aspect = nonnegative_int,
70+
textual = flag,
71+
proportional = flag,
72+
)
73+
option_spec = images.Image.option_spec.copy()
74+
option_spec.update(own_option_spec)
75+
76+
def run(self):
77+
aafig_options = dict()
78+
image_attrs = dict()
79+
own_options_keys = self.own_option_spec.keys() + ['scale']
80+
for (k, v) in self.options.items():
81+
if k in own_options_keys:
82+
# convert flags to booleans
83+
if v is None:
84+
v = True
85+
# convert percentage to float
86+
if k == 'scale' or k == 'aspect':
87+
v = float(v) / 100.0
88+
aafig_options[k] = v
89+
del self.options[k]
90+
self.arguments = ['']
91+
(image_node,) = images.Image.run(self)
92+
if isinstance(image_node, nodes.system_message):
93+
return [image_node]
94+
text = '\n'.join(self.content)
95+
image_node.aafig = dict(options = aafig_options, text = text)
96+
return [image_node]
97+
98+
99+
def render_aafig_images(app, doctree):
100+
format_map = app.builder.config.aafig_format
101+
merge_dict(format_map, DEFAULT_FORMATS)
102+
if aafigure is None:
103+
app.builder.warn('aafigure module not installed, ASCII art images '
104+
'will be redered as literal text')
105+
for img in doctree.traverse(nodes.image):
106+
if not hasattr(img, 'aafig'):
107+
continue
108+
if aafigure is None:
109+
img.replace_self(nodes.literal_block(text, text))
110+
continue
111+
options = img.aafig['options']
112+
text = img.aafig['text']
113+
format = app.builder.format
114+
merge_dict(options, app.builder.config.aafig_default_options)
115+
if format in format_map:
116+
options['format'] = format_map[format]
117+
else:
118+
app.builder.warn('unsupported builder format "%s", please '
119+
'add a custom entry in aafig_format config option '
120+
'for this builder' % format)
121+
img.replace_self(nodes.literal_block(text, text))
122+
continue
123+
if options['format'] is None:
124+
img.replace_self(nodes.literal_block(text, text))
125+
continue
126+
try:
127+
fname, outfn, id, extra = render_aafigure(app, text, options)
128+
except AafigError, exc:
129+
app.builder.warn('aafigure error: ' + str(exc))
130+
img.replace_self(nodes.literal_block(text, text))
131+
continue
132+
img['uri'] = fname
133+
# FIXME: find some way to avoid this hack in aafigure
134+
if extra:
135+
(width, height) = [x.split('"')[1] for x in extra.split()]
136+
if not img.has_key('width'):
137+
img['width'] = width
138+
if not img.has_key('height'):
139+
img['height'] = height
140+
141+
142+
def render_aafigure(app, text, options):
143+
"""
144+
Render an ASCII art figure into the requested format output file.
145+
"""
146+
147+
if aafigure is None:
148+
raise AafigError('aafigure module not installed')
149+
150+
fname = get_basename(text, options)
151+
fname = '%s.%s' % (get_basename(text, options), options['format'])
152+
if app.builder.format == 'html':
153+
# HTML
154+
imgpath = relative_uri(app.builder.env.docname, '_images')
155+
relfn = posixpath.join(imgpath, fname)
156+
outfn = path.join(app.builder.outdir, '_images', fname)
157+
else:
158+
# Non-HTML
159+
if app.builder.format != 'latex':
160+
app.builder.warn('aafig: the builder format %s is not officially '
161+
'supported, aafigure images could not work. Please report '
162+
'problems and working builder to avoid this warning in '
163+
'the future' % app.builder.format)
164+
relfn = fname
165+
outfn = path.join(app.builder.outdir, fname)
166+
metadata_fname = '%s.aafig' % outfn
167+
168+
try:
169+
if path.isfile(outfn):
170+
extra = None
171+
if options['format'].lower() == 'svg':
172+
f = None
173+
try:
174+
try:
175+
f = file(metadata_fname, 'r')
176+
extra = f.read()
177+
except:
178+
raise AafigError()
179+
finally:
180+
if f is not None:
181+
f.close()
182+
return relfn, outfn, id, extra
183+
except AafigError:
184+
pass
185+
186+
ensuredir(path.dirname(outfn))
187+
188+
try:
189+
(visitor, output) = aafigure.render(text, outfn, options)
190+
output.close()
191+
except aafigure.UnsupportedFormatError, e:
192+
raise AafigError(str(e))
193+
194+
extra = None
195+
if options['format'].lower() == 'svg':
196+
extra = visitor.get_size_attrs()
197+
f = file(metadata_fname, 'w')
198+
f.write(extra)
199+
f.close()
200+
201+
return relfn, outfn, id, extra
202+
203+
204+
def setup(app):
205+
app.add_directive('aafig', AafigDirective)
206+
app.connect('doctree-read', render_aafig_images)
207+
app.add_config_value('aafig_format', DEFAULT_FORMATS, 'html')
208+
app.add_config_value('aafig_default_options', dict(), 'html')
209+
210+
211+
# vim: set expandtab shiftwidth=4 softtabstop=4 :

doc/_templates/page.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{% extends "!page.html" %}
2+
{% block footer -%}
3+
{{ super() }}
4+
<a href="https://github.com/tony/tmuxp">
5+
<img style="position: absolute; top: 0; right: 0; border: 0;"
6+
src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"
7+
alt="Fork me on GitHub">
8+
</a>
9+
{%- endblock %}

doc/conf.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,14 @@
2424
# This lets us ensure that the source package is imported, and that its
2525
# version is used.
2626
sys.path.insert(0, project_root)
27+
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "_ext")))
2728

2829
# package data
2930
about = {}
3031
with open("../tmuxp/__about__.py") as fp:
3132
exec(fp.read(), about)
3233

3334

34-
# If extensions (or modules to document with autodoc) are in another directory,
35-
# add these directories to sys.path here. If the directory is relative to the
36-
# documentation root, use os.path.abspath to make it absolute, like shown here.
37-
#sys.path.insert(0, os.path.abspath('.'))
38-
3935
# -- General configuration -----------------------------------------------------
4036

4137

@@ -47,8 +43,8 @@
4743
extensions = ['sphinx.ext.autodoc',
4844
'sphinx.ext.intersphinx',
4945
'sphinx.ext.todo',
50-
'sphinxcontrib.aafig',
5146
'sphinxarg.ext',
47+
'aafig',
5248
]
5349

5450
# Add any paths that contain templates here, relative to this directory.
@@ -129,7 +125,12 @@
129125
if on_rtd:
130126
html_theme = 'default'
131127
else:
132-
html_theme = 'pyramid'
128+
try:
129+
import sphinx_rtd_theme
130+
html_theme = "sphinx_rtd_theme"
131+
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
132+
except ImportError:
133+
html_theme = 'pyramid'
133134

134135
#html_theme = 'sphinx_rtd_theme'
135136

doc/requirements.pip

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
-r ../requirements.pip
22
docutils==0.12
3-
sphinx<1.2.1
3+
sphinx
44
reportlab
5-
sphinxcontrib-aafig
65
sphinx-argparse
6+
sphinx-rtd-theme

0 commit comments

Comments
 (0)