You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

448 lines
13 KiB

# Copyright 2012-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import logging
logger = logging.getLogger('bcdocs')
# Terminal punctuation where a space is not needed before.
PUNCTUATION_CHARACTERS = ('.', ',', '?', '!', ':', ';')
class BaseStyle:
def __init__(self, doc, indent_width=2):
self.doc = doc
self.indent_width = indent_width
self._indent = 0
self.keep_data = True
@property
def indentation(self):
return self._indent
@indentation.setter
def indentation(self, value):
self._indent = value
def new_paragraph(self):
return '\n%s' % self.spaces()
def indent(self):
self._indent += 1
def dedent(self):
if self._indent > 0:
self._indent -= 1
def spaces(self):
return ' ' * (self._indent * self.indent_width)
def bold(self, s):
return s
def ref(self, link, title=None):
return link
def h2(self, s):
return s
def h3(self, s):
return s
def underline(self, s):
return s
def italics(self, s):
return s
def add_trailing_space_to_previous_write(self):
# Adds a trailing space if none exists. This is mainly used for
# ensuring inline code and links are separated from surrounding text.
last_write = self.doc.pop_write()
if last_write is None:
last_write = ''
if last_write != '' and last_write[-1] != ' ':
last_write += ' '
self.doc.push_write(last_write)
class ReSTStyle(BaseStyle):
def __init__(self, doc, indent_width=2):
BaseStyle.__init__(self, doc, indent_width)
self.do_p = True
self.a_href = None
self.list_depth = 0
def new_paragraph(self):
self.doc.write('\n\n%s' % self.spaces())
def new_line(self):
self.doc.write('\n%s' % self.spaces())
def _start_inline(self, markup):
# Insert space between any directly adjacent bold and italic inlines to
# avoid situations like ``**abc***def*``.
try:
last_write = self.doc.peek_write()
except IndexError:
pass
else:
if last_write in ('*', '**') and markup in ('*', '**'):
self.doc.write(' ')
self.doc.write(markup)
def _end_inline(self, markup):
# Remove empty and self-closing tags like ``<b></b>`` and ``<b/>``.
# If we simply translate that directly then we end up with something
# like ****, which rst will assume is a heading instead of an empty
# bold.
last_write = self.doc.pop_write()
if last_write == markup:
return
self.doc.push_write(last_write)
self.doc.write(markup)
def start_bold(self, attrs=None):
self._start_inline('**')
def end_bold(self):
self._end_inline('**')
def start_b(self, attrs=None):
self.doc.do_translation = True
self.start_bold(attrs)
def end_b(self):
self.doc.do_translation = False
self.end_bold()
def bold(self, s):
if s:
self.start_bold()
self.doc.write(s)
self.end_bold()
def ref(self, title, link=None):
if link is None:
link = title
self.doc.write(f':doc:`{title} <{link}>`')
def _heading(self, s, border_char):
border = border_char * len(s)
self.new_paragraph()
self.doc.write(f'{border}\n{s}\n{border}')
self.new_paragraph()
def h1(self, s):
self._heading(s, '*')
def h2(self, s):
self._heading(s, '=')
def h3(self, s):
self._heading(s, '-')
def start_italics(self, attrs=None):
self._start_inline('*')
def end_italics(self):
self._end_inline('*')
def italics(self, s):
if s:
self.start_italics()
self.doc.write(s)
self.end_italics()
def start_p(self, attrs=None):
if self.do_p:
self.doc.write('\n\n%s' % self.spaces())
def end_p(self):
if self.do_p:
self.doc.write('\n\n%s' % self.spaces())
def start_code(self, attrs=None):
self.doc.do_translation = True
self.add_trailing_space_to_previous_write()
self._start_inline('``')
def end_code(self):
self.doc.do_translation = False
self._end_inline('``')
def code(self, s):
if s:
self.start_code()
self.doc.write(s)
self.end_code()
def start_note(self, attrs=None):
self.new_paragraph()
self.doc.write('.. note::')
self.indent()
self.new_paragraph()
def end_note(self):
self.dedent()
self.new_paragraph()
def start_important(self, attrs=None):
self.new_paragraph()
self.doc.write('.. warning::')
self.indent()
self.new_paragraph()
def end_important(self):
self.dedent()
self.new_paragraph()
def start_danger(self, attrs=None):
self.new_paragraph()
self.doc.write('.. danger::')
self.indent()
self.new_paragraph()
def end_danger(self):
self.dedent()
self.new_paragraph()
def start_a(self, attrs=None):
# Write an empty space to guard against zero whitespace
# before an "a" tag. Example: hi<a>Example</a>
self.add_trailing_space_to_previous_write()
if attrs:
for attr_key, attr_value in attrs:
if attr_key == 'href':
# Removes unnecessary whitespace around the href link.
# Example: <a href=" http://example.com ">Example</a>
self.a_href = attr_value.strip()
self.doc.write('`')
else:
# There are some model documentation that
# looks like this: <a>DescribeInstances</a>.
# In this case we just write out an empty
# string.
self.doc.write(' ')
self.doc.do_translation = True
def link_target_definition(self, refname, link):
self.doc.writeln(f'.. _{refname}: {link}')
def sphinx_reference_label(self, label, text=None):
if text is None:
text = label
if self.doc.target == 'html':
self.doc.write(f':ref:`{text} <{label}>`')
else:
self.doc.write(text)
def _clean_link_text(self):
doc = self.doc
# Pop till we reach the link start character to retrieve link text.
last_write = doc.pop_write()
while not last_write.startswith('`'):
last_write = doc.pop_write() + last_write
if last_write != '':
# Remove whitespace from the start of link text.
if last_write.startswith('` '):
last_write = f'`{last_write[1:].lstrip(" ")}'
doc.push_write(last_write)
def end_a(self, next_child=None):
self.doc.do_translation = False
if self.a_href:
self._clean_link_text()
last_write = self.doc.pop_write()
last_write = last_write.rstrip(' ')
if last_write and last_write != '`':
if ':' in last_write:
last_write = last_write.replace(':', r'\:')
self.doc.push_write(last_write)
self.doc.push_write(' <%s>`__' % self.a_href)
elif last_write == '`':
# Look at start_a(). It will do a self.doc.write('`')
# which is the start of the link title. If that is the
# case then there was no link text. We should just
# use an inline link. The syntax of this is
# `<http://url>`_
self.doc.push_write('`<%s>`__' % self.a_href)
else:
self.doc.push_write(self.a_href)
self.doc.hrefs[self.a_href] = self.a_href
self.doc.write('`__')
self.a_href = None
def start_i(self, attrs=None):
self.doc.do_translation = True
self.start_italics()
def end_i(self):
self.doc.do_translation = False
self.end_italics()
def start_li(self, attrs=None):
self.new_line()
self.do_p = False
self.doc.write('* ')
def end_li(self):
self.do_p = True
self.new_line()
def li(self, s):
if s:
self.start_li()
self.doc.writeln(s)
self.end_li()
def start_ul(self, attrs=None):
if self.list_depth != 0:
self.indent()
self.list_depth += 1
self.new_paragraph()
def end_ul(self):
self.list_depth -= 1
if self.list_depth != 0:
self.dedent()
self.new_paragraph()
def start_ol(self, attrs=None):
# TODO: Need to control the bullets used for LI items
if self.list_depth != 0:
self.indent()
self.list_depth += 1
self.new_paragraph()
def end_ol(self):
self.list_depth -= 1
if self.list_depth != 0:
self.dedent()
self.new_paragraph()
def start_examples(self, attrs=None):
self.doc.keep_data = False
def end_examples(self):
self.doc.keep_data = True
def start_fullname(self, attrs=None):
self.doc.keep_data = False
def end_fullname(self):
self.doc.keep_data = True
def start_codeblock(self, attrs=None):
self.doc.write('::')
self.indent()
self.new_paragraph()
def end_codeblock(self):
self.dedent()
self.new_paragraph()
def codeblock(self, code):
"""
Literal code blocks are introduced by ending a paragraph with
the special marker ::. The literal block must be indented
(and, like all paragraphs, separated from the surrounding
ones by blank lines).
"""
self.start_codeblock()
self.doc.writeln(code)
self.end_codeblock()
def toctree(self):
if self.doc.target == 'html':
self.doc.write('\n.. toctree::\n')
self.doc.write(' :maxdepth: 1\n')
self.doc.write(' :titlesonly:\n\n')
else:
self.start_ul()
def tocitem(self, item, file_name=None):
if self.doc.target == 'man':
self.li(item)
else:
if file_name:
self.doc.writeln(' %s' % file_name)
else:
self.doc.writeln(' %s' % item)
def hidden_toctree(self):
if self.doc.target == 'html':
self.doc.write('\n.. toctree::\n')
self.doc.write(' :maxdepth: 1\n')
self.doc.write(' :hidden:\n\n')
def hidden_tocitem(self, item):
if self.doc.target == 'html':
self.tocitem(item)
def table_of_contents(self, title=None, depth=None):
self.doc.write('.. contents:: ')
if title is not None:
self.doc.writeln(title)
if depth is not None:
self.doc.writeln(' :depth: %s' % depth)
def start_sphinx_py_class(self, class_name):
self.new_paragraph()
self.doc.write('.. py:class:: %s' % class_name)
self.indent()
self.new_paragraph()
def end_sphinx_py_class(self):
self.dedent()
self.new_paragraph()
def start_sphinx_py_method(self, method_name, parameters=None):
self.new_paragraph()
content = '.. py:method:: %s' % method_name
if parameters is not None:
content += '(%s)' % parameters
self.doc.write(content)
self.indent()
self.new_paragraph()
def end_sphinx_py_method(self):
self.dedent()
self.new_paragraph()
def start_sphinx_py_attr(self, attr_name):
self.new_paragraph()
self.doc.write('.. py:attribute:: %s' % attr_name)
self.indent()
self.new_paragraph()
def end_sphinx_py_attr(self):
self.dedent()
self.new_paragraph()
def write_py_doc_string(self, docstring):
docstring_lines = docstring.splitlines()
for docstring_line in docstring_lines:
self.doc.writeln(docstring_line)
def external_link(self, title, link):
if self.doc.target == 'html':
self.doc.write(f'`{title} <{link}>`_')
else:
self.doc.write(title)
def internal_link(self, title, page):
if self.doc.target == 'html':
self.doc.write(f':doc:`{title} <{page}>`')
else:
self.doc.write(title)

Powered by BW's shoe-string budget.