On Thu, Dec 15, 2016 at 06:01:42PM +0100, Daniel Vetter wrote: > On Wed, Dec 07, 2016 at 09:49:44AM +0100, Markus Heiser wrote: > > This patch brings scalable figure, image handling and a concept to > > embed *render* markups: > > > > * DOT (http://www.graphviz.org) > > * SVG > > > > For image handling use the 'image' replacement:: > > > > .. kernel-image:: svg_image.svg > > :alt: simple SVG image > > > > For figure handling use the 'figure' replacement:: > > > > .. kernel-figure:: svg_image.svg > > :alt: simple SVG image > > > > SVG image example > > > > Embed *render* markups (or languages) like Graphviz's **DOC** is > > provided by the *render* directive.:: > > > > .. kernel-render:: DOT > > :alt: foobar digraph > > :caption: Embedded **DOT** (Graphviz) code. > > > > digraph foo { > > "bar" -> "baz"; > > } > > > > The *render* directive is a concept to integrate *render* markups and > > languages, yet supported markups: > > > > * DOT: render embedded Graphviz's **DOC** > > * SVG: render embedded Scalable Vector Graphics (**SVG**) > > > > Signed-off-by: Markus Heiser <markus.heiser@xxxxxxxxxxx> > > I started playing around with this. Another thing I've noticed after adding my hack, and I don't even know how that works in your code so top comment: The auto-generated .dot file for in-line kernel-render directives seems to depend upon the content and doesn't get auto-removed. Which means when I change back to an old version of an inline dot it's not regenerated. Which also means I don't get to see the stderr output again. For the kernel-render directive I think it'd be better to pass the graph to dot via stdin. -Daniel > > > --- > > Documentation/conf.py | 2 +- > > Documentation/doc-guide/hello.dot | 3 + > > Documentation/doc-guide/sphinx.rst | 90 +++++- > > Documentation/doc-guide/svg_image.svg | 10 + > > Documentation/process/changes.rst | 8 +- > > Documentation/sphinx/kfigure.py | 505 ++++++++++++++++++++++++++++++++++ > > 6 files changed, 612 insertions(+), 6 deletions(-) > > create mode 100644 Documentation/doc-guide/hello.dot > > create mode 100644 Documentation/doc-guide/svg_image.svg > > create mode 100644 Documentation/sphinx/kfigure.py > > > > diff --git a/Documentation/conf.py b/Documentation/conf.py > > index 1ac958c..19ea030 100644 > > --- a/Documentation/conf.py > > +++ b/Documentation/conf.py > > @@ -34,7 +34,7 @@ from load_config import loadConfig > > # Add any Sphinx extension module names here, as strings. They can be > > # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom > > # ones. > > -extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain'] > > +extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain', 'kfigure'] > > > > # The name of the math extension changed on Sphinx 1.4 > > if major == 1 and minor > 3: > > diff --git a/Documentation/doc-guide/hello.dot b/Documentation/doc-guide/hello.dot > > new file mode 100644 > > index 0000000..504621d > > --- /dev/null > > +++ b/Documentation/doc-guide/hello.dot > > @@ -0,0 +1,3 @@ > > +graph G { > > + Hello -- World > > +} > > diff --git a/Documentation/doc-guide/sphinx.rst b/Documentation/doc-guide/sphinx.rst > > index 96fe7ccb..c7c7876 100644 > > --- a/Documentation/doc-guide/sphinx.rst > > +++ b/Documentation/doc-guide/sphinx.rst > > @@ -34,8 +34,10 @@ format-specific subdirectories under ``Documentation/output``. > > > > To generate documentation, Sphinx (``sphinx-build``) must obviously be > > installed. For prettier HTML output, the Read the Docs Sphinx theme > > -(``sphinx_rtd_theme``) is used if available. For PDF output, ``rst2pdf`` is also > > -needed. All of these are widely available and packaged in distributions. > > +(``sphinx_rtd_theme``) is used if available. For PDF output you'll also need > > +``XeLaTeX`` and CairoSVG (http://cairosvg.org) or alternatively ``convert(1)`` > > +from ImageMagick (https://www.imagemagick.org). All of these are widely > > +available and packaged in distributions. > > > > To pass extra options to Sphinx, you can use the ``SPHINXOPTS`` make > > variable. For example, use ``make SPHINXOPTS=-v htmldocs`` to get more verbose > > @@ -217,3 +219,87 @@ Rendered as: > > * .. _`last row`: > > > > - column 3 > > + > > + > > +Figures & Images > > +================ > > + > > +If you want to add an image, you should use the ``kernel-figure`` and > > +``kernel-image`` directives. E.g. to insert a figure with a scalable > > +image format use SVG:: > > + > > + .. kernel-figure:: svg_image.svg > > + :alt: simple SVG image > > + > > + SVG image example > > + > > +.. kernel-figure:: svg_image.svg > > + :alt: simple SVG image > > + > > + SVG image example > > + > > +The kernel figure (and image) directive support **DOT** formated files, see > > + > > +* DOT: http://graphviz.org/pdf/dotguide.pdf > > +* Graphviz: http://www.graphviz.org/content/dot-language > > + > > +A simple example:: > > + > > + .. kernel-figure:: hello.dot > > + :alt: hello world > > + > > + DOT's hello world example > > + > > +.. kernel-figure:: hello.dot > > + :alt: hello world > > + > > + DOT's hello world example > > + > > +Embed *render* markups (or languages) like Graphviz's **DOC** is provided by the > > s/DOC/DOT/ I think? Same in the commit message. > > > +``kernel-render`` directives.:: > > + > > + .. kernel-render:: DOT > > + :alt: foobar digraph > > + :caption: Embedded **DOT** (Graphviz) code. > > + > > + digraph foo { > > + "bar" -> "baz"; > > + } > > + > > +How this will be rendered depends on the installed tools. If Graphviz is > > +installed, you will see an vector image. If not the raw markup is inserted as > > +*literal-block*. > > + > > +.. kernel-render:: DOT > > + :alt: foobar digraph > > + :caption: Embedded **DOT** (Graphviz) code. > > + > > + digraph foo { > > + "bar" -> "baz"; > > + } > > + > > +The *render* directive has all the options known from the *figure* directive, > > +plus option ``caption``. If ``caption`` has a value, a *figure* node is > > +inserted. If not, a *image* node is inserted. > > + > > +Embedded **SVG**:: > > + > > + .. kernel-render:: SVG > > + :caption: Embedded **SVG** markup. > > + :alt: so-nw-arrow > > + > > + <?xml version="1.0" encoding="UTF-8"?> > > + <svg xmlns="http://www.w3.org/2000/svg" version="1.1" ...> > > + ... > > + </svg> > > + > > +.. kernel-render:: SVG > > + :caption: Embedded **SVG** markup. > > + :alt: so-nw-arrow > > + > > + <?xml version="1.0" encoding="UTF-8"?> > > + <svg xmlns="http://www.w3.org/2000/svg" > > + version="1.1" baseProfile="full" width="70px" height="40px" viewBox="0 0 700 400"> > > + <line x1="180" y1="370" x2="500" y2="50" stroke="black" stroke-width="15px"/> > > + <polygon points="585 0 525 25 585 50" transform="rotate(135 525 25)"/> > > + </svg> > > diff --git a/Documentation/doc-guide/svg_image.svg b/Documentation/doc-guide/svg_image.svg > > new file mode 100644 > > index 0000000..5405f85 > > --- /dev/null > > +++ b/Documentation/doc-guide/svg_image.svg > > @@ -0,0 +1,10 @@ > > +<?xml version="1.0" encoding="UTF-8"?> > > +<!-- originate: https://commons.wikimedia.org/wiki/File:Variable_Resistor.svg --> > > +<svg xmlns="http://www.w3.org/2000/svg" > > + version="1.1" baseProfile="full" > > + width="70px" height="40px" viewBox="0 0 700 400"> > > + <line x1="0" y1="200" x2="700" y2="200" stroke="black" stroke-width="20px"/> > > + <rect x="100" y="100" width="500" height="200" fill="white" stroke="black" stroke-width="20px"/> > > + <line x1="180" y1="370" x2="500" y2="50" stroke="black" stroke-width="15px"/> > > + <polygon points="585 0 525 25 585 50" transform="rotate(135 525 25)"/> > > +</svg> > > diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst > > index 56ce661..de284ca 100644 > > --- a/Documentation/process/changes.rst > > +++ b/Documentation/process/changes.rst > > @@ -318,9 +318,11 @@ PDF outputs, it is recommended to use version 1.4.6. > > .. note:: > > > > Please notice that, for PDF and LaTeX output, you'll also need ``XeLaTeX`` > > - version 3.14159265. Depending on the distribution, you may also need > > - to install a series of ``texlive`` packages that provide the minimal > > - set of functionalities required for ``XeLaTex`` to work. > > + version 3.14159265. Depending on the distribution, you may also need to > > + install a series of ``texlive`` packages that provide the minimal set of > > + functionalities required for ``XeLaTex`` to work. For PDF output you'll also > > + need CairoSVG (http://cairosvg.org) or alternatively ``convert(1)`` from > > + ImageMagick (https://www.imagemagick.org). > > > > Other tools > > ----------- > > diff --git a/Documentation/sphinx/kfigure.py b/Documentation/sphinx/kfigure.py > > new file mode 100644 > > index 0000000..76425b4 > > --- /dev/null > > +++ b/Documentation/sphinx/kfigure.py > > @@ -0,0 +1,505 @@ > > +# -*- coding: utf-8; mode: python -*- > > +# pylint: disable=C0103 > > +u""" > > + scalable figure and image handling > > + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > > + > > + Sphinx extension which implements scalable image handling. > > + > > + :copyright: Copyright (C) 2016 Markus Heiser > > + :license: GPL Version 2, June 1991 see Linux/COPYING for details. > > + > > + The build for image formats depence on image's source format and output's > > + destination format. This extension implement methods to simplify image > > + handling from the author's POV. Directives like ``kernel-figure`` implement > > + methods *to* always get the best output-format even if some tools are not > > + installed.For more details take a look at ``convert_image(...)`` which is > > + the core of all conversions. > > + > > + * ``.. kernel-image``: for image handling / ``.. image::`` replacement > > + > > + * ``.. kernel-figure``: for figure handling / ``.. figure::`` replacement > > + > > + * ``.. kernel-render``: for render markup / a concept to embed *render* > > + markups (or languages). Supported markups (see ``RENDER_MARKUP_EXT``) > > + > > + + ``DOT``: render embedded Graphviz's **DOC** > > + + ``SVG``: render embedded Scalable Vector Graphics (**SVG**) > > + + ... *developable* > > + > > + Used tools: > > + > > + * ``dot(1)``: Graphviz (http://www.graphviz.org). If Graphviz is not > > + available, the DOT language is inserted as literal-block. > > + > > + * SVG to PDF: To generate PDF, you need at least one of this tools: > > + > > + - CairoSVG (http://cairosvg.org) if installed or alternatively > > + - ``convert(1)``: ImageMagick (https://www.imagemagick.org) > > + > > + List of customizations: > > + > > + * generate PDF from SVG / used by PDF (LaTeX) builder > > + > > + * generate SVG (html-builder) and PDF (latex-builder) from DOT files. > > + DOT: see http://www.graphviz.org/content/dot-language > > + > > + """ > > + > > +import os > > +from os import path > > +import subprocess > > +from hashlib import sha1 > > + > > +from docutils import nodes > > +from docutils.statemachine import ViewList > > +from docutils.parsers.rst import directives > > +from docutils.parsers.rst.directives import images > > + > > +from sphinx.directives import patches > > + > > +__version__ = '1.0' > > + > > +# simple helper > > +# ------------- > > + > > +def which(cmd): > > + """Searches the ``cmd`` in the ``PATH`` enviroment. > > + > > + This *which* searches the PATH for executable ``cmd`` . First match is > > + returned, if nothing is found, ``None` is returned. > > + """ > > + envpath = os.environ.get('PATH', None) or os.defpath > > + for folder in envpath.split(os.pathsep): > > + fname = folder + os.sep + cmd > > + if path.isfile(fname): > > + return fname > > + > > +def mkdir(folder, mode=0o775): > > + if not path.isdir(folder): > > + os.makedirs(folder, mode) > > + > > +def isNewer(path1, path2): > > + """Returns True if ``path1`` is newer than ``path2`` > > + > > + If ``path1`` exists and is newer than ``path2`` the function returns > > + ``True`` is returned otherwise ``False`` > > + """ > > + return (path.exists(path1) > > + and os.stat(path1).st_ctime > os.stat(path2).st_ctime) > > + > > +# def debug_handle(self, node): # pylint: disable=W0613 > > +# from linuxdoc.kernel_doc import CONSOLE > > +# CONSOLE() > > + > > +def pass_handle(self, node): # pylint: disable=W0613 > > + pass > > + > > +# setup conversion tools and sphinx extension > > +# ------------------------------------------- > > + > > +# Graphviz's dot(1) support > > +dot_cmd = which('dot') > > + > > +# ImageMagick' convert(1) support > > +convert_cmd = which('convert') > > + > > +# cairosvg support > > +try: > > + import cairosvg # pylint: disable=C0413 > > +except ImportError: > > + cairosvg = None > > + > > + > > +def setup(app): > > + # check toolchain first > > + app.connect('builder-inited', checkTools) > > + > > + # image handling > > + app.add_directive("kernel-image", KernelImage) > > + app.add_node(kernel_image, > > + html = (visit_kernel_image, pass_handle), > > + latex = (visit_kernel_image, pass_handle), > > + texinfo = (visit_kernel_image, pass_handle), > > + text = (visit_kernel_image, pass_handle), > > + man = (visit_kernel_image, pass_handle), ) > > + > > + # figure handling > > + app.add_directive("kernel-figure", KernelFigure) > > + app.add_node(kernel_figure, > > + html = (visit_kernel_figure, pass_handle), > > + latex = (visit_kernel_figure, pass_handle), > > + texinfo = (visit_kernel_figure, pass_handle), > > + text = (visit_kernel_figure, pass_handle), > > + man = (visit_kernel_figure, pass_handle), ) > > + > > + # render handling > > + app.add_directive('kernel-render', KernelRender) > > + app.add_node(kernel_render, > > + html = (visit_kernel_render, pass_handle), > > + latex = (visit_kernel_render, pass_handle), > > + texinfo = (visit_kernel_render, pass_handle), > > + text = (visit_kernel_render, pass_handle), > > + man = (visit_kernel_render, pass_handle), ) > > + > > + return dict( > > + version = __version__, > > + parallel_read_safe = True, > > + parallel_write_safe = True > > + ) > > + > > + > > +def checkTools(app): > > + u""" > > + Check available build tools and log some *verbose* messages. > > + > > + This function is called once, when the builder is initiated. > > + """ > > + app.verbose("kfigure: check installed tools ...") > > + if dot_cmd: > > + app.verbose("use dot(1) from: " + dot_cmd) > > + else: > > + app.warn("dot(1) not found, for better output quality install " > > + "graphviz from http://www.graphviz.org") > > + if cairosvg: > > + app.verbose("use CairoSVG from: " + str(cairosvg)) > > + if convert_cmd: > > + app.verbose("use ImageMagick: " + convert_cmd) > > + if cairosvg is None and convert_cmd is None: > > + app.warn("no SVG to PDF conversion available, " > > + "install CairoSVG (http://cairosvg.org) or alternatively " > > + "``convert(1)`` from ImageMagick (https://www.imagemagick.org)") > > + > > + > > +# integrate conversion tools > > +# -------------------------- > > + > > +RENDER_MARKUP_EXT = { > > + # The '.ext' must be handled by convert_image(..) function's *in_ext* input. > > + # <name> : <.ext> > > + 'DOT' : '.dot' > > + , 'SVG' : '.svg' > > +} > > + > > +def convert_image(img_node, translator): # pylint: disable=R0912 > > + """Convert an image node for the builder. > > + > > + Different builder prefer different image formats, e.g. *latex* builder > > + prefer PDF while *html* builder prefer SVG format for images. > > + > > + This function handles outputs image formats in depence of source the format > > + of the image and the translator's output format. This also means to > > + manipulate/update the *image* dictionary of the builder (``builder.images``) > > + > > + """ > > + fname, in_ext = path.splitext(path.basename(img_node['uri'])) > > + src_fname = path.join(translator.builder.srcdir, img_node['uri']) > > + src_folder = path.dirname(img_node['uri']) > > + out_dir = translator.builder.outdir > > + dst_fname = None > > + > > + # in kernel builds, use 'make SPHINXOPTS=-v' to see verbose messages > > + verbose = translator.builder.app.verbose > > + warn = translator.builder.warn > > + > > + verbose('assert best format for: ' + img_node['uri']) > > + > > + if in_ext == '.dot': > > + > > + # ---------- > > + # handle DOT > > + # ---------- > > + > > + if not dot_cmd: > > + verbose("dot from graphviz not available / include DOT raw.") > > + with open(src_fname, "r") as dot: > > + data = dot.read() > > + node = nodes.literal_block(data, data) > > + img_node.replace_self(node) > > + > > + elif translator.builder.format == 'latex': > > + dst_fname = path.join(out_dir, fname + '.pdf') > > + > > + elif translator.builder.format == 'html': > > + dst_fname = path.join(out_dir, src_folder, fname + '.svg') > > + else: > > + # all other builder formats will include DOT as raw > > + with open(src_fname, "r") as dot: > > + data = dot.read() > > + node = nodes.literal_block(data, data) > > + img_node.replace_self(node) > > + > > + > > + elif in_ext == '.svg': > > + > > + # ---------- > > + # handle SVG > > + # ---------- > > + > > + if translator.builder.format == 'latex': > > + if cairosvg is None and convert_cmd is None: > > + warn("no SVG to PDF conversion available") > > + else: > > + dst_fname = path.join(out_dir, fname + '.pdf') > > + > > + if dst_fname: > > + name = dst_fname[len(out_dir) + 1:] > > + # the builder needs not to copy one more time, so pop it if exists. > > + translator.builder.images.pop(img_node['uri'], None) > > + img_node['uri'] = dst_fname > > + img_node['candidates'] = {'*': dst_fname} > > + > > + if isNewer(dst_fname, src_fname): > > + verbose("convert: %s allready exists and is newer" % name) > > + else: > > + mkdir(path.dirname(dst_fname)) > > + > > + if in_ext == '.dot': > > + verbose('convert DOT to: {out}/' + name) > > + dot2format(src_fname, dst_fname) > > + > > + elif in_ext == '.svg': > > + verbose('convert SVG to: {out}/' + name) > > + svg2pdf(src_fname, dst_fname) > > + > > +def dot2format(dot_fname, out_fname): > > + """Converts DOT file to ``out_fname`` using ``dot(1)``. > > + > > + * ``dot_fname`` pathname of the input DOT file, including extension ``.dot`` > > + * ``out_fname`` pathname of the output file, including format extension > > + > > + The *format extension* depends on the ``dot`` command (see ``man dot`` > > + option ``-Txxx``). Normally you will use one of the following extensions: > > + > > + - ``.ps`` for PostScript, > > + - ``.svg`` or ``svgz`` for Structured Vector Graphics, > > + - ``.fig`` for XFIG graphics and > > + - ``.png`` or ``gif`` for common bitmap graphics. > > + > > + """ > > + out_format = path.splitext(out_fname)[1][1:] > > + cmd = [dot_cmd, '-T%s' % out_format, dot_fname] > > Hm, adding '-v' when we run in verbose sphinx mode might be useful for > more debugging here. > ' > > + exit_code = 42 > > + with open(out_fname, "w") as out: > > + exit_code = subprocess.call( > > + cmd, stdout = out, stderr = subprocess.PIPE ) > > + out.flush() > > This eats stderr, which is a bit unhelpful when debugging dot (or in the > case below, svg) formatting issues. I've hacked something up, but would be > good someone versed in python fixes it ;-) > > Cheers, Daniel > > > + return bool(exit_code == 0) > > + > > +def svg2pdf(svg_fname, pdf_fname): > > + """Converts SVG to PDF with CairoSVG or ``convert(1)`` command. > > + > > + Uses CairoSVG (http://cairosvg.org) if installed or alternatively > > + ``convert(1)`` from ImageMagick (https://www.imagemagick.org) for > > + conversion. Returns ``True`` on success and ``False`` if an error occurred > > + (e.g. none of the conversion tool is available). > > + > > + * ``svg_fname`` pathname of the input SVG file with extension (``.svg``) > > + * ``pdf_name`` pathname of the output PDF file with extension (``.pdf``) > > + > > + """ > > + if cairosvg: > > + # pylint: disable=E1101 > > + cairosvg.svg2pdf(url = svg_fname, write_to = pdf_fname) > > + return True > > + if convert_cmd: > > + cmd = [convert_cmd, svg_fname, pdf_fname] > > + exit_code = subprocess.call( > > + cmd, stdout = subprocess.PIPE, stderr = subprocess.PIPE ) > > + return bool(exit_code == 0) > > + return False > > + > > + > > +# image handling > > +# --------------------- > > + > > +def visit_kernel_image(self, node): # pylint: disable=W0613 > > + """Visitor of the ``kernel_image`` Node. > > + > > + Handles the ``image`` child-node with the ``convert_image(...)``. > > + """ > > + img_node = node[0] > > + convert_image(img_node, self) > > + > > +class kernel_image(nodes.General, nodes.Element): > > + """Node for ``kernel-image`` directive.""" > > + pass > > + > > +class KernelImage(images.Image): > > + u"""KernelImage directive > > + > > + Earns everything from ``.. image::`` directive, except *remote URI* and > > + *glob* pattern. The KernelImage wraps a image node into a > > + kernel_image node. See ``visit_kernel_image``. > > + """ > > + > > + def run(self): > > + uri = self.arguments[0] > > + if uri.endswith('.*') or uri.find('://') != -1: > > + raise self.severe( > > + 'Error in "%s: %s": glob pattern and remote images are not allowed' > > + % (self.name, uri)) > > + result = images.Image.run(self) > > + if len(result) == 2 or isinstance(result[0], nodes.system_message): > > + return result > > + (image_node,) = result > > + # wrap image node into a kernel_image node / see visitors > > + node = kernel_image('', image_node) > > + return [node] > > + > > +# figure handling > > +# --------------------- > > + > > +def visit_kernel_figure(self, node): # pylint: disable=W0613 > > + """Visitor of the ``kernel_figure`` Node. > > + > > + Handles the ``image`` child-node with the ``convert_image(...)``. > > + """ > > + img_node = node[0][0] > > + convert_image(img_node, self) > > + > > +class kernel_figure(nodes.General, nodes.Element): > > + """Node for ``kernel-figure`` directive.""" > > + > > +class KernelFigure(patches.Figure): > > + u"""KernelImage directive > > + > > + Earns everything from ``.. figure::`` directive, except *remote URI* and > > + *glob* pattern. The KernelFigure wraps a figure node into a kernel_figure > > + node. See ``visit_kernel_figure``. > > + """ > > + > > + def run(self): > > + uri = self.arguments[0] > > + if uri.endswith('.*') or uri.find('://') != -1: > > + raise self.severe( > > + 'Error in "%s: %s":' > > + ' glob pattern and remote images are not allowed' > > + % (self.name, uri)) > > + result = patches.Figure.run(self) > > + if len(result) == 2 or isinstance(result[0], nodes.system_message): > > + return result > > + (figure_node,) = result > > + # wrap figure node into a kernel_figure node / see visitors > > + node = kernel_figure('', figure_node) > > + return [node] > > + > > + > > +# render handling > > +# --------------------- > > + > > +def visit_kernel_render(self, node): > > + """Visitor of the ``kernel_render`` Node. > > + > > + If rendering tools available, save the markup of the ``literal_block`` child > > + node into a file and replace the ``literal_block`` node with a new created > > + ``image`` node, pointing to the saved markup file. Afterwards, handle the > > + image child-node with the ``convert_image(...)``. > > + """ > > + > > + verbose = self.builder.app.verbose > > + warn = self.builder.warn > > + srclang = node.get('srclang') > > + > > + verbose('visit kernel-render node lang: "%s"' % (srclang)) > > + > > + tmp_ext = RENDER_MARKUP_EXT.get(srclang, None) > > + if tmp_ext is None: > > + warn('kernel-render: "%s" unknow / include raw.' % (srclang)) > > + return > > + > > + literal_block = node[0] > > + code = literal_block.astext() > > + > > + if not dot_cmd and tmp_ext == '.dot': > > + verbose("dot from graphviz not available / include raw.") > > + tmp_ext = None > > + > > + if tmp_ext: > > + hashobj = code.encode('utf-8') # str(node.attributes) > > + fname = '%s-%s' % (srclang, sha1(hashobj).hexdigest()) > > + tmp_fname = path.join( > > + self.builder.outdir, self.builder.imagedir, fname + tmp_ext) > > + > > + if not path.isfile(tmp_fname): > > + mkdir(path.dirname(tmp_fname)) > > + with open(tmp_fname, "w") as out: > > + out.write(code) > > + > > + image_node = nodes.image(node.rawsource, **node.attributes) > > + image_node['uri'] = tmp_fname > > + > > + literal_block.replace_self(image_node) > > + convert_image(image_node, self) > > + > > + > > +class kernel_render(nodes.General, nodes.Inline, nodes.Element): > > + """Node for ``kernel-render`` directive.""" > > + pass > > + > > +class KernelRender(patches.Figure): > > + u"""KernelRender directive > > + > > + Render content by external tool. Has all the options known from the > > + *figure* directive, plus option ``caption``. If ``caption`` has a > > + value, a figure node with the *caption* is inserted. If not, a image node is > > + inserted. > > + > > + The KernelRender directive wraps the text of the directive into a > > + literal_block node and wraps it into a kernel_render node. See > > + ``visit_kernel_render``. > > + """ > > + has_content = True > > + required_arguments = 1 > > + optional_arguments = 0 > > + final_argument_whitespace = False > > + > > + # earn options from 'figure' > > + option_spec = patches.Figure.option_spec.copy() > > + option_spec['caption'] = directives.unchanged > > + > > + def run(self): > > + return [self.build_node()] > > + > > + def build_node(self): > > + > > + srclang = self.arguments[0].strip() > > + if srclang not in RENDER_MARKUP_EXT.keys(): > > + return [self.state_machine.reporter.warning( > > + 'Unknow source language "%s", use one of: %s.' % ( > > + srclang, ",".join(RENDER_MARKUP_EXT.keys())), > > + line=self.lineno)] > > + > > + code = '\n'.join(self.content) > > + if not code.strip(): > > + return [self.state_machine.reporter.warning( > > + 'Ignoring "%s" directive without content.' % ( > > + self.name), > > + line=self.lineno)] > > + > > + node = kernel_render() > > + node['alt'] = self.options.get('alt','') > > + node['srclang'] = srclang > > + literal_node = nodes.literal_block(code, code) > > + node += literal_node > > + > > + caption = self.options.get('caption') > > + if caption: > > + # parse cation's content > > + parsed = nodes.Element() > > + self.state.nested_parse( > > + ViewList([caption], source=''), self.content_offset, parsed) > > + caption_node = nodes.caption( > > + parsed[0].rawsource, '', *parsed[0].children) > > + caption_node.source = parsed[0].source > > + caption_node.line = parsed[0].line > > + > > + figure_node = nodes.figure('', node) > > + for k,v in self.options.items(): > > + figure_node[k] = v > > + figure_node += caption_node > > + > > + node = figure_node > > + > > + return node > > + > > -- > > 2.7.4 > > > > -- > Daniel Vetter > Software Engineer, Intel Corporation > http://blog.ffwll.ch -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch -- To unsubscribe from this list: send the line "unsubscribe linux-doc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html