X-Git-Url: https://git.llucax.com/z.facultad/75.00/informe.git/blobdiff_plain/03b62e9899469e294fbd7d7e1622ec27cac669c2..af3cc91ddf531e9eb73f3dac73b15ab317a3cbb2:/ext/aafig.py?ds=sidebyside diff --git a/ext/aafig.py b/ext/aafig.py index 7850613..87d2281 100644 --- a/ext/aafig.py +++ b/ext/aafig.py @@ -1,16 +1,15 @@ # -*- coding: utf-8 -*- """ - sphinxcontrib.aafigure - ~~~~~~~~~~~~~~~~~~~~~~ + sphinxcontrib.aafig + ~~~~~~~~~~~~~~~~~~~ - Allow mscgen-formatted :abbr:`MSC (Message Sequence Chart)` graphs to be - included in Sphinx-generated documents inline. + Allow embeded ASCII art to be rendered as nice looking images + using the aafigure reStructuredText extension. See the README file for details. - :copyright: Copyright 2009 by Leandro Lucarella (based on \ - sphinx.ext.graphviz). - :license: BSD, see LICENSE for details. + :author: Leandro Lucarella + :license: BOLA, see LICENSE for details """ import posixpath @@ -27,117 +26,173 @@ from sphinx.errors import SphinxError from sphinx.util import ensuredir from sphinx.util.compat import Directive -import aafigure +try: + import aafigure +except ImportError: + aafigure = None -DEFAULT_PREFIX = 'aafig' -class AafigError(SphinxError): - category = 'aafig error' +DEFAULT_FORMATS = dict(html='svg', latex='pdf', text=None) -class aafig(nodes.General, nodes.Element): - pass +def merge_dict(dst, src): + for (k, v) in src.items(): + if k not in dst: + dst[k] = v + return dst + + +def get_basename(text, options, prefix='aafig'): + options = options.copy() + if 'format' in options: + del options['format'] + hashkey = text.encode('utf-8') + str(options) + id = sha(hashkey).hexdigest() + return '%s-%s' % (prefix, id) -class Aafig(Directive): +class AafigError(SphinxError): + category = 'aafig error' + + +class AafigDirective(directives.images.Image): """ Directive to insert an ASCII art figure to be rendered by aafigure. """ has_content = True required_arguments = 0 - optional_arguments = 0 - final_argument_whitespace = False - option_spec = dict( - scale = float, + own_option_spec = dict( line_width = float, background = str, foreground = str, fill = str, - aspect = float, + aspect = directives.nonnegative_int, textual = directives.flag, proportional = directives.flag, ) + option_spec = directives.images.Image.option_spec.copy() + option_spec.update(own_option_spec) def run(self): - node = aafig() - node['text'] = '\n'.join(self.content) - if 'textual' in self.options: self.options['textual'] = True - if 'proportional' in self.options: self.options['proportional'] = True - node['options'] = self.options - return [node] - - -def render_aafigure(self, text, options, prefix): + aafig_options = dict() + image_attrs = dict() + own_options_keys = self.own_option_spec.keys() + ['scale'] + for (k, v) in self.options.items(): + if k in own_options_keys: + # convert flags to booleans + if v is None: + v = True + # convert percentage to float + if k == 'scale' or k == 'aspect': + v = float(v) / 100.0 + aafig_options[k] = v + del self.options[k] + self.arguments = [''] + (image_node,) = directives.images.Image.run(self) + if isinstance(image_node, nodes.system_message): + return [image_node] + text = '\n'.join(self.content) + image_node.aafig = dict(options = aafig_options, text = text) + return [image_node] + + +def render_aafig_images(app, doctree): + format_map = app.builder.config.aafig_format + merge_dict(format_map, DEFAULT_FORMATS) + for img in doctree.traverse(nodes.image): + if not hasattr(img, 'aafig'): + continue + + options = img.aafig['options'] + text = img.aafig['text'] + format = app.builder.format + merge_dict(options, app.builder.config.aafig_default_options) + if format in format_map: + options['format'] = format_map[format] + else: + app.builder.warn('unsupported builder format "%s", please ' + 'add a custom entry in aafig_format config option ' + 'for this builder' % format) + img.replace_self(nodes.literal_block(text, text)) + continue + if options['format'] is None: + img.replace_self(nodes.literal_block(text, text)) + continue + try: + fname, outfn, id, extra = render_aafigure(app, text, options) + except AafigError, exc: + app.builder.warn('aafigure error: ' + str(exc)) + img.replace_self(nodes.literal_block(text, text)) + continue + img['uri'] = fname + # FIXME: find some way to avoid this hack in aafigure + if extra: + (width, height) = [x.split('"')[1] for x in extra.split()] + if not img.has_key('width'): + img['width'] = width + if not img.has_key('height'): + img['height'] = height + + +def render_aafigure(app, text, options): """ Render an ASCII art figure into the requested format output file. """ - hashkey = text.encode('utf-8') + str(options) - id = sha(hashkey).hexdigest() - fname = '%s-%s.%s' % (prefix, id, options['format']) - if hasattr(self.builder, 'imgpath'): + + if aafigure is None: + raise AafigError('aafigure module not installed') + + fname = get_basename(text, options) + fname = '%s.%s' % (get_basename(text, options), options['format']) + if hasattr(app.builder, 'imgpath'): # HTML - relfn = posixpath.join(self.builder.imgpath, fname) - outfn = path.join(self.builder.outdir, '_images', fname) + relfn = posixpath.join(app.builder.imgpath, fname) + outfn = path.join(app.builder.outdir, '_images', fname) else: # LaTeX relfn = fname - outfn = path.join(self.builder.outdir, fname) + outfn = path.join(app.builder.outdir, fname) + metadata_fname = '%s.aafig' % outfn - if path.isfile(outfn): - return relfn, outfn, id + try: + if path.isfile(outfn): + extra = None + if options['format'].lower() == 'svg': + f = None + try: + try: + f = file(metadata_fname, 'r') + extra = f.read() + except: + raise AafigError() + finally: + if f is not None: + f.close() + return relfn, outfn, id, extra + except AafigError: + pass ensuredir(path.dirname(outfn)) try: - aafigure.render(text, outfn, options) + (visitor, output) = aafigure.render(text, outfn, options) + output.close() except aafigure.UnsupportedFormatError, e: - raise MscgenError(str(e)) - - return relfn, outfn, id - - -def render_html(self, node, text, options, prefix=DEFAULT_PREFIX, imgcls=None): - try: - options['format'] = self.builder.config.aafig_format['html'] - fname, outfn, id = render_aafigure(self, text, options, prefix) - except AafigError, exc: - self.builder.warn('aafigure error: ' + str(exc)) - raise nodes.SkipNode - - self.body.append(self.starttag(node, 'p', CLASS='aafigure')) - if fname is None: - self.body.append(self.encode(text)) - else: - imgcss = imgcls and 'class="%s"' % imgcls or '' - # nothing in image map - self.body.append('%s\n' % - (fname, self.encode(text).strip(), imgcss)) - self.body.append('

\n') - raise nodes.SkipNode - - -def html_visit(self, node): - render_html(self, node, node['text'], node['options']) - - -def render_latex(self, node, text, options, prefix=DEFAULT_PREFIX): - try: - options['format'] = self.builder.config.aafig_format['latex'] - fname, outfn, id = render_aafigure(self, text, options, prefix) - except AafigError, exc: - self.builder.warn('aafigure error: ' + str(exc)) - raise nodes.SkipNode + raise AafigError(str(e)) - if fname is not None: - self.body.append('\\includegraphics[]{%s}' % fname) - raise nodes.SkipNode + extra = None + if options['format'].lower() == 'svg': + extra = visitor.get_size_attrs() + f = file(metadata_fname, 'w') + f.write(extra) + f.close() + return relfn, outfn, id, extra -def latex_visit(self, node): - render_latex(self, node, node['text'], node['options']) def setup(app): - app.add_node(aafig, html=(html_visit, None), latex=(latex_visit, None)) - app.add_directive('aafig', Aafig) - app.add_config_value('aafig_format', dict(html='svg', latex='pdf'), 'html') + app.add_directive('aafig', AafigDirective) + app.connect('doctree-read', render_aafig_images) + app.add_config_value('aafig_format', DEFAULT_FORMATS, 'html') + app.add_config_value('aafig_default_options', dict(), 'html')