diff options
author | milde <milde@929543f6-e4f2-0310-98a6-ba3bd3dd1d04> | 2013-02-18 21:22:20 +0000 |
---|---|---|
committer | milde <milde@929543f6-e4f2-0310-98a6-ba3bd3dd1d04> | 2013-02-18 21:22:20 +0000 |
commit | 65bbadbd51bd20569a7429b33b6799873b94dd27 (patch) | |
tree | ad30d65e79ef069f346ecb8d9d25ac9e2d7a80bd | |
parent | 5c9868fadd5997a26d7e8e02057284481f4e4d4e (diff) | |
download | docutils-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.txt | 1 | ||||
-rw-r--r-- | docs/ref/rst/restructuredtext.txt | 39 | ||||
-rw-r--r-- | docutils/parsers/rst/states.py | 55 | ||||
-rwxr-xr-x | test/test_parsers/test_rst/test_inline_markup.py | 85 | ||||
-rwxr-xr-x | test/test_transforms/test_hyperlinks.py | 36 |
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_ |