Repository: django-wiki/django-wiki

Issue:
Bug: Edit section fails when fenced code block contains comments
### Discussed in https://github.com/django-wiki/django-wiki/discussions/1245

<div type='discussions-op-text'>

<sup>Originally posted by **chrisv2** January  8, 2023</sup>
The following markup will break section editing (due to the `#` in the fenced code block):

````markdown
# Section 1
Section 1 Lorem ipsum dolor sit amet

```python
# hello world
print("hello world")
```

# Section 2
Section 2 Lorem ipsum dolor sit amet
````

# Expected result
When clicking the "edit" link next to "Section 2", the editor should show the following markup:

```markdown
# Section 2
Section 2 Lorem ipsum dolor sit amet
```

# Actual result

The editor shows parts of the fenced code block:

````markdown
# hello world
print("hello world")
```

# Section 2
Section 2 Lorem ipsum dolor sit amet
````

# Notes

Actually it is surprisingly hard to create a proper fix for that, as [it is not possible to get source line numbers from the markdown parser](https://github.com/Python-Markdown/markdown/issues/1235). Currently, the editsection plugin parses the source itself by using regexes, but that doesn't account for fenced code blocks, and it's probably quite difficult to do this with regex alone. IMHO we could do one of the following:

1. loop over markdown source line by line, detecting headers and start/end of fenced code blocks (and possibly other blocks like HTML)
2. create a block level extension and annotate each `h[1-6]` with the source line, then find them in the markup

I'm interested in hacking at this, but I'm not sure which is the best approach. Any thoughts?</div>


Discussion:
Thanks for opening this @chrisv2 - this definitely looks like a bug.

Resolving patch:
diff --git a/src/wiki/plugins/editsection/wiki_plugin.py b/src/wiki/plugins/editsection/wiki_plugin.py
--- a/src/wiki/plugins/editsection/wiki_plugin.py
+++ b/src/wiki/plugins/editsection/wiki_plugin.py
@@ -13,7 +13,7 @@ class EditSectionPlugin(BasePlugin):
     urlpatterns = {
         "article": [
             url(
-                r"^header/(?P<header>[\w-]+)/$",
+                r"^header/(?P<header>[\S]+)/$",
                 views.EditSection.as_view(),
                 name="editsection",
             ),


Test patch:
diff --git a/tests/plugins/editsection/test_editsection.py b/tests/plugins/editsection/test_editsection.py
--- a/tests/plugins/editsection/test_editsection.py
+++ b/tests/plugins/editsection/test_editsection.py
@@ -155,6 +155,20 @@ def test_nonunique_headers(self):
         expected = "## Date\r\n2023-01-02"
         self.assertEqual(actual, expected)
 
+    def test_underscore_and_dot(self):
+        """test whether we can handle non-slug characters like dots in header IDs"""
+        # Explanation: While autogenerated ids are slugified, Markdown allows to manually
+        # specify the ID using the {#custom_id_value} syntax. As HTML5 only requires ID
+        # values not to contain whitespace, we should be able to handle any valid HTML5 ID, too.
+        source = """# Title 1 {#some_id_with.dot}\n\n"""
+        urlpath = URLPath.create_urlpath(
+            URLPath.root(), "testedit", title="TestEdit", content=source
+        )
+        # rendering causes NoReverseMatch without the fix
+        actual = urlpath.article.render()
+        expected = '<h1 id="some_id_with.dot">Title 1<a class="article-edit-title-link" href="/testedit/_plugin/editsection/header/some_id_with.dot/">[edit]</a></h1>'
+        self.assertEqual(actual, expected)
+
 
 class EditSectionEditBase(RequireRootArticleMixin, FuncBaseMixin):
     pass