#
"""template - Jinja templating support."""
# Copyright © 2014-2020 James Rowe <jnrowe@gmail.com>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This file is part of jnrbase.
#
# jnrbase is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# jnrbase is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# jnrbase. If not, see <http://www.gnu.org/licenses/>.
import re
import sys
from datetime import datetime
from os import path
from typing import Callable, Dict, Union
import html2text as html2
import jinja2
from click import style
from pygments import highlight as pyg_highlight
from pygments.formatters import get_formatter_by_name
from pygments.lexers import get_lexer_by_name
from . import xdg_basedir
from .human_time import human_timestamp
#: Collection of custom filters to add to Jinja environment
FILTERS: Dict[str, Callable] = {}
[docs]def jinja_filter(__func: Callable[..., str]) -> Callable[..., str]:
"""Simple decorator to add a new filter to Jinja environment.
See also: :obj:`FILTERS`
Args:
__func: Function to add to Jinja environment
Returns:
Unmodified function
"""
FILTERS[__func.__name__] = __func
return __func
[docs]@jinja_filter
def colourise(__text: str, *args, **kwargs) -> str:
"""Colourise text using click’s style function.
Returns text untouched if colour output is not enabled, or ``stdout`` is
not a tty.
See :func:`click.style` for parameters
Args:
__text: Text to colourise
Returns:
Colourised text, when possible
"""
if sys.stdout.isatty():
__text = style(__text, *args, **kwargs)
return __text
[docs]@jinja_filter
def highlight(__text: str, *, lexer: str = 'diff',
formatter: str = 'terminal') -> str:
"""Highlight text highlighted using ``pygments``.
Returns text untouched if colour output is not enabled.
See also: :pypi:`Pygments`
Args:
__text: Text to highlight
lexer: Jinja lexer to use
formatter: Jinja formatter to use
Returns:
Syntax highlighted output, when possible
"""
if sys.stdout.isatty():
lexer = get_lexer_by_name(lexer)
formatter = get_formatter_by_name(formatter)
__text = pyg_highlight(__text, lexer, formatter)
return __text
[docs]@jinja_filter
def html2text(__html: str,
*,
width: int = 80,
ascii_replacements: bool = False) -> str:
"""HTML to plain text renderer.
See also: :pypi:`html2text`
Args:
__html: Text to process
width: Paragraph width
ascii_replacements: Use pseudo-ASCII replacements for Unicode
Returns:
Rendered text
"""
html2.BODY_WIDTH = width
html2.UNICODE_SNOB = ascii_replacements
return html2.html2text(__html).strip()
[docs]@jinja_filter
def regexp(__string: str,
__pattern: str,
__repl: Union[Callable, str],
*,
count: int = 0,
flags: int = 0) -> str:
"""Jinja filter for regexp replacements.
See :func:`re.sub` for documentation.
Returns:
Text with substitutions applied
"""
return re.sub(__pattern, __repl, __string, count, flags)
[docs]@jinja_filter
def relative_time(__timestamp: datetime) -> str:
"""Format a relative time.
See :func:`~jnrbase.human_time.human_timestamp`
Args:
__timestamp: Event to generate relative timestamp against
Returns:
Human readable date and time offset
"""
return human_timestamp(__timestamp)
[docs]def setup(__pkg: str) -> jinja2.Environment:
"""Configure a new Jinja environment with our filters.
Args:
__pkg: Package name to use as base for templates searches
Returns:
Configured Jinja environment
"""
dirs = [
path.join(d, 'templates') for d in xdg_basedir.get_data_dirs(__pkg)
]
env = jinja2.Environment(
autoescape=jinja2.select_autoescape(['html', 'xml']),
loader=jinja2.ChoiceLoader([jinja2.FileSystemLoader(s) for s in dirs]))
env.loader.loaders.append(jinja2.PackageLoader(__pkg, 'templates'))
env.filters.update(FILTERS)
return env