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.
ORPA-pyOpenRPA/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/prompt_toolkit/formatted_text/html.py

120 lines
3.7 KiB

from __future__ import unicode_literals
import six
import xml.dom.minidom as minidom
from .base import FormattedText
__all__ = [
'HTML'
]
class HTML(object):
"""
HTML formatted text.
Take something HTML-like, for use as a formatted string.
::
# Turn something into red.
HTML('<style fg="ansired" bg="#00ff44">...</style>')
# Italic, bold and underline.
HTML('<i>...</i>')
HTML('<b>...</b>')
HTML('<u>...</u>')
All HTML elements become available as a "class" in the style sheet.
E.g. ``<username>...</username>`` can be styled, by setting a style for
``username``.
"""
def __init__(self, value):
assert isinstance(value, six.text_type)
self.value = value
document = minidom.parseString('<html-root>%s</html-root>' % (value, ))
result = []
name_stack = []
fg_stack = []
bg_stack = []
def get_current_style():
" Build style string for current node. "
parts = []
if name_stack:
parts.append('class:' + ','.join(name_stack))
if fg_stack:
parts.append('fg:' + fg_stack[-1])
if bg_stack:
parts.append('bg:' + bg_stack[-1])
return ' '.join(parts)
def process_node(node):
" Process node recursively. "
for child in node.childNodes:
if child.nodeType == child.TEXT_NODE:
result.append((get_current_style(), child.data))
else:
add_to_name_stack = child.nodeName not in ('#document', 'html-root', 'style')
fg = bg = ''
for k, v in child.attributes.items():
if k == 'fg': fg = v
if k == 'bg': bg = v
if k == 'color': fg = v # Alias for 'fg'.
# Check for spaces in attributes. This would result in
# invalid style strings otherwise.
if ' ' in fg: raise ValueError('"fg" attribute contains a space.')
if ' ' in bg: raise ValueError('"bg" attribute contains a space.')
if add_to_name_stack: name_stack.append(child.nodeName)
if fg: fg_stack.append(fg)
if bg: bg_stack.append(bg)
process_node(child)
if add_to_name_stack: name_stack.pop()
if fg: fg_stack.pop()
if bg: bg_stack.pop()
process_node(document)
self.formatted_text = FormattedText(result)
def __repr__(self):
return 'HTML(%r)' % (self.value, )
def __pt_formatted_text__(self):
return self.formatted_text
def format(self, *args, **kwargs):
"""
Like `str.format`, but make sure that the arguments are properly
escaped.
"""
# Escape all the arguments.
args = [html_escape(a) for a in args]
kwargs = dict((k, html_escape(v)) for k, v in kwargs.items())
return HTML(self.value.format(*args, **kwargs))
def __mod__(self, value):
"""
HTML('<b>%s</b>') % value
"""
if not isinstance(value, tuple):
value = (value, )
value = tuple(html_escape(i) for i in value)
return HTML(self.value % value)
def html_escape(text):
# The string interpolation functions also take integers and other types.
# Convert to string first.
if not isinstance(text, six.text_type):
text = '{}'.format(text)
return text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;')