Skip to content

Instantly share code, notes, and snippets.

@abits
Forked from dvarrazzo/ditaa_rst.py
Created January 9, 2014 14:20
Show Gist options
  • Save abits/8334807 to your computer and use it in GitHub Desktop.
Save abits/8334807 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
"""Custom reST_ directive for ditaa_ integration.
.. _reST: http://docutils.sourceforge.net/rst.html
.. _ditaa: http://ditaa.sourceforge.net/
"""
import os
import tempfile
from zlib import adler32
from subprocess import Popen, PIPE
from docutils.nodes import image, literal_block
from docutils.parsers.rst import Directive, directives
class DiTAA(Directive):
required_arguments = 0
optional_arguments = 0
has_content = True
_ditaa_flags = [
'no-antialias', 'no-separation', 'round-corners', 'no-shadows', ]
option_spec = {
# 'name': directives.uri, # sanitize me
'class': directives.class_option,
'alt': directives.unchanged,
'scale': directives.percentage,
}
for f in _ditaa_flags:
option_spec[f] = directives.flag
def run(self):
settings = self.state.document.settings
path = getattr(settings, 'ditaa_dir', '.')
if not os.path.exists(path):
os.makedirs(path)
nodes = []
# Y U NO STDINNNNN...
body = '\n'.join(self.content)
tf = tempfile.NamedTemporaryFile()
tf.write(body.encode('utf8'))
tf.flush()
# make a name
name = self.options.pop('name', None)
if not name:
name = "%08x" % (adler32(body) & 0xffffffff)
if not name.endswith('.png'):
name += '.png'
alt = self.options.get('alt', 'ditaa diagram')
classes = self.options.pop('class', ['ditaa'])
cmdline = ['ditaa', tf.name, os.path.join(path, name),
'--overwrite', '--encoding', 'utf8']
if 'scale' in self.options:
cmdline.extend(['--scale',
"%f" % (float(self.options['scale']) / 100)])
for f in self._ditaa_flags:
if f in self.options:
cmdline.append("--" + f)
try:
p = Popen(cmdline, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
except Exception, exc:
error = self.state_machine.reporter.error(
'Failed to run ditaa: %s' % (exc, ),
literal_block(self.block_text, self.block_text),
line=self.lineno)
nodes.append(error)
else:
if p.returncode == 0:
url = name
urlpath = getattr(settings, 'ditaa_url_path')
if not urlpath and path != '.':
urlpath = path
if urlpath:
url = urlpath + '/' + name
imgnode = image(uri=url, classes=classes, alt=alt)
nodes.append(imgnode)
else:
error = self.state_machine.reporter.error(
'Error in "%s" directive: %s' % (self.name, err),
literal_block(self.block_text, self.block_text),
line=self.lineno)
nodes.append(error)
return nodes
def get_ditaa_settings_spec():
from docutils import SettingsSpec
ss = SettingsSpec()
ss.settings_spec = (
'Diagrams Generation Options',
None,
(
("Diagrams output directory. Default: '.'",
['--ditaa-dir'],
{'default': '.', 'metavar': 'DIR'}),
("Diagrams url path. Defaults to DIR",
['--ditaa-url-path'],
{'metavar': 'PATH'}),
))
return ss
def pubprog():
"""Just an example of how to pass options to publish_programmatically"""
directives.register_directive('ditaa', DiTAA)
from docutils.core import publish_string
print publish_string(open('ditaa_rst.txt').read(),
writer_name='html',
settings_spec=get_ditaa_settings_spec(),
settings_overrides={'ditaa_dir': 'qux'})
if __name__ == '__main__':
directives.register_directive('ditaa', DiTAA)
from docutils.core import publish_cmdline
publish_cmdline(writer_name='html', description="HTML with DiTAA",
settings_spec=get_ditaa_settings_spec())
Integrating reST_ with ditaa_
=============================
.. _reST: http://docutils.sourceforge.net/rst.html
.. _ditaa: http://ditaa.sourceforge.net/
This is a test, with a diagram:
.. ditaa::
:alt: Demo diagram
:scale: 150%
+--------+ +-------+ +-------+
| | --+ ditaa +--> | |
| Text | +-------+ |diagram|
|Document| |!magic!| | |
| {d}| | | | |
+---+----+ +-------+ +-------+
: ^
| Lots of work |
+-------------------------+
It should result in a diagram or something.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment