##// END OF EJS Templates
Adding citation support.
Brian E. Granger -
Show More
@@ -0,0 +1,70 b''
1 """Citation handling for LaTeX output."""
2
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
5 #
6 # Distributed under the terms of the Modified BSD License.
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
10
11 #-----------------------------------------------------------------------------
12 # Code
13 #-----------------------------------------------------------------------------
14
15
16 __all__ = ['parse_citation']
17
18
19 def parse_citation(s):
20 """Parse citations in Markdown cells.
21
22 This looks for HTML tags having a data attribute names `data-cite`
23 and replaces it by the call to LaTeX cite command. The tranformation
24 looks like this:
25
26 `<cite data-cite="granger">(Granger, 2013)</cite>`
27
28 Becomes
29
30 `\\cite{granger}`
31
32 Any HTML tag can be used, which allows the citations to be formatted
33 in HTML in any manner.
34 """
35 try:
36 from lxml import html
37 except ImportError:
38 return s
39
40 tree = html.fragment_fromstring(s, create_parent='div')
41 _process_node_cite(tree)
42 s = html.tostring(tree)
43 s = s.lstrip('<div>')
44 s = s.rstrip('</div>')
45 return s
46
47
48 def _process_node_cite(node):
49 """Do the citation replacement as we walk the lxml tree."""
50
51 def _get(o, name):
52 value = getattr(o, name)
53 return '' if value is None else value
54
55 if 'data-cite' in node.attrib:
56 cite = '\cite{%(ref)s}' % {'ref': node.attrib['data-cite']}
57 prev = node.getprevious()
58 if prev is not None:
59 prev.tail = _get(prev, 'tail') + cite + _get(node, 'tail')
60 else:
61 parent = node.getparent()
62 if parent is not None:
63 parent.text = _get(parent, 'text') + cite + _get(node, 'tail')
64 try:
65 node.getparent().remove(node)
66 except AttributeError:
67 pass
68 else:
69 for child in node:
70 _process_node_cite(child)
@@ -0,0 +1,54 b''
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2013, the IPython Development Team.
3 #
4 # Distributed under the terms of the Modified BSD License.
5 #
6 # The full license is in the file COPYING.txt, distributed with this software.
7 #-----------------------------------------------------------------------------
8
9 #-----------------------------------------------------------------------------
10 # Imports
11 #-----------------------------------------------------------------------------
12
13 from ..citation import parse_citation
14
15 #-----------------------------------------------------------------------------
16 # Tests
17 #-----------------------------------------------------------------------------
18
19 test_md = """
20 # My Heading
21
22 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ac magna non augue
23 porttitor scelerisque ac id diam <cite data-cite="granger">Granger</cite>. Mauris elit
24 velit, lobortis sed interdum at, vestibulum vitae libero <strong data-cite="fperez">Perez</strong>.
25 Lorem ipsum dolor sit amet, consectetur adipiscing elit
26 <em data-cite="takluyver">Thomas</em>. Quisque iaculis ligula ut ipsum mattis viverra.
27
28 * One <cite data-cite="jdfreder">Jonathan</cite>.
29 * Two <cite data-cite="carreau">Matthias</cite>.
30 * Three <cite data-cite="ivanov">Paul</cite>.
31 """
32
33 test_md_parsed = """
34 # My Heading
35
36 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ac magna non augue
37 porttitor scelerisque ac id diam \cite{granger}. Mauris elit
38 velit, lobortis sed interdum at, vestibulum vitae libero \cite{fperez}.
39 Lorem ipsum dolor sit amet, consectetur adipiscing elit
40 \cite{takluyver}. Quisque iaculis ligula ut ipsum mattis viverra.
41
42 * One \cite{jdfreder}.
43 * Two \cite{carreau}.
44 * Three \cite{ivanov}.
45 """
46
47 def test_parse_citation():
48 """Are citations parsed properly?"""
49 try:
50 import lxml
51 except ImportError:
52 assert test_md == parse_citation(test_md)
53 else:
54 assert test_md_parsed == parse_citation(test_md)
@@ -68,6 +68,7 b' default_filters = {'
68 'strip_math_space': filters.strip_math_space,
68 'strip_math_space': filters.strip_math_space,
69 'wrap_text': filters.wrap_text,
69 'wrap_text': filters.wrap_text,
70 'escape_latex': filters.escape_latex,
70 'escape_latex': filters.escape_latex,
71 'parse_citation': filters.parse_citation
71 }
72 }
72
73
73 #-----------------------------------------------------------------------------
74 #-----------------------------------------------------------------------------
@@ -3,4 +3,5 b' from .datatypefilter import *'
3 from .highlight import *
3 from .highlight import *
4 from .latex import *
4 from .latex import *
5 from .markdown import *
5 from .markdown import *
6 from .strings import * No newline at end of file
6 from .strings import *
7 from .citation import * No newline at end of file
@@ -103,11 +103,11 b' it introduces a new line'
103 ((* endblock stream *))
103 ((* endblock stream *))
104
104
105 ((* block markdowncell scoped *))
105 ((* block markdowncell scoped *))
106 ((( cell.source | markdown2latex )))
106 ((( cell.source | parse_citation | markdown2latex )))
107 ((* endblock markdowncell *))
107 ((* endblock markdowncell *))
108
108
109 ((* block headingcell scoped -*))
109 ((* block headingcell scoped -*))
110 ((( ('#' * cell.level + cell.source) | replace('\n', ' ') | markdown2latex )))
110 ((( ('#' * cell.level + cell.source) | replace('\n', ' ') | parse_citation | markdown2latex )))
111 ((* endblock headingcell *))
111 ((* endblock headingcell *))
112
112
113 ((* block rawcell scoped *))
113 ((* block rawcell scoped *))
@@ -127,6 +127,10 b' unknown type ((( cell.type )))'
127 ((( super() )))
127 ((( super() )))
128
128
129 ((* block bodyEnd *))
129 ((* block bodyEnd *))
130
131 ((* block bibliography *))
132 ((* endblock bibliography *))
133
130 \end{document}
134 \end{document}
131 ((* endblock bodyEnd *))
135 ((* endblock bodyEnd *))
132 ((* endblock body *))
136 ((* endblock body *))
@@ -192,6 +192,9 b' Note: For best display, use latex syntax highlighting. =))'
192 \renewcommand{\indexname}{Index}
192 \renewcommand{\indexname}{Index}
193 \printindex
193 \printindex
194
194
195 ((* block bibliography *))
196 ((* endblock bibliography *))
197
195 % End of document
198 % End of document
196 \end{document}
199 \end{document}
197 ((* endblock bodyEnd *))
200 ((* endblock bodyEnd *))
@@ -229,7 +232,7 b' Note: For best display, use latex syntax highlighting. =))'
229 in IPYNB file titles) do not make their way into latex. Sometimes this
232 in IPYNB file titles) do not make their way into latex. Sometimes this
230 causes latex to barf. =))
233 causes latex to barf. =))
231 ((*- endif -*))
234 ((*- endif -*))
232 {((( cell.source | markdown2latex )))}
235 {((( cell.source | parse_citation | markdown2latex )))}
233 ((*- endblock headingcell *))
236 ((*- endblock headingcell *))
234
237
235 %==============================================================================
238 %==============================================================================
@@ -239,7 +242,7 b' Note: For best display, use latex syntax highlighting. =))'
239 % called since we know we want latex output.
242 % called since we know we want latex output.
240 %==============================================================================
243 %==============================================================================
241 ((*- block markdowncell scoped-*))
244 ((*- block markdowncell scoped-*))
242 ((( cell.source | markdown2latex )))
245 ((( cell.source | parse_citation | markdown2latex )))
243 ((*- endblock markdowncell -*))
246 ((*- endblock markdowncell -*))
244
247
245 %==============================================================================
248 %==============================================================================
General Comments 0
You need to be logged in to leave comments. Login now