From ef0ed63e5079a0fe62f711e072588d0e8dbd3c51 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Wed, 5 Sep 2012 08:38:10 -0400 Subject: [PATCH] Properly handle newlines in template names with named parameters. --- README.rst | 2 +- docs/usage.rst | 2 +- mwparserfromhell/parser/tokenizer.py | 28 ++++++++++++++++++++++++---- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 94ca26a..77f12c7 100644 --- a/README.rst +++ b/README.rst @@ -70,7 +70,7 @@ passing ``recursive=True``:: >>> mwparserfromhell.parse(text).filter_templates(recursive=True) ['{{foo|{{bar}}={{baz|{{spam}}}}}}', '{{bar}}', '{{baz|{{spam}}}}', '{{spam}}'] -Templates can be easily modified to add, remove, alter or params. ``Wikicode`` +Templates can be easily modified to add, remove, or alter params. ``Wikicode`` can also be treated like a list with ``append()``, ``insert()``, ``remove()``, ``replace()``, and more:: diff --git a/docs/usage.rst b/docs/usage.rst index c4472f9..2fd19af 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -48,7 +48,7 @@ by passing *recursive=True*:: >>> mwparserfromhell.parse(text).filter_templates(recursive=True) ['{{foo|{{bar}}={{baz|{{spam}}}}}}', '{{bar}}', '{{baz|{{spam}}}}', '{{spam}}'] -Templates can be easily modified to add, remove alter or params. +Templates can be easily modified to add, remove, or alter params. :py:class:`~.Wikicode` can also be treated like a list with :py:meth:`~.Wikicode.append`, :py:meth:`~.Wikicode.insert`, :py:meth:`~.Wikicode.remove`, :py:meth:`~.Wikicode.replace`, and more:: diff --git a/mwparserfromhell/parser/tokenizer.py b/mwparserfromhell/parser/tokenizer.py index 2086214..9e6ae11 100644 --- a/mwparserfromhell/parser/tokenizer.py +++ b/mwparserfromhell/parser/tokenizer.py @@ -83,9 +83,18 @@ class Tokenizer(object): self._stack.append(tokens.Text(text="".join(self._textbuffer))) self._textbuffer = [] - def _pop(self): - """Pop the current stack/context/textbuffer, returing the stack.""" + def _pop(self, keep_context=False): + """Pop the current stack/context/textbuffer, returing the stack. + + If *keep_context is ``True``, then we will replace the underlying + stack's context with the current stack's. + """ self._push_textbuffer() + if keep_context: + context = self._context + stack = self._stacks.pop()[0] + self._context = context + return stack return self._stacks.pop()[0] def _fail_route(self): @@ -225,14 +234,23 @@ class Tokenizer(object): if self._context & contexts.TEMPLATE_NAME: self._verify_safe(["\n", "{", "}", "[", "]"]) self._context ^= contexts.TEMPLATE_NAME - if self._context & contexts.TEMPLATE_PARAM_VALUE: + elif self._context & contexts.TEMPLATE_PARAM_VALUE: self._context ^= contexts.TEMPLATE_PARAM_VALUE + elif self._context & contexts.TEMPLATE_PARAM_KEY: + self._write_all(self._pop(keep_context=True)) self._context |= contexts.TEMPLATE_PARAM_KEY self._write(tokens.TemplateParamSeparator()) + self._push(self._context) def _handle_template_param_value(self): """Handle a template parameter's value at the head of the string.""" - self._verify_safe(["\n", "{{", "}}"]) + try: + self._verify_safe(["\n", "{{", "}}"]) + except BadRoute: + self._pop() + raise + else: + self._write_all(self._pop(keep_context=True)) self._context ^= contexts.TEMPLATE_PARAM_KEY self._context |= contexts.TEMPLATE_PARAM_VALUE self._write(tokens.TemplateParamEquals()) @@ -241,6 +259,8 @@ class Tokenizer(object): """Handle the end of a template at the head of the string.""" if self._context & contexts.TEMPLATE_NAME: self._verify_safe(["\n", "{", "}", "[", "]"]) + elif self._context & contexts.TEMPLATE_PARAM_KEY: + self._write_all(self._pop(keep_context=True)) self._head += 1 return self._pop()