summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormilde <milde@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2013-02-18 21:22:20 +0000
committermilde <milde@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2013-02-18 21:22:20 +0000
commit65bbadbd51bd20569a7429b33b6799873b94dd27 (patch)
treead30d65e79ef069f346ecb8d9d25ac9e2d7a80bd
parent5c9868fadd5997a26d7e8e02057284481f4e4d4e (diff)
downloaddocutils-65bbadbd51bd20569a7429b33b6799873b94dd27.tar.gz
Support embedded aliases within hyperlink references.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@7610 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
-rw-r--r--HISTORY.txt1
-rw-r--r--docs/ref/rst/restructuredtext.txt39
-rw-r--r--docutils/parsers/rst/states.py55
-rwxr-xr-xtest/test_parsers/test_rst/test_inline_markup.py85
-rwxr-xr-xtest/test_transforms/test_hyperlinks.py36
5 files changed, 190 insertions, 26 deletions
diff --git a/HISTORY.txt b/HISTORY.txt
index 082e2738e..fffdae50a 100644
--- a/HISTORY.txt
+++ b/HISTORY.txt
@@ -19,6 +19,7 @@ Changes Since 0.10
* General
- Apply [ 2714873 ] Fix for the overwritting of document attributes.
+ - Support embedded aliases within hyperlink references.
* docutils/nodes.py
diff --git a/docs/ref/rst/restructuredtext.txt b/docs/ref/rst/restructuredtext.txt
index 57ff4e47a..fb07780b2 100644
--- a/docs/ref/rst/restructuredtext.txt
+++ b/docs/ref/rst/restructuredtext.txt
@@ -1862,7 +1862,8 @@ indirect.
.. _link: underscore\_
It is possible (although not generally recommended) to include URIs
- directly within hyperlink references. See `Embedded URIs`_ below.
+ directly within hyperlink references. See `Embedded URIs and Aliases`_
+ below.
3. _`Indirect hyperlink targets` have a hyperlink reference in their
link blocks. In the following example, target "one" indirectly
@@ -1891,6 +1892,9 @@ indirect.
.. _split: `A
Hyperlink`_
+ It is possible to include an alias directly within hyperlink
+ references. See `Embedded URIs and Aliases`_ below.
+
If the reference name contains any colons, either:
- the phrase must be enclosed in backquotes::
@@ -2649,24 +2653,30 @@ match references to targets, but otherwise behave similarly to named
hyperlinks.
-Embedded URIs
-`````````````
+Embedded URIs and Aliases
+`````````````````````````
-A hyperlink reference may directly embed a target URI inline, within
-angle brackets ("<...>") as follows::
+A hyperlink reference may directly embed a target URI or a hyperlink
+reference within angle brackets ("<...>") as follows::
See the `Python home page <http://www.python.org>`_ for info.
+ This `link <Python home page_>`_ is an alias to the link above.
+
This is exactly equivalent to::
See the `Python home page`_ for info.
+ This link_ is an alias to the link above.
+
.. _Python home page: http://www.python.org
+ .. _link: `Python home page`_
The bracketed URI must be preceded by whitespace and be the last text
-before the end string. With a single trailing underscore, the
-reference is named and the same target URI may be referred to again.
+before the end string.
+With a single trailing underscore, the reference is named and the same
+target URI may be referred to again.
With two trailing underscores, the reference and target are both
anonymous, and the target cannot be referred to again. These are
"one-off" hyperlinks. For example::
@@ -2682,9 +2692,18 @@ Equivalent to::
__ http://www.rfc-editor.org/rfc/rfc2396.txt
__ http://www.rfc-editor.org/rfc/rfc2732.txt
-If reference text happens to end with angle-bracketed text that is
-*not* a URI, the open-angle-bracket needs to be backslash-escaped.
-For example, here is a reference to a title describing a tag::
+If a target URI happens to end with an underscore, this needs to be
+backslash-escaped to avoid being parsed as hyperlink reference. For
+example ::
+
+ Use the `source <parrots.txt\_>`__.
+
+creates an anonymous reference to the file ``parrots.txt_``.
+
+If the reference text happens to end with angle-bracketed text that is
+*not* a URI or hyperlink reference, the open-angle-bracket needs to be
+backslash-escaped. For example, here is a reference to a title
+describing a tag::
See `HTML Element: \<a>`_ below.
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index 0905ab7af..8441d09ec 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -608,13 +608,14 @@ class Inliner:
)
%(end_string_suffix)s
""" % locals(), re.VERBOSE | re.UNICODE),
- embedded_uri=re.compile(
+ embedded_link=re.compile(
r"""
(
(?:[ \n]+|^) # spaces or beginning of line/string
< # open bracket
%(non_whitespace_after)s
- ([^<>\x00]+) # anything but angle brackets & nulls
+ ([^<>\x00]+(\x00_)?) # anything but angle brackets & nulls
+ # except escaped trailing low line
%(non_whitespace_before)s
> # close bracket w/o whitespace before
)
@@ -787,41 +788,63 @@ class Inliner:
return string[:matchstart], [prb], string[matchend:], [msg]
def phrase_ref(self, before, after, rawsource, escaped, text):
- match = self.patterns.embedded_uri.search(escaped)
- if match:
+ match = self.patterns.embedded_link.search(escaped)
+ if match: # embedded <URI> or <alias_>
text = unescape(escaped[:match.start(0)])
- uri_text = match.group(2)
- uri = ''.join(uri_text.split())
- uri = self.adjust_uri(uri)
- if uri:
- target = nodes.target(match.group(1), refuri=uri)
- target.referenced = 1
+ aliastext = unescape(match.group(2), restore_backslashes=True)
+ if aliastext.endswith('_') and not aliastext.endswith(r'\_'):
+ aliastype = 'name'
+ alias = normalize_name(aliastext[:-1])
+ target = nodes.target(match.group(1), refname=alias)
+ target.indirect_reference_name = aliastext[:-1]
else:
- raise ApplicationError('problem with URI: %r' % uri_text)
+ aliastype = 'uri'
+ alias = ''.join(aliastext.split())
+ alias = self.adjust_uri(alias)
+ if alias.endswith(r'\_'):
+ alias = alias[:-2] + '_'
+ target = nodes.target(match.group(1), refuri=alias)
+ target.referenced = 1
+ if not aliastext:
+ raise ApplicationError('problem with embedded link: %r'
+ % aliastext)
if not text:
- text = uri
+ text = alias
else:
target = None
+
refname = normalize_name(text)
reference = nodes.reference(rawsource, text,
name=whitespace_normalize_name(text))
node_list = [reference]
+
if rawsource[-2:] == '__':
- if target:
- reference['refuri'] = uri
+ if target and (aliastype == 'name'):
+ reference['refname'] = alias
+ self.document.note_refname(reference)
+ # self.document.note_indirect_target(target) # required?
+ elif target and (aliastype == 'uri'):
+ reference['refuri'] = alias
else:
reference['anonymous'] = 1
else:
if target:
- reference['refuri'] = uri
target['names'].append(refname)
- self.document.note_explicit_target(target, self.parent)
+ if aliastype == 'name':
+ reference['refname'] = alias
+ self.document.note_indirect_target(target)
+ self.document.note_refname(reference)
+ else:
+ reference['refuri'] = alias
+ self.document.note_explicit_target(target, self.parent)
+ # target.note_referenced_by(name=refname)
node_list.append(target)
else:
reference['refname'] = refname
self.document.note_refname(reference)
return before, node_list, after, []
+
def adjust_uri(self, uri):
match = self.patterns.email.match(uri)
if match:
diff --git a/test/test_parsers/test_rst/test_inline_markup.py b/test/test_parsers/test_rst/test_inline_markup.py
index b758800cf..134fa7444 100755
--- a/test/test_parsers/test_rst/test_inline_markup.py
+++ b/test/test_parsers/test_rst/test_inline_markup.py
@@ -1037,6 +1037,91 @@ Relative URIs' reference text can be omitted:
<reference name="anonymous" refuri="anonymous">
anonymous
"""],
+["""\
+Escape trailing low-line char in URIs:
+
+`<reference\_>`_
+
+`<anonymous\_>`__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Escape trailing low-line char in URIs:
+ <paragraph>
+ <reference name="reference_" refuri="reference_">
+ reference_
+ <target ids="reference" names="reference_" refuri="reference_">
+ <paragraph>
+ <reference name="anonymous_" refuri="anonymous_">
+ anonymous_
+"""],
+]
+
+totest['embedded_aliases'] = [
+["""\
+`phrase reference <alias_>`_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="phrase reference" refname="alias">
+ phrase reference
+ <target names="phrase\ reference" refname="alias">
+"""],
+["""\
+`anonymous reference <alias_>`__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="anonymous reference" refname="alias">
+ anonymous reference
+"""],
+["""\
+`embedded alias on next line
+<alias_>`__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="embedded alias on next line" refname="alias">
+ embedded alias on next line
+"""],
+["""\
+`embedded alias across lines <alias
+phrase_>`__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="embedded alias across lines" refname="alias phrase">
+ embedded alias across lines
+"""],
+["""\
+`embedded alias with whitespace <alias
+long phrase_>`__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="embedded alias with whitespace" refname="alias long phrase">
+ embedded alias with whitespace
+"""],
+[r"""
+`embedded alias with too much whitespace < alias_ >`__
+
+`embedded alias with no preceding whitespace<alias_>`__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference anonymous="1" name="embedded alias with too much whitespace < alias_ >">
+ embedded alias with too much whitespace < alias_ >
+ <paragraph>
+ <reference anonymous="1" name="embedded alias with no preceding whitespace<alias_>">
+ embedded alias with no preceding whitespace<alias_>
+"""],
]
totest['inline_targets'] = [
diff --git a/test/test_transforms/test_hyperlinks.py b/test/test_transforms/test_hyperlinks.py
index dc0d972c3..caaef1014 100755
--- a/test/test_transforms/test_hyperlinks.py
+++ b/test/test_transforms/test_hyperlinks.py
@@ -339,6 +339,42 @@ An `anonymous embedded uri <http://direct>`__.
.
"""],
["""\
+An `embedded alias <alias_>`_.
+
+Another reference to the same `embedded alias`_.
+
+.. _alias: ham.py
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ An \n\
+ <reference name="embedded alias" refuri="ham.py">
+ embedded alias
+ <target names="embedded\ alias" refuri="ham.py">
+ .
+ <paragraph>
+ Another reference to the same \n\
+ <reference name="embedded alias" refuri="ham.py">
+ embedded alias
+ .
+ <target ids="alias" names="alias" refuri="ham.py">
+"""],
+["""\
+An `anonymous embedded alias <redirect_>`__.
+
+.. _redirect: spam.py
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ An \n\
+ <reference name="anonymous embedded alias" refuri="spam.py">
+ anonymous embedded alias
+ .
+ <target ids="redirect" names="redirect" refuri="spam.py">
+"""],
+["""\
.. _target:
.. [1] Footnote; target_