class htmltree(object):
    """
    Helper class for generating html documents
    """
    m2h = markdown2html()

    def __init__(self, tag_name='div', cls='', *args, **kwargs):
        self.attrib = {'class': cls} if cls else {}
        self.tag_name = tag_name
        self.root = ET.Element(tag_name, self.attrib)
        self.counter = 0
        self.roots = [self.root]

    def tag(self, tag_name, value='', attrib={}, no_escape=True, **kwargs):
        """
        Method will create and append element with tag based on tag_name value
        :param tag_name: tag name
        :param value: tag value
        :param attrib: optional attribute dict
        :param no_escape: whether to escape value
        :return: element
        """
        attrib_copy = {}
        if 'cls' in kwargs:
            attrib_copy['class'] = kwargs.pop('cls')

        attrib_copy.update(attrib)
        attrib_copy.update(kwargs)

        element = ET.Element(tag_name, attrib_copy)
        element.text = cgi.escape(value) if not no_escape else value
        self.current().append(element)
        return element

    def tagc(self, tag_name, cls='', value=''):
        if cls:
            return self.tag(tag_name, value, {'class': cls})
        return self.tag(tag_name, value)

    def current(self):
        """
        :return: current top
        """
        return self.roots[self.counter]

    def add(self, element):
        """
        :return: appends element to top
        """
        return self.current().append(element)

    def item_list_title(self,
                        item_field,
                        add_link=False,
                        add_id=True,
                        text=None):
        """
        Method creates and appends header with level
        If subtitle is given href to title will consist of subtitle

        :param title: main header title
        :param subtitle: optional subtitle
        :param level: h level
        :param hide_subtitle: hide subtitle section
        :return:
        """
        if add_link:
            with self.open('a', attrib={'href': '#' + item_field.href_id}):
                self.item_list_title(item_field,
                                     add_link=False,
                                     add_id=add_id,
                                     text=text)
        else:
            attrib = {'id': item_field.href_id} if add_id else {}
            with self.open('h3', attrib=attrib):
                self.span(text or item_field.get('name', 'key', 'href_name'))
        return self

    def main_section_title(self, item, attrib={}, **kwargs):
        """
        Method creates level 2 header also with "on the side" href with icon
          to this href
        :type item: ist.nodes.TypeSelection or ist.nodes.TypeRecord or ist.nodes.TypeAbstract
        """
        # with self.open('span', '', { 'class': 'pull-right side-anchor' }):
        #     href_attrib = { 'href': '#' + item.href_id }
        #     href_attrib.update({ 'title': 'Permalink to this section' })
        #     with self.open('a', '', href_attrib):
        #         self.span(' ', { 'class': 'glyphicon glyphicon-link', 'aria-hidden': 'true' })
        with self.open('h2'):
            self.tag('a', item.href_name, attrib={'href': '#' + item.href_id})
        # self.tag('h2', item.href_name, attrib, **kwargs)

    def mark_as_obsolete(self, element):
        """
        :type item: ist.nodes.TypeSelection or ist.nodes.TypeRecord or ist.nodes.TypeAbstract
        """
        with self.open('div', cls='obsolete'):
            self.tag('p', 'Obsolete', cls='obsolete-title')
            self.description(element.attributes.obsolete)

    def add_clear(self):
        self.div('', cls='clear')

    def h2(self, value='', attrib={}, **kwargs):
        """
        Method creates level 3 header
        :param value: header title
        :param attrib: optional attribute
        :return: element
        """
        # attrib.update(self.generate_id(value))
        self.tag('h2', value, attrib, **kwargs)

    def h3(self, value='', attrib={}, **kwargs):
        """
        Method creates level 3 header
        :param value: header title
        :param attrib: optional attribute
        :return: element
        """
        return self.tag('h3', value, attrib, **kwargs)

    def h4(self, value='', attrib={}, **kwargs):
        """
        Method creates level 4 header
        :param value: header title
        :param attrib: optional attribute
        :return: element
        """
        return self.tag('h4', value, attrib, **kwargs)

    def h5(self, value='', attrib={}, **kwargs):
        """
        Method creates level 5 header
        :param value: header title
        :param attrib: optional attribute
        :return: element
        """
        return self.tag('h5', value, attrib, **kwargs)

    def h6(self, value='', attrib={}, **kwargs):
        """
        Method creates level 6 header
        :param value: header title
        :param attrib: optional attribute
        :return: element
        """
        return self.tag('h6', value, attrib, **kwargs)

    def ul(self, value='', attrib={}, **kwargs):
        """
        Method creates ul element
        :param value: ul optional text
        :param attrib: optional attribute
        :return: element
        """
        return self.tag('ul', value, attrib, **kwargs)

    def ol(self, value='', attrib={}, **kwargs):
        """
        Method creates ol element
        :param value: ol optional text
        :param attrib: optional attribute
        :return: element
        """
        return self.tag('ol', value, attrib, **kwargs)

    def span(self, value='', attrib={}, **kwargs):
        """
        Method creates span element
        :param value: span optional text
        :param attrib: optional attribute
        :return: element
        """
        return self.tag('span', value, attrib, **kwargs)

    def spanc(self, cls, value=''):
        return self.tagc('span', cls, value)

    def info(self, value='', attrib={"class": 'info'}, **kwargs):
        """
        Method creates info element
        :param value: span optional text
        :param attrib: optional attribute, default has class of 'leading-text'
        :return: element
        """
        return self.tag('span', value, attrib, **kwargs)

    def div(self, value='', attrib={}, **kwargs):
        """
        Method creates div element
        :param value: div optional text
        :param attrib: optional attribute
        :return: element
        """
        return self.tag('div', value, attrib, **kwargs)

    def bold(self, value='', attrib={}, **kwargs):
        """
        Method creates bold element
        :param value: bold optional text
        :param attrib: optional attribute
        :return: element
        """
        return self.tag('strong', value, attrib, **kwargs)

    def italic(self, value='', attrib={}, **kwargs):
        """
        Method creates em element
        :param value: em optional text
        :param attrib: optional attribute
        :return: element
        """
        return self.tag('em', value, attrib, **kwargs)

    def li(self, value='', attrib={}, **kwargs):
        """
        Method creates li element
        :param value: li optional text
        :param attrib: optional attribute
        :return: element
        """
        return self.tag('li', value, attrib, **kwargs)

    def link(self, target, text='', ns=''):
        """
        Method creates link element based on given attributes
        :param target: machine link name
        :param text: link title
        :param ns: namespace for link
        """
        return self.tag('a',
                        text if text else target,
                        attrib=self.generate_href(target, ns))

    def link_to_main(self, item, text=None):
        """
        :type item: ist.nodes.TypeSelection or ist.nodes.TypeRecord or ist.nodes.TypeAbstract
        """
        # return self.tag('a', item.name + '(' + item.id + ')', self.generate_href(item.id))
        return self.tag('a', text or item.href_name,
                        {'href': '#' + item.href_id})

    def open(self, tag_name, value='', attrib={}, **kwargs):
        """
        Method opens current element, shifts current top.
          When adding new elements, current top is this newly created
        :param tag_name: tag name
        :param value: optional text
        :param attrib: optional attribs
        :return: self
        """
        element = self.tag(tag_name, value, attrib, **kwargs)
        self.roots.append(element)
        return self

    def openc(self, tag_name, cls=''):
        """
        Method opens current element, shifts current top.
          When adding new elements, current top is this newly created
        :param tag_name: tag name
        :param cls: class name
        :return: self
        """
        if cls:
            element = self.tag(tag_name, '', {"class": cls})
        else:
            element = self.tag(tag_name, '')
        self.roots.append(element)
        return self

    def description(self, value):
        """
        method will append description element to top
        element has predefined class
        :param value:
        :return:
        """
        # self.tag('span', 'DESCRIPTION', attrib={ 'class': 'desc-title' })
        if not value:
            return self.tag('div',
                            'no description provided',
                            cls='description no-description')

        value = self.m2h.parse(value, reduce_to_tree=True)
        value.attrib['class'] = 'description'
        self.add(value)
        # return self.tag('div', value, { 'class': 'description' }, no_escape=True)

    def __enter__(self):
        """
        Enter the runtime context related to this object.
        :return:
        """
        self.counter += 1
        return self

    def __exit__(self, exception_type, exception_value, traceback):
        """
        Exit the runtime context related to this object.
        :param exception_type:
        :param exception_value:
        :param traceback:
        :return:
        """
        # add debug info
        if exception_type:
            return False

        self.counter -= 1
        self.roots.pop()
        return self

    def dump(self):
        """
        Debug html dump
        :return:
        """
        return ET.tostring(self.root, method='html')

    def __repr__(self):
        return '<htmltree object>'

    def style(self, location):
        """
        Method add css link style
        :param location: css file location relative to server
        :return: element
        """
        self.tag('link',
                 '',
                 rel='stylesheet',
                 type='text/css',
                 media='screen',
                 href=location)

    def script(self, location):
        """
        Method add css link script
        :param location: css file location relative to server
        :return: element
        """
        self.tag('script', '', attrib={}, type='text/javascript', src=location)

    def id(self, id):
        """
        Method sets id to root element
        :param id: id value
        """
        self.root.attrib['id'] = id

    @staticmethod
    def secure(value):
        """
        Method for securing input value
        :param value: value to be secured
        :return: safe value consisting of numbers and alphabet chars and _ char
        """
        if value:
            value = re.sub(r'\W+', '-', value)
            value = re.sub(r'-$', '', value)
            return value
        return ''

    @staticmethod
    def chain_values(value, sub_value=''):
        """
        Method for chaining given values
        Used in href and id creation
        :param value: main value
        :param sub_value: optional sub value
        :return: secured chained value: "values-subvalue"  or "value" in lowercase
        """
        chain = value if not sub_value else sub_value + '-' + value
        return htmltree.secure(chain).lower()
Esempio n. 2
0
class texlist(list):
    """
    Helper class for creating latex document
    """
    m2h = markdown2html()

    def __init__(self, name=''):
        super(list, self).__init__()
        self.name = name
        self.counter = 1

    def tag(self, field_name, *values):
        """
        Method adds \name{value1}{value2}
        :param field_name:
        :param values:
        :return: self
        """
        self.slash(field_name)
        for value in values:
            self.add_s(value)

        return self

    def KeyItem(self, name='', description=''):
        """
        Method add KeyItem tag
        :param name:
        :param description:
        :return:
        """
        self.slash('KeyItem')
        if name:
            self.add_s(name)
        if description:
            with self:
                self.add_description_field(description)

        return self

    def add(self, value=''):
        """
        Method add value surrounded with braces
        :param value:
        :return:
        """
        self.append("{" + str(value) + "}")
        return self

    def add_s(self, value=''):
        '''
        Add field with value escaped
        '''
        self.append("{" + self.name_mode(value) + "}")
        return self

    def add_d(self, value=''):
        '''
        Add field with value underscores replaced by dashed
        '''
        self.append("{" + self.name_mode(value) + "}")
        return self

    def open(self):
        """
        Add open brace
        """
        self.append('{')
        return self

    def close(self):
        """
        Add close brace
        """
        self.append('}')
        return self

    def hyperB(self, value, ns='IT::'):
        """
        Add HyperB element
        :param value: id
        :param ns: optional namespace
        :return: self
        """
        if __debug__:
            self.tag('hyperB', self.name_mode((ns if ns.endswith('::') else ns + '::') + value))
            self.add(self.plain_mode((ns if ns.endswith('::') else ns + '::') + value))
        else:
            self.tag('hyperB', self.name_mode((ns if ns.endswith('::') else ns + '::') + value))
            self.add(self.plain_mode(value))
        return self

    def slash(self, value=''):
        """
        Add \value
        :param value:
        :return: self
        """
        self.append('\\')
        if value:
            self.append(value)

        return self

    def Alink(self, url, ns="IT::", text=None):
        """
        Method adds Alink section
        :param url: Alink url
        :param ns: optional namespace
        :param text: optional text (otherwise url is used)
        :return: self
        """
        ns = str(ns)
        url = str(url)
        ns = ns if ns.endswith('::') else ns + '::'
        ns = ns if url.find('::') == -1 else ''

        if __debug__:
            self.tag('Alink', self.name_mode(ns + url))
            self.add(self.plain_mode(ns + (url if text is None else text)))
        else:
            self.tag('Alink', self.name_mode(ns + url))
            self.add(self.plain_mode(url if text is None else text))

        return self

    def AddDoc(self, value):
        """
        Adds \AddDoc{value}
        :return: self
        """
        self.slash('AddDoc')
        self.add(self.plain_mode(value))

    def textlangle(self, value, namespace='\\it '):
        """
        Add < value > with optional italic
        :param value:
        :param namespace:
        :return:
        """
        self.slash('textlangle')
        self.add(self.plain_mode(namespace + str(value) + ' ').lower())
        self.slash('textrangle')

        return self

    def newline(self):
        """
        Adds newline
        :return: self
        """
        self.append('\n')
        return self

    def element(self):
        """
        Resets counter
        :return:
        """
        self.counter = 0
        return self

    def open_element(self, name):
        """
        Opens current element by name
        \begin{name}
        :param name: element name
        :return: self
        """
        self.tag('begin', name)
        return self

    def close_element(self, name):
        """
        Closes current element by name
        \end{name}
        :param name: element name
        :return: self
        """
        self.tag('end', name)
        return self

    def __enter__(self):
        """
        Enter the runtime context related to this object.
        :return:
        """
        if self.counter == 0:
            self.open_element(self.name)
        else:
            self.open()
        self.counter += 1
        return self

    def __exit__(self, exception_type, exception_value, tb):
        """
        Exit the runtime context related to this object.
        :param exception_type:
        :param exception_value:
        :param tb:
        :return:
        """
        # add debug info
        if exception_type:
            return False

        self.counter -= 1
        if self.counter == 0:
            self.close_element(self.name)
        else:
            self.close()
        return self

    def add_description_field(self, value):
        """
        Adds complex description field
        :param value: string value with markdown support
        :return: self
        """
        self.add(self.description(value))

    def description(self, value):
        """
        Creates complex description field
        :param value: string value with markdown support
        :return: self
        """
        # return self.escape (value.strip ().replace ('\n', '\\\\'))
        html = self.m2h.parse(str(value), True)
        latex = Html2Latex(html)
        result = latex.to_latex()
        desc_result = list()
        for r in result:
            if r.startswith('{$') and r.endswith('$}'):
                desc_result.append(self.equation_mode(r))
            else:
                desc_result.append(self.plain_mode(r))
        return ''.join(desc_result)

    @staticmethod
    def equation_mode(value):
        """
        Method will ensure that value will be valid equation in latex
        :type value: str or list
        :param value: value tu be secured
        :return:
        """
        return value if type(value) is str else ''.join(value)

    @staticmethod
    def plain_mode(value):
        """
        Method will ensure that value will be valid text in latex
        no equation
        :type value: str or list
        :param value: value tu be secured
        :return:
        """
        value = value if type(value) is str else ''.join(value)
        value = value \
            .replace('_', '\\_') \
            .replace("'", "'") \
            .replace('->', '$\\rightarrow$') \
            .replace('<-', '$\\leftarrow$') \
            .replace('\n\n', '\n')
        return str(value)

    @staticmethod
    def name_mode(value):
        """
        Method will ensure that value will be valid name in latex
        This method will replace all characters except a-z A-Z 0-9 and -
        :type value: str or list
        :param value: value tu be secured
        :return:
        """
        value = value if type(value) is str else ''.join(value)
        return re.sub('[^a-zA-Z0-9-]', '', value)
class TexList(list):
    """
    Helper class for creating latex document
    """
    special_chars = [
        ['''\\''', r'{\textbackslash}'],
        [r'{', r'{\{}'],
        [r'}', r'{\}}'],
        [r'%', r'{\%}'],
        [r'$', r'{\$}'],
        [r'#', r'{\#}'],
        [r'&', r'{\&}'],
        [r'_', r'{\_}'],
        [r'^', r'{\^{}}'],
        [r'|', r'{\textbar}'],
        [r'>', r'{\textgreater}'],
        [r'<', r'{\textless}'],
        [r'->', r'{\rightarrow}'],
        [r'<-', r'{\leftarrow}'],
    ]
    m2h = markdown2html()
    _OPEN = '{'
    _CLOSE = '}'
    _SLASH = '\\'
    _IT = 'it'
    _SPACE = ' '
    _BEGIN = 'begin'
    _END = 'end'
    _NEWLINE = '\n'
    _TAB = '\t'
    _TEXTLANGLE = 'textlangle'
    _TEXTRANGLE = 'textrangle'
    """Will create well-formatted latex file but result will be INVALID, for debug purposes only"""
    PRETTY_FORMAT = False

    def __init__(self):
        super(TexList, self).__init__()
        self.levels = {}
        self.l = 0
        self.open_name = ''
        self.append('')

    def add(self, value, t=None):
        if t is None:
            self.append(self._OPEN + str(value) + self._CLOSE)
        else:
            self.append(self._OPEN + str(t(value)) + self._CLOSE)

    def comment(self, value):
        if not self.PRETTY_FORMAT:
            return
        self.append(" % " + str(value))

    def to_string(self, fix_newlines=True):
        if not fix_newlines:
            return ''.join(self)

        tmp_list = list()
        nl = False
        for x in self:
            if x == '':
                continue
            if x == self._NEWLINE:
                if nl:
                    tmp_list.append(x)
                nl = False
            else:
                tmp_list.append(x)
                if str(x).strip():
                    nl = True
        return ''.join(tmp_list)

    def _function_call(self, args, mode=None, func=None):
        if func:
            self.slash(func)

        # secure arguments
        args = args if type(args) is list else [args]
        if mode is None:
            mode = [None] * len(args)
        mode = mode if type(mode) is list else [mode]

        for i in range(len(args)):
            self.add(str(args[i]), mode[i])

    def slash(self, value=''):
        """
        Add \value
        """
        if value:
            self.append(self._SLASH + str(value))
        else:
            self.append(self._SLASH)

    def macro_alink(self, item, text=None):
        """
        Adds \Alink{item.href_id}{item.href_name}, will create href
        :type item: ist.nodes.TypeSelection or ist.nodes.TypeRecord or ist.nodes.TypeAbstract or Unicode
        """
        self._function_call(func='Alink',
                            args=[item.href_id, text or item.href_name],
                            mode=[self.TYPE_NONE, self.TYPE_PLAIN])

    def macro_alink_(self, url, text):
        t = TexList()
        t._function_call(func='Alink',
                         args=[url, text or text],
                         mode=[self.TYPE_NAME, self.TYPE_PLAIN])
        self.append(str(t))

    def macro_hyper_b(self, item, text=None):
        """
        Adds \hyperB{item.href_id}{item.href_name}, will register href
        :type item: Parsable or ist.nodes.TypeSelection or ist.nodes.TypeRecord or ist.nodes.TypeAbstract
        """
        self._function_call(func='hyperB',
                            args=[item.href_id, text or item.href_name],
                            mode=[self.TYPE_NONE, self.TYPE_PLAIN])

    def macro_add_doc(self, item):
        """
        Adds \hyperB{item.href_id}{item.href_name}, will register href
        :type item: Parsable or ist.nodes.TypeSelection or ist.nodes.TypeRecord or ist.nodes.TypeAbstract
        """
        self._function_call(func='AddDoc',
                            args=[item.href_name],
                            mode=[self.TYPE_PLAIN])

    def macro_text_lr_angle(self, value, mode=None, italic=True):
        self.slash(self._TEXTLANGLE)
        with self:
            self.append(self._SPACE)
            self._function_call(func=self._IT if italic else None,
                                args=value,
                                mode=mode if mode else self.TYPE_PLAIN)
            self.append(self._SPACE)
        self.slash(self._TEXTRANGLE)

    def begin(self, name):
        self._newline()
        self.slash(self._BEGIN)
        self.add(name)
        self._newline()

    def end(self, name):
        self._newline()
        self.slash(self._END)
        self.add(name)
        self._newline()

    def __enter__(self):
        """
        Enter the runtime context related to this object.
        """
        if self.open_name:
            self.levels[self.l] = self.open_name
            self.l += 1
            self.slash(self.open_name)
            self.open_name = ''
        else:
            self.levels[self.l] = False
            self.l += 1
            self.append(self._OPEN)
        return self

    def __exit__(self, exception_type, exception_value, tb):
        """
        Exit the runtime context related to this object.
        """
        if exception_type:
            return False

        self.l -= 1
        if not self.levels[self.l]:
            self.append(self._CLOSE)
        return self

    def _newline(self):
        if not self.PRETTY_FORMAT:
            return
        if self[-1] != self._NEWLINE:
            self.append(self._NEWLINE)

    def _tab(self, n=1):
        if not self.PRETTY_FORMAT:
            return
        self.append(self._TAB * n)

    @classmethod
    def description(cls, value):
        if not value.strip():
            return ''

        html = TexList.m2h.parse2latex(str(value))
        latex = Html2Latex(html)
        result = latex.to_latex()
        return ''.join(result)

    @classmethod
    def equation_mode(cls, value):
        """
        Method will ensure that value will be valid equation in latex
        :type value: str or list
        :param value: value tu be secured
        :return:
        """
        return value if type(value) is str else ''.join(value)

    @classmethod
    def plain_mode(cls, value):
        """
        Method will ensure that value will be valid text in latex
        no equation
        :type value: str or list
        :param value: value tu be secured
        :return:
        """
        value = value if type(value) is str else ''.join(value)

        value = cls.prepare_plain(value)
        return cls.finish_plain(value)

    @classmethod
    def prepare_plain(cls, value):
        # replace all characters with placeholders
        # since some characters contains other non allowed chars
        for i in range(len(cls.special_chars)):
            value = value.replace(cls.special_chars[i][0],
                                  '(-(-{}-)-)'.format(i))
        return value

    @classmethod
    def finish_plain(cls, value):
        # replace placeholders with escaped characters
        for i in range(len(cls.special_chars)):
            value = value.replace('(-(-{}-)-)'.format(i),
                                  cls.special_chars[i][1])
        return str(value)

    @classmethod
    def name_mode(cls, value):
        """
        Method will ensure that value will be valid name in latex
        This method will replace all characters except a-z A-Z 0-9 and -
        :type value: str or list
        :param value: value tu be secured
        :return:
        """
        value = value if type(value) is str else ''.join(value)
        return re.sub('[^a-zA-Z0-9-]+', '-', value)

    @classmethod
    def auto_mode(cls, values):
        result = list()
        for value in values:
            if value.startswith('{$') and value.endswith('$}'):
                result.append(TexList.TYPE_EQ(value))
            elif value.startswith('\Alink'):
                result.append(value)
            else:
                result.append(TexList.TYPE_PLAIN(value))
        return ''.join(result).rstrip('\\')

    @classmethod
    def none_mode(cls, values):
        if type(values) is str:
            return values
        return ''.join(values)

    def __str__(self):
        return ''.join(self)

    TYPE_NAME = name_mode
    TYPE_EQ = equation_mode
    TYPE_PLAIN = plain_mode
    TYPE_AUTO = auto_mode
    TYPE_NONE = none_mode

    def item_open(self, name):
        self.open_name = name
        return self
Esempio n. 4
0
class texlist(list):
    """
    Helper class for creating latex document
    """
    m2h = markdown2html()

    def __init__(self, name=''):
        super(list, self).__init__()
        self.name = name
        self.counter = 1

    def tag(self, field_name, *values):
        """
        Method adds \name{value1}{value2}
        :param field_name:
        :param values:
        :return: self
        """
        self.slash(field_name)
        for value in values:
            self.add_s(value)

        return self

    def KeyItem(self, name='', description=''):
        """
        Method add KeyItem tag
        :param name:
        :param description:
        :return:
        """
        self.slash('KeyItem')
        if name:
            self.add_s(name)
        if description:
            with self:
                self.add_description_field(description)

        return self

    def add(self, value=''):
        """
        Method add value surrounded with braces
        :param value:
        :return:
        """
        self.append("{" + value + "}")
        return self

    def add_s(self, value=''):
        '''
        Add field with value escaped
        '''
        self.append("{" + self.escape(value) + "}")
        return self

    def add_d(self, value=''):
        '''
        Add field with value underscores replaced by dashed
        '''
        self.append("{" + self.secure(value) + "}")
        return self

    def open(self):
        """
        Add open brace
        """
        self.append('{')
        return self

    def close(self):
        """
        Add close brace
        """
        self.append('}')
        return self

    def hyperB(self, value, ns='IT::'):
        """
        Add HyperB element
        :param value: id
        :param ns: optional namespace
        :return: self
        """
        if __debug__:
            self.tag(
                'hyperB',
                self.secure((ns if ns.endswith('::') else ns + '::') + value))
            self.add(
                self.escape((ns if ns.endswith('::') else ns + '::') + value))
        else:
            self.tag(
                'hyperB',
                self.secure((ns if ns.endswith('::') else ns + '::') + value))
            self.add(self.escape(value))
        return self

    def slash(self, value=''):
        """
        Add \value
        :param value:
        :return: self
        """
        self.append('\\')
        if value:
            self.append(value)

        return self

    def Alink(self, url, ns="IT::", text=None):
        """
        Method adds Alink section
        :param url: Alink url
        :param ns: optional namespace
        :param text: optional text (otherwise url is used)
        :return: self
        """
        ns = ns if ns.endswith('::') else ns + '::'
        ns = ns if url.find('::') == -1 else ''

        if __debug__:
            self.tag('Alink', self.secure(ns + url))
            self.add(self.escape(ns + (url if text is None else text)))
        else:
            self.tag('Alink', self.secure(ns + url))
            self.add(self.escape(url if text is None else text))

        return self

    def AddDoc(self, value):
        """
        Add \AddDoc{value}
        :return: self
        """
        self.slash('AddDoc', self.escape(value))

    def textlangle(self, value, namespace='\\it '):
        """
        Add < value > with optional italic
        :param value:
        :param namespace:
        :return:
        """
        self.slash('textlangle')
        self.add(self.escape(namespace + value + ' ').lower())
        self.slash('textrangle')

        return self

    def newline(self):
        """
        Adds newline
        :return: self
        """
        self.append('\n')
        return self

    def element(self):
        """
        Resets counter
        :return:
        """
        self.counter = 0
        return self

    def open_element(self, name):
        """
        Opens current element by name
        \begin{name}
        :param name: element name
        :return: self
        """
        self.tag('begin', name)
        return self

    def close_element(self, name):
        """
        Closes current element by name
        \end{name}
        :param name: element name
        :return: self
        """
        self.tag('end', name)
        return self

    def __enter__(self):
        """
        Enter the runtime context related to this object.
        :return:
        """
        if self.counter == 0:
            self.open_element(self.name)
        else:
            self.open()
        self.counter += 1
        return self

    def __exit__(self, exception_type, exception_value, traceback):
        """
        Exit the runtime context related to this object.
        :param exception_type:
        :param exception_value:
        :param traceback:
        :return:
        """
        self.counter -= 1
        if self.counter == 0:
            self.close_element(self.name)
        else:
            self.close()
        return self

    def add_description_field(self, value):
        """
        Adds complex description field
        :param value: string value with markdown support
        :return: self
        """
        self.add(self.description(value))

    def description(self, value):
        """
        Creates complex description field
        :param value: string value with markdown support
        :return: self
        """
        # return self.escape (value.strip ().replace ('\n', '\\\\'))
        html = self.m2h.parse('' + value + '', True)
        latex = Html2Latex(html)
        result = latex.to_latex()
        result = self.escape(''.join(result))
        return result
        return self

    def secure(self, value):
        """
        Method secures given value
        :param value: value to be secured
        :return: secured value
        """
        return value \
            .replace('_', '-') \
            .replace('>', '') \
            .replace('<', '')

    def escape(self, value):
        """
        Method escapes given value
        :param value: value to be escaped
        :return: escaped value
        """
        value = re.sub(r'\$ElementData', r'\$ElementData', value)
        value = value \
            .replace('_', '\\_') \
            .replace('->', '$\\rightarrow$') \
            .replace('<-', '$\\leftarrow$') \
            .replace('\n\n', '\n')
        return value