163 lines
4.8 KiB
Python
163 lines
4.8 KiB
Python
"""
|
|
Emoji extras for Material.
|
|
|
|
Override the indexes with an extended version that includes short names for Material icons, FontAwesome, etc.
|
|
"""
|
|
import os
|
|
import glob
|
|
import copy
|
|
import codecs
|
|
import functools
|
|
import inspect
|
|
import material
|
|
import pymdownx
|
|
from pymdownx.emoji import TWEMOJI_SVG_CDN, add_attriubtes
|
|
import xml.etree.ElementTree as etree # noqa: N813
|
|
import warnings
|
|
from functools import wraps
|
|
import logging
|
|
|
|
log = logging.getLogger('mkdocs')
|
|
|
|
DEPRECATED = """\
|
|
Material emoji logic has been officially moved into mkdocs-material
|
|
version 9.4. Please use Material's '{}'
|
|
instead of '{}' in your 'mkdocs.yml' file.
|
|
|
|
```
|
|
markdown_extensions:
|
|
- pymdownx.emoji:
|
|
emoji_index: !!python/name:material.extensions.emoji.twemoji
|
|
emoji_generator: !!python/name:material.extensions.emoji.to_svg
|
|
```
|
|
|
|
'mkdocs_material_extensions' is deprecated and will no longer be
|
|
supported moving forward. This is the last release.
|
|
"""
|
|
|
|
|
|
OPTION_SUPPORT = pymdownx.__version_info__ >= (7, 1, 0)
|
|
RESOURCES = os.path.dirname(inspect.getfile(material))
|
|
if os.path.exists(os.path.join(RESOURCES, 'templates', '.icons')): # pragma: no cover
|
|
RES_PATH = os.path.join(RESOURCES, 'templates', '.icons')
|
|
else: # pragma: no cover
|
|
RES_PATH = os.path.join(RESOURCES, '.icons')
|
|
|
|
|
|
@functools.lru_cache(maxsize=None)
|
|
def log_msg(message):
|
|
"""Log message."""
|
|
|
|
log.warning(message)
|
|
|
|
|
|
def deprecated(message, stacklevel=2, name=None): # pragma: no cover
|
|
"""
|
|
Raise a `DeprecationWarning` when wrapped function/method is called.
|
|
|
|
Usage:
|
|
|
|
@deprecated("This method will be removed in version X; use Y instead.")
|
|
def some_method()"
|
|
pass
|
|
"""
|
|
|
|
def _wrapper(func):
|
|
@wraps(func)
|
|
def _deprecated_func(*args, **kwargs):
|
|
warnings.warn(
|
|
f"'{func.__name__ if name is None else name}' is deprecated.\n{message}",
|
|
category=DeprecationWarning,
|
|
stacklevel=stacklevel
|
|
)
|
|
|
|
log_msg(message)
|
|
return func(*args, **kwargs)
|
|
return _deprecated_func
|
|
return _wrapper
|
|
|
|
|
|
@deprecated(
|
|
DEPRECATED.format('material.extensions.emoji.twemoji', 'materialx.emoji.twemoji'),
|
|
name='materialx.emoji.twemoji'
|
|
)
|
|
def _patch_index(options):
|
|
"""Patch the given index."""
|
|
|
|
icon_locations = options.get('custom_icons', [])[:]
|
|
icon_locations.append(RES_PATH)
|
|
return _patch_index_for_locations(tuple(icon_locations))
|
|
|
|
|
|
@functools.lru_cache(maxsize=None)
|
|
def _patch_index_for_locations(icon_locations):
|
|
import pymdownx.twemoji_db as twemoji_db
|
|
|
|
# Copy the Twemoji index
|
|
index = {
|
|
"name": 'twemoji',
|
|
"emoji": copy.deepcopy(twemoji_db.emoji) if not OPTION_SUPPORT else twemoji_db.emoji,
|
|
"aliases": copy.deepcopy(twemoji_db.aliases) if not OPTION_SUPPORT else twemoji_db.aliases
|
|
}
|
|
|
|
# Find our icons
|
|
for icon_path in icon_locations:
|
|
norm_base = icon_path.replace('\\', '/') + '/'
|
|
for result in glob.glob(glob.escape(icon_path.replace('\\', '/')) + '/**/*.svg', recursive=True):
|
|
name = ':{}:'.format(result.replace('\\', '/').replace(norm_base, '', 1).replace('/', '-').lstrip('.')[:-4])
|
|
if name not in index['emoji'] and name not in index['aliases']:
|
|
# Easiest to just store the path and pull it out from the index
|
|
index["emoji"][name] = {'name': name, 'path': result}
|
|
return index
|
|
|
|
|
|
if OPTION_SUPPORT: # pragma: no cover
|
|
def twemoji(options, md):
|
|
"""Provide a copied Twemoji index with additional codes for Material included icons."""
|
|
|
|
return _patch_index(options)
|
|
|
|
else: # pragma: no cover
|
|
def twemoji():
|
|
"""Provide a copied Twemoji index with additional codes for Material included icons."""
|
|
|
|
return _patch_index({})
|
|
|
|
|
|
@deprecated(
|
|
DEPRECATED.format('material.extensions.emoji.to_svg', 'materialx.emoji.to_svg'),
|
|
1,
|
|
name='materialx.emoji.to_svg'
|
|
)
|
|
def to_svg(index, shortname, alias, uc, alt, title, category, options, md):
|
|
"""Return SVG element."""
|
|
|
|
is_unicode = uc is not None
|
|
|
|
if is_unicode:
|
|
# Handle Twemoji emoji.
|
|
svg_path = TWEMOJI_SVG_CDN
|
|
|
|
attributes = {
|
|
"class": options.get('classes', index),
|
|
"alt": alt,
|
|
"src": "%s%s.svg" % (
|
|
options.get('image_path', svg_path),
|
|
uc
|
|
)
|
|
}
|
|
|
|
if title:
|
|
attributes['title'] = title
|
|
|
|
add_attriubtes(options, attributes)
|
|
|
|
return etree.Element("img", attributes)
|
|
else:
|
|
# Handle Material SVG assets.
|
|
el = etree.Element('span', {"class": options.get('classes', index)})
|
|
svg_path = md.inlinePatterns['emoji'].emoji_index['emoji'][shortname]['path']
|
|
with codecs.open(svg_path, 'r', encoding='utf-8') as f:
|
|
el.text = md.htmlStash.store(f.read())
|
|
return el
|