Repository: facelessuser/pymdown-extensions

Issue:
Arithmatex hang/slow render
Hi,

I'm facing one Latex block which is slowly render by Arithmatex. It takes ~ 10 minutes to render.

Latex block:
```
text='''
$z^{[1]} = \begin{bmatrix}w^{[1]T}_1 \\ w^{[1]T}_2 \\ w^{[1]T}_3 \\ w^{[1]T}_4 \end{bmatrix} \begin{bmatrix}x_1 \\ x_2 \\ x_3 \end{bmatrix} + \begin{bmatrix}b^{[1]}_1 \\ b^{[1]}_2 \\ b^{[1]}_3 \\ b^{[1]}_4 \end{bmatrix}= \begin{bmatrix}w^{[1]T}_1 x + b^{[1]}_1 \\ w^{[1]T}_2 x + b^{[1]}_2\\ w^{[1]T}_3 x + b^{[1]}_3 \\ w^{[1]T}_4 x + b^{[1]}_4 \end{bmatrix} $
'''
html = markdown.markdown(text, extensions=['pymdownx.arithmatex'])
```

When Break pressed, it throws this backtrace:

```
 File "./markdown/core.py", line 388, in markdown
    return md.convert(text)
  File "./markdown/core.py", line 269, in convert
    newRoot = treeprocessor.run(root)
  File "./markdown/treeprocessors.py", line 370, in run
    self.__handleInline(text), child
  File "./markdown/treeprocessors.py", line 131, in __handleInline
    self.inlinePatterns[patternIndex], data, patternIndex, startIndex
  File "./markdown/treeprocessors.py", line 270, in __applyPattern
    for match in pattern.getCompiledRegExp().finditer(data, startIndex):
```



Discussion:
facelessuser: @gir-bot lgtm

Patch:
diff --git a/docs/src/markdown/about/changelog.md b/docs/src/markdown/about/changelog.md
index 0c72a7bd..c78a3fa2 100644
--- a/docs/src/markdown/about/changelog.md
+++ b/docs/src/markdown/about/changelog.md
@@ -1,5 +1,10 @@
 # Changelog
 
+## Next
+
+- **FIX**: Better Arithmatex patterns. Fix issue #888 which caused a hang due to a regular expression typo. Also ensure
+  `#!tex $$..$$` and `#!tex begin{}...end{}` patterns properly don't match if the tail markers are escaped.
+
 ## 7.0
 
 Please see [Release Notes](./release.md#upgrading-to-70) for details on upgrading to 7.0.
diff --git a/pymdownx/arithmatex.py b/pymdownx/arithmatex.py
index 4e379d29..1feb4f76 100644
--- a/pymdownx/arithmatex.py
+++ b/pymdownx/arithmatex.py
@@ -50,12 +50,12 @@ import xml.etree.ElementTree as etree
 from . import util
 import re
 
-RE_SMART_DOLLAR_INLINE = r'(?:(?<!\\)((?:\\{2})+)(?=\$)|(?<!\\)(\$)(?!\s)((?:\\.|[^\$])+?)(?<!\s)(?:\$))'
-RE_DOLLAR_INLINE = r'(?:(?<!\\)((?:\\{2})+)(?=\$)|(?<!\\)(\$)((?:\\.|[^\$])+?)(?:\$))'
+RE_SMART_DOLLAR_INLINE = r'(?:(?<!\\)((?:\\{2})+)(?=\$)|(?<!\\)(\$)(?!\s)((?:\\.|[^\\$])+?)(?<!\s)(?:\$))'
+RE_DOLLAR_INLINE = r'(?:(?<!\\)((?:\\{2})+)(?=\$)|(?<!\\)(\$)((?:\\.|[^\\$])+?)(?:\$))'
 RE_BRACKET_INLINE = r'(?:(?<!\\)((?:\\{2})+?)(?=\\\()|(?<!\\)(\\\()((?:\\[^)]|[^\\])+?)(?:\\\)))'
 
-RE_DOLLAR_BLOCK = r'(?P<dollar>[$]{2})(?P<math>.+?)(?P=dollar)'
-RE_TEX_BLOCK = r'(?P<math2>\\begin\{(?P<env>[a-z]+\*?)\}.+?\\end\{(?P=env)\})'
+RE_DOLLAR_BLOCK = r'(?P<dollar>[$]{2})(?P<math>((?:\\.|[^\\])+?))(?P=dollar)'
+RE_TEX_BLOCK = r'(?P<math2>\\begin\{(?P<env>[a-z]+\*?)\}(?:\\.|[^\\])+?\\end\{(?P=env)\})'
 RE_BRACKET_BLOCK = r'\\\[(?P<math3>(?:\\[^\]]|[^\\])+?)\\\]'
 
 


Test patch:
diff --git a/tests/test_extensions/test_arithmatex.py b/tests/test_extensions/test_arithmatex.py
new file mode 100644
index 00000000..90178b2d
--- /dev/null
+++ b/tests/test_extensions/test_arithmatex.py
@@ -0,0 +1,133 @@
+"""Test cases for Arithmatex."""
+from .. import util
+
+
+class TestArithmatexBlockEscapes(util.MdCase):
+    """Test escaping cases for Arithmatex blocks."""
+
+    extension = [
+        'pymdownx.arithmatex'
+    ]
+    extension_configs = {}
+
+    def test_escaped_dollar_block(self):
+        """Test escaping a dollar."""
+
+        self.check_markdown(
+            r'''
+            $$3+2\$$
+            ''',
+            r'''
+            <p>$<span><span class="MathJax_Preview">3+2\$</span><script type="math/tex">3+2\$</script></span></p>
+            ''',
+            True
+        )
+
+    def test_escaped_dollar_dollar_block(self):
+        """Test escaping both dollars."""
+
+        self.check_markdown(
+            r'''
+            $$3+2\$\$
+            ''',
+            r'''
+            <p>$$3+2$$</p>
+            ''',
+            True
+        )
+
+    def test_double_escaped_dollar_block(self):
+        """Test double escaping a dollar."""
+
+        self.check_markdown(
+            r'''
+            $$3+2\\$$
+            ''',
+            r'''
+            <div>
+            <div class="MathJax_Preview">3+2\\</div>
+            <script type="math/tex; mode=display">3+2\\</script>
+            </div>
+            ''',
+            True
+        )
+
+    def test_escaped_end_block(self):
+        """Test escaping an end."""
+
+        self.check_markdown(
+            r'''
+            \begin{align}3+2\\end{align}
+            ''',
+            r'''
+            <p>\begin{align}3+2\end{align}</p>
+            ''',
+            True
+        )
+
+    def test_double_escaped_end_block(self):
+        """Test double escaping an end."""
+
+        self.check_markdown(
+            r'''
+            \begin{align}3+2\\\end{align}
+            ''',
+            r'''
+            <div>
+            <div class="MathJax_Preview">\begin{align}3+2\\\end{align}</div>
+            <script type="math/tex; mode=display">\begin{align}3+2\\\end{align}</script>
+            </div>
+            ''',
+            True
+        )
+
+    def test_escaped_bracket_block(self):
+        """Test escaping a bracket."""
+
+        self.check_markdown(
+            r'''
+            \[3+2\\]
+            ''',
+            r'''
+            <p>[3+2\]</p>
+            ''',
+            True
+        )
+
+    def test_double_escaped_bracket_block(self):
+        """Test double escaping a bracket."""
+
+        self.check_markdown(
+            r'''
+            \[3+2\\\]
+            ''',
+            r'''
+            <div>
+            <div class="MathJax_Preview">3+2\\</div>
+            <script type="math/tex; mode=display">3+2\\</script>
+            </div>
+            ''',
+            True
+        )
+
+
+class TestArithmatexHang(util.MdCase):
+    """Test hang cases."""
+
+    def test_hang_dollar(self):
+        """
+        We are just making sure this works.
+
+        Previously this pattern would hang. It isn't supposed to match due to the space before the last dollar,
+        but it definitely shouldn't hang the process.
+        """
+
+        self.check_markdown(
+            r'''
+            $z^{[1]} = \begin{bmatrix}w^{[1]T}_1 \\ w^{[1]T}_2 \\ w^{[1]T}_3 \\ w^{[1]T}_4 \end{bmatrix} \begin{bmatrix}x_1 \\ x_2 \\ x_3 \end{bmatrix} + \begin{bmatrix}b^{[1]}_1 \\ b^{[1]}_2 \\ b^{[1]}_3 \\ b^{[1]}_4 \end{bmatrix}= \begin{bmatrix}w^{[1]T}_1 x + b^{[1]}_1 \\ w^{[1]T}_2 x + b^{[1]}_2\\ w^{[1]T}_3 x + b^{[1]}_3 \\ w^{[1]T}_4 x + b^{[1]}_4 \end{bmatrix} $
+            ''',  # noqa: E501
+            r'''
+            <p>$z^{[1]} = \begin{bmatrix}w^{[1]T}_1 \ w^{[1]T}_2 \ w^{[1]T}_3 \ w^{[1]T}_4 \end{bmatrix} \begin{bmatrix}x_1 \ x_2 \ x_3 \end{bmatrix} + \begin{bmatrix}b^{[1]}_1 \ b^{[1]}_2 \ b^{[1]}_3 \ b^{[1]}_4 \end{bmatrix}= \begin{bmatrix}w^{[1]T}_1 x + b^{[1]}_1 \ w^{[1]T}_2 x + b^{[1]}_2\ w^{[1]T}_3 x + b^{[1]}_3 \ w^{[1]T}_4 x + b^{[1]}_4 \end{bmatrix} $</p>
+            ''',  # noqa: E501
+            True
+        )