Skip to content

Commit 0800304

Browse files
committed
Added TeX escaping utility functions and template filters. Removed
html escaping and added TeX escaping for relevant parts of the bibtext template. Fixes issue ietf-tools#2459. - Legacy-Id: 14711
1 parent 93633cd commit 0800304

4 files changed

Lines changed: 192 additions & 7 deletions

File tree

ietf/templates/doc/document_bibtex.bib

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{% spaceless %}
2-
2+
{% autoescape off %}
33
{% load ietf_filters %}
4+
{% load textfilters %}
45
56
{% if doc.get_state_slug == "rfc" %}
67
{% if doc.stream|slugify == "legacy" %}
@@ -24,13 +25,14 @@ @techreport{
2425
publisher = {% templatetag openbrace %}Internet Engineering Task Force{% templatetag closebrace %},
2526
note = {% templatetag openbrace %}Work in Progress{% templatetag closebrace %},
2627
url = {% templatetag openbrace %}https://datatracker.ietf.org/doc/html/{{doc.name}}-{{doc.rev}}{% templatetag closebrace %},{% endif %}
27-
author = {% templatetag openbrace %}{% for author in doc.documentauthor_set.all %}{{ author.person.name}}{% if not forloop.last %} and {% endif %}{% endfor %}{% templatetag closebrace %},
28-
title = {% templatetag openbrace %}{% templatetag openbrace %}{{doc.title}}{% templatetag closebrace %}{% templatetag closebrace %},
28+
author = {% templatetag openbrace %}{% for author in doc.documentauthor_set.all %}{{ author.person.name|texescape}}{% if not forloop.last %} and {% endif %}{% endfor %}{% templatetag closebrace %},
29+
title = {% templatetag openbrace %}{% templatetag openbrace %}{{doc.title|texescape}}{% templatetag closebrace %}{% templatetag closebrace %},
2930
pagetotal = {{ doc.pages }},
3031
year = {{ doc.pub_date.year }},
3132
month = {{ doc.pub_date|date:"b" }},{% if not doc.rfc_number or doc.pub_date.day == 1 and doc.pub_date.month == 4 %}
3233
day = {{ doc.pub_date.day }},{% endif %}
33-
abstract = {% templatetag openbrace %}{{ doc.abstract|clean_whitespace }}{% templatetag closebrace %},
34+
abstract = {% templatetag openbrace %}{{ doc.abstract|clean_whitespace|texescape }}{% templatetag closebrace %},
3435
{% templatetag closebrace %}
3536
37+
{% endautoescape %}
3638
{% endspaceless %}

ietf/utils/templatetags/textfilters.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
from __future__ import unicode_literals
22

3-
from django.template.library import Library
3+
from django import template
44
from django.template.defaultfilters import stringfilter
55

6-
from ietf.utils.text import xslugify as _xslugify
6+
import debug # pyflakes:ignore
77

8-
register = Library()
8+
from ietf.utils.text import xslugify as _xslugify, texescape
9+
10+
register = template.Library()
911

1012
@register.filter(is_safe=True)
1113
@stringfilter
@@ -26,3 +28,40 @@ def format(format, values):
2628
tmp[f.name] = getattr(values, f.name)
2729
values = tmp
2830
return format.format(**values)
31+
32+
# ----------------------------------------------------------------------
33+
34+
# from django.utils.safestring import mark_safe
35+
# class TeXEscapeNode(template.Node):
36+
# """TeX escaping, rather than html escaping.
37+
#
38+
# Mostly, this tag is _not_ the right thing to use in a template that produces TeX
39+
# markup, as it will escape all the markup characters, which is not what you want.
40+
# Use the '|texescape' filter instead on text fragments where escaping is needed
41+
# """
42+
# def __init__(self, nodelist):
43+
# self.nodelist = nodelist
44+
#
45+
# def render(self, context):
46+
# saved_autoescape = context.autoescape
47+
# context.autoescape = False
48+
# text = self.nodelist.render(context)
49+
# text = texescape(text)
50+
# context.autoescape = saved_autoescape
51+
# return mark_safe(text)
52+
#
53+
# @register.tag('texescape')
54+
# def do_texescape(parser, token):
55+
# args = token.contents.split()
56+
# if len(args) != 1:
57+
# raise TemplateSyntaxError("'texescape' tag takes no arguments.")
58+
# nodelist = parser.parse(('endtexescape',))
59+
# parser.delete_first_token()
60+
# return TeXEscapeNode(nodelist)
61+
62+
@register.filter('texescape')
63+
@stringfilter
64+
def texescape_filter(value):
65+
"A TeX escape filter"
66+
return texescape(value)
67+

ietf/utils/texescape.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# -*- coding: utf-8 -*-
2+
# Copied from https://github.com/sphinx-doc/sphinx/blob/master/sphinx/util/texescape.py
3+
# Copyright and license as indicated in the original and below
4+
"""
5+
sphinx.util.texescape
6+
~~~~~~~~~~~~~~~~~~~~~
7+
8+
TeX escaping helper.
9+
10+
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
11+
:license: BSD, see LICENSE for details.
12+
"""
13+
14+
from __future__ import unicode_literals
15+
16+
tex_replacements = [
17+
# map TeX special chars
18+
('$', r'\$'),
19+
('%', r'\%'),
20+
('&', r'\&'),
21+
('#', r'\#'),
22+
('_', r'\_'),
23+
('{', r'\{'),
24+
('}', r'\}'),
25+
('[', r'{[}'),
26+
(']', r'{]}'),
27+
('`', r'{}`'),
28+
('\\', r'\textbackslash{}'),
29+
('~', r'\textasciitilde{}'),
30+
('<', r'\textless{}'),
31+
('>', r'\textgreater{}'),
32+
('^', r'\textasciicircum{}'),
33+
# map special Unicode characters to TeX commands
34+
('¶', r'\P{}'),
35+
('§', r'\S{}'),
36+
('€', r'\texteuro{}'),
37+
('∞', r'\(\infty\)'),
38+
('±', r'\(\pm\)'),
39+
('→', r'\(\rightarrow\)'),
40+
('‣', r'\(\rightarrow\)'),
41+
('✓', r'\(\checkmark\)'),
42+
# used to separate -- in options
43+
('', r'{}'),
44+
# map some special Unicode characters to similar ASCII ones
45+
('⎽', r'\_'),
46+
('–', r'\textendash{}'),
47+
('|', r'\textbar{}'),
48+
('ℯ', r'e'),
49+
('ⅈ', r'i'),
50+
('⁰', r'\(\sp{\text{0}}\)'),
51+
('¹', r'\(\sp{\text{1}}\)'),
52+
('²', r'\(\sp{\text{2}}\)'),
53+
('³', r'\(\sp{\text{3}}\)'),
54+
('⁴', r'\(\sp{\text{4}}\)'),
55+
('⁵', r'\(\sp{\text{5}}\)'),
56+
('⁶', r'\(\sp{\text{6}}\)'),
57+
('⁷', r'\(\sp{\text{7}}\)'),
58+
('⁸', r'\(\sp{\text{8}}\)'),
59+
('⁹', r'\(\sp{\text{9}}\)'),
60+
('₀', r'\(\sb{\text{0}}\)'),
61+
('₁', r'\(\sb{\text{1}}\)'),
62+
('₂', r'\(\sb{\text{2}}\)'),
63+
('₃', r'\(\sb{\text{3}}\)'),
64+
('₄', r'\(\sb{\text{4}}\)'),
65+
('₅', r'\(\sb{\text{5}}\)'),
66+
('₆', r'\(\sb{\text{6}}\)'),
67+
('₇', r'\(\sb{\text{7}}\)'),
68+
('₈', r'\(\sb{\text{8}}\)'),
69+
('₉', r'\(\sb{\text{9}}\)'),
70+
# map Greek alphabet
71+
('α', r'\(\alpha\)'),
72+
('β', r'\(\beta\)'),
73+
('γ', r'\(\gamma\)'),
74+
('δ', r'\(\delta\)'),
75+
('ε', r'\(\epsilon\)'),
76+
('ζ', r'\(\zeta\)'),
77+
('η', r'\(\eta\)'),
78+
('θ', r'\(\theta\)'),
79+
('ι', r'\(\iota\)'),
80+
('κ', r'\(\kappa\)'),
81+
('λ', r'\(\lambda\)'),
82+
('μ', r'\(\mu\)'),
83+
('ν', r'\(\nu\)'),
84+
('ξ', r'\(\xi\)'),
85+
('ο', r'o'),
86+
('π', r'\(\pi\)'),
87+
('ρ', r'\(\rho\)'),
88+
('σ', r'\(\sigma\)'),
89+
('τ', r'\(\tau\)'),
90+
('υ', '\\(\\upsilon\\)'),
91+
('φ', r'\(\phi\)'),
92+
('χ', r'\(\chi\)'),
93+
('ψ', r'\(\psi\)'),
94+
('ω', r'\(\omega\)'),
95+
('Α', r'A'),
96+
('Β', r'B'),
97+
('Γ', r'\(\Gamma\)'),
98+
('Δ', r'\(\Delta\)'),
99+
('Ε', r'E'),
100+
('Ζ', r'Z'),
101+
('Η', r'H'),
102+
('Θ', r'\(\Theta\)'),
103+
('Ι', r'I'),
104+
('Κ', r'K'),
105+
('Λ', r'\(\Lambda\)'),
106+
('Μ', r'M'),
107+
('Ν', r'N'),
108+
('Ξ', r'\(\Xi\)'),
109+
('Ο', r'O'),
110+
('Π', r'\(\Pi\)'),
111+
('Ρ', r'P'),
112+
('Σ', r'\(\Sigma\)'),
113+
('Τ', r'T'),
114+
('Υ', '\\(\\Upsilon\\)'),
115+
('Φ', r'\(\Phi\)'),
116+
('Χ', r'X'),
117+
('Ψ', r'\(\Psi\)'),
118+
('Ω', r'\(\Omega\)'),
119+
('Ω', r'\(\Omega\)'),
120+
]
121+
122+
tex_escape_map = {}
123+
tex_replace_map = {}
124+
tex_hl_escape_map_new = {}
125+
126+
127+
def init():
128+
# type: () -> None
129+
for a, b in tex_replacements:
130+
tex_escape_map[ord(a)] = b
131+
tex_replace_map[ord(a)] = '_'
132+
133+
for a, b in tex_replacements:
134+
if a in '[]{}\\':
135+
continue
136+
tex_hl_escape_map_new[ord(a)] = b

ietf/utils/text.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
import debug # pyflakes:ignore
1313

14+
from texescape import init as texescape_init, tex_escape_map
15+
1416
@keep_lazy(six.text_type)
1517
def xslugify(value):
1618
"""
@@ -174,3 +176,9 @@ def dict_to_text(d):
174176
for k, v in d.items():
175177
t += "%s: %s\n" % (k, v)
176178
return t
179+
180+
def texescape(s):
181+
if not tex_escape_map:
182+
texescape_init()
183+
t = s.translate(tex_escape_map)
184+
return t

0 commit comments

Comments
 (0)