Repository: executablebooks/mdit-py-plugins

Issue:
Admonition title syntax is not consistent with other implementation
### Describe the bug

**context**

The [admonition syntax](https://mdit-py-plugins.readthedocs.io/en/latest/#containers) is based on [Python Markdown](https://python-markdown.github.io/extensions/admonition/):

~~~markdown
!!! danger "Don't try this at home"
    ...
~~~

**expectation**

I would expect the quotes to be absent from the output.

**bug**

With mdit-py-plugins, the quotes are present in the output:

![image](https://github.com/executablebooks/mdit-py-plugins/assets/946727/7a1543cd-d4a3-4df4-b96a-e225965720ee)

Unexpected output generated by mdit-py-plugins (spurious quotes):

~~~html
<div class="admonition danger"> <p class="admonition-title">"Don't try this at home"</p> <p>...</p> </div>
~~~

Moreover, the [additional CSS classes](https://squidfunk.github.io/mkdocs-material/reference/admonitions/) are not supported either.

Changing the behavior might cause compatiblity issues with [markdown-it-admon](https://github.com/commenthol/markdown-it-admon) however.

**problem**

This is a problem for people migrating from Python Markdown.


### Reproduce the bug

Create markdown file with:

~~~markdown
!!! danger "Don't try this at home"
    ...
~~~

Create script

~~~python3
from markdown_it import MarkdownIt
from mdit_py_plugins.admon import admon_plugin

md_opts = {
    "html": True,
}

markdown_it_render = MarkdownIt("commonmark", md_opts).use(admon_plugin)

source = open("/dev/stdin", "rt").read()
res = markdown_it_render.render(source)
print(res)
~~~

Run:

~~~sh
python3 test.py < test.md
~~~

Output:

~~~html
<div class="admonition danger">
<p class="admonition-title">&quot;Don't try this at home&quot;</p>
<p>...</p>
</div>
~~~

### List your environment

* Python 3.11.4
* Debian Linux
* markdown-it-py==3.0.0
* mdit-py-plugins==0.4.0


Comments:

Patch:
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..06e4886
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,4 @@
+[report]
+exclude_lines =
+    pragma: no cover
+    if TYPE_CHECKING:
diff --git a/mdit_py_plugins/admon/index.py b/mdit_py_plugins/admon/index.py
index a46e8cf..c39a4f7 100644
--- a/mdit_py_plugins/admon/index.py
+++ b/mdit_py_plugins/admon/index.py
@@ -1,7 +1,10 @@
 # Process admonitions and pass to cb.
+
 from __future__ import annotations
 
-from typing import TYPE_CHECKING, Callable, Sequence
+from contextlib import suppress
+import re
+from typing import TYPE_CHECKING, Callable, List, Sequence, Tuple
 
 from markdown_it import MarkdownIt
 from markdown_it.rules_block import StateBlock
@@ -14,20 +17,34 @@ if TYPE_CHECKING:
     from markdown_it.utils import EnvType, OptionsDict
 
 
-def _get_tag(params: str) -> tuple[str, str]:
+def _get_multiple_tags(params: str) -> Tuple[List[str], str]:
+    """Check for multiple tags when the title is double quoted."""
+    re_tags = re.compile(r'^\s*(?P<tokens>[^"]+)\s+"(?P<title>.*)"\S*$')
+    match = re_tags.match(params)
+    if match:
+        tags = match["tokens"].strip().split(" ")
+        return [tag.lower() for tag in tags], match["title"]
+    raise ValueError("No match found for parameters")
+
+
+def _get_tag(_params: str) -> Tuple[List[str], str]:
     """Separate the tag name from the admonition title."""
-    if not params.strip():
-        return "", ""
+    params = _params.strip()
+    if not params:
+        return [""], ""
+
+    with suppress(ValueError):
+        return _get_multiple_tags(params)
 
-    tag, *_title = params.strip().split(" ")
+    tag, *_title = params.split(" ")
     joined = " ".join(_title)
 
     title = ""
     if not joined:
         title = tag.title()
-    elif joined != '""':
+    elif joined != '""':  # Specifically check for no title
         title = joined
-    return tag.lower(), title
+    return [tag.lower()], title
 
 
 def _validate(params: str) -> bool:
@@ -125,12 +142,13 @@ def admonition(state: StateBlock, startLine: int, endLine: int, silent: bool) ->
     # this will prevent lazy continuations from ever going past our end marker
     state.lineMax = next_line
 
-    tag, title = _get_tag(params)
+    tags, title = _get_tag(params)
+    tag = tags[0]
 
     token = state.push("admonition_open", "div", 1)
     token.markup = markup
     token.block = True
-    token.attrs = {"class": " ".join(["admonition", tag, *_extra_classes(markup)])}
+    token.attrs = {"class": " ".join(["admonition", *tags, *_extra_classes(markup)])}
     token.meta = {"tag": tag}
     token.content = title
     token.info = params


Test patch:
diff --git a/tests/fixtures/admon.md b/tests/fixtures/admon.md
index 083d0b9..ffd7d2f 100644
--- a/tests/fixtures/admon.md
+++ b/tests/fixtures/admon.md
@@ -53,6 +53,32 @@ Shows no title
 .
 
 
+Removes extra quotes from the title
+.
+!!! danger "Don't try this at home"
+    ...
+
+.
+<div class="admonition danger">
+<p class="admonition-title">Don't try this at home</p>
+<p>...</p>
+</div>
+.
+
+
+Parse additional classes to support Python markdown (https://github.com/executablebooks/mdit-py-plugins/issues/93#issuecomment-1601822723)
+.
+!!! a b c d inline-classes   "Note: note about "foo"" 
+    ...
+
+.
+<div class="admonition a b c d inline-classes">
+<p class="admonition-title">Note: note about &quot;foo&quot;</p>
+<p>...</p>
+</div>
+.
+
+
 Closes block after 2 empty lines
 .
 !!! note