diff --git a/docs/features/admonition/callout.md b/docs/features/admonition/callout.md index 544086f..28adb45 100644 --- a/docs/features/admonition/callout.md +++ b/docs/features/admonition/callout.md @@ -70,6 +70,57 @@ See [Demo](demo) for more examples > [!faq]- Are callouts foldable? > Yes! In a foldable callout, the contents are hidden when the callout is collapsed. ``` + +## Nested + +### obsidian callout + +```tabs +---tab obsidian markdown +~~~ +> [!note] some note +> some content before nested notes +> +> > [!note] nested note with no content +> +> > [!note] another nested note with some another content +> > some another content +> +> some content after nested notes +~~~ +---tab obsidian rendered +![[images/callout_3.png]] +``` + +### mkdocs-material admonition + +```tabs +---tab mkdocs-material markdown +~~~ +!!! note "some note" + + some content before nested notes + + !!! note "nested note with no content" + + !!! note "another nested note with some another content" + + some another content + + some content after nested notes +~~~ +---tab mkdocs-material rendered +> [!note] some note +> some content before nested notes +> +> > [!note] nested note with no content +> +> > [!note] another nested note with some another content +> > some another content +> +> some content after nested notes +``` + ## 💡 Notes common types that `obsidian callout` and `mkdocs-material admonition` support are @@ -96,16 +147,12 @@ common types that `obsidian callout`, `mkdocs-material admonition` and even `Git ## Implementation details and Warning > [!warning] implementation limitation -> 1. Nested callout or admonition is not suppoerted -> -> 2. Unlike actual obsidian callout, It requires more precise syntax.
-> there sholud be only zero or one space before and after first `>` character
-> and no space before the rest of `>` characters and one space after it. +> Unlike actual obsidian callout, It requires more precise syntax.
+> there sholud be only zero or one space before and after first `>` character
+> and no space before the rest of `>` characters and one space after it. > > recommended format is as below > ```text > > [!info] > > copy me > ``` - - diff --git a/obsidian_support/conversion/abstract_conversion.py b/obsidian_support/conversion/abstract_conversion.py index ec7e02a..6da77d9 100644 --- a/obsidian_support/conversion/abstract_conversion.py +++ b/obsidian_support/conversion/abstract_conversion.py @@ -33,14 +33,14 @@ def obsidian_regex_groups(self): return list(self.obsidian_regex_pattern.groupindex.keys()) @abstractmethod - def convert(self, syntax_groups: SyntaxGroup, page: Page) -> str: + def convert(self, syntax_groups: SyntaxGroup, page: Page, depth: int) -> str: pass """ A template method that applies conversion for every regex matches """ - def markdown_convert(self, markdown: str, page: Page) -> str: + def markdown_convert(self, markdown: str, page: Page, depth: int = 0) -> str: converted_markdown = "" index = 0 excluded_indices = get_exclude_indices(markdown) @@ -56,7 +56,7 @@ def markdown_convert(self, markdown: str, page: Page) -> str: syntax_groups = list(map(lambda group: obsidian_syntax.group(group), self.obsidian_regex_groups)) - mkdocs_syntax = self.convert(syntax_groups, page) + mkdocs_syntax = self.convert(syntax_groups, page, depth) converted_markdown += markdown[index:start] converted_markdown += mkdocs_syntax index = end + 1 diff --git a/obsidian_support/conversion/admonition/admonition_backquotes.py b/obsidian_support/conversion/admonition/admonition_backquotes.py index 0f79fc2..45e14c9 100644 --- a/obsidian_support/conversion/admonition/admonition_backquotes.py +++ b/obsidian_support/conversion/admonition/admonition_backquotes.py @@ -46,7 +46,7 @@ def obsidian_regex_pattern(self): """, flags=re.VERBOSE) @override - def convert(self, syntax_groups: SyntaxGroup, page: Page) -> str: + def convert(self, syntax_groups: SyntaxGroup, page: Page, depth: int) -> str: return self._create_admonition(*syntax_groups) def _create_admonition(self, place, ad_type: str, title: str, collapse: str, contents: str) -> str: diff --git a/obsidian_support/conversion/admonition/admonition_callout.py b/obsidian_support/conversion/admonition/admonition_callout.py index 0156224..4c8defe 100644 --- a/obsidian_support/conversion/admonition/admonition_callout.py +++ b/obsidian_support/conversion/admonition/admonition_callout.py @@ -39,10 +39,11 @@ def obsidian_regex_pattern(self): """, flags=re.VERBOSE) @override - def convert(self, syntax_groups: SyntaxGroup, page: Page) -> str: - return self._create_admonition(*syntax_groups) + def convert(self, syntax_groups: SyntaxGroup, page: Page, depth: int) -> str: + return self._create_admonition(page, depth, *syntax_groups) - def _create_admonition(self, place, ad_type: str, collapse: str, title: str, contents: str) -> str: + def _create_admonition(self, page: Page, depth: int, place: str, ad_type: str, collapse: str, title: str, + contents: str) -> str: contents = contents.replace("\n> ", "\n ") contents = contents.replace("\n > ", "\n ") contents = contents.replace("\n>", "\n ") @@ -60,5 +61,18 @@ def _create_admonition(self, place, ad_type: str, collapse: str, title: str, con else: collapse = "!!! " - admonition = place + collapse + ad_type + title + "\n" + contents + de_indented_contents = self._de_indent(contents) + contents = self.markdown_convert(de_indented_contents, page, depth) + re_indented_contents = self._indent(depth + 1, contents) + + admonition = place + collapse + ad_type + title + "\n" + re_indented_contents return admonition + + def _de_indent(self, contents: str) -> str: + contents = contents.replace("\n ", "\n") + return contents + + def _indent(self, depth: int, contents: str) -> str: + indent = " " * 4 * depth + contents = contents.replace("\n", "\n" + indent) + return contents diff --git a/obsidian_support/conversion/comment/comment.py b/obsidian_support/conversion/comment/comment.py index f9995ed..2c5e901 100644 --- a/obsidian_support/conversion/comment/comment.py +++ b/obsidian_support/conversion/comment/comment.py @@ -24,7 +24,7 @@ def obsidian_regex_pattern(self): return re.compile(r"%%(?P[\S\s]*?)%%") @override - def convert(self, syntax_groups: SyntaxGroup, page: Page) -> str: + def convert(self, syntax_groups: SyntaxGroup, page: Page, depth: int) -> str: return self._convert_comment(*syntax_groups) def _convert_comment(self, comment): diff --git a/obsidian_support/conversion/image_link/image_internal_link.py b/obsidian_support/conversion/image_link/image_internal_link.py index 1e0e04a..90f5d34 100644 --- a/obsidian_support/conversion/image_link/image_internal_link.py +++ b/obsidian_support/conversion/image_link/image_internal_link.py @@ -25,7 +25,7 @@ def obsidian_regex_pattern(self): return re.compile(r"!\[\[(?P[^|^\]]+)(?P|.+)?]]") @override - def convert(self, syntax_groups: SyntaxGroup, page: Page) -> str: + def convert(self, syntax_groups: SyntaxGroup, page: Page, depth: int) -> str: return self._convert_image_internal_link(*syntax_groups) def _convert_image_internal_link(self, image_path: str, tags: str) -> str: diff --git a/obsidian_support/conversion/image_link/image_web_link.py b/obsidian_support/conversion/image_link/image_web_link.py index babdbee..a789089 100644 --- a/obsidian_support/conversion/image_link/image_web_link.py +++ b/obsidian_support/conversion/image_link/image_web_link.py @@ -27,7 +27,7 @@ def obsidian_regex_pattern(self): return re.compile(r"!\[(?P(?!\\).*)]\((?Phttps?://.*)\)") @override - def convert(self, syntax_groups: SyntaxGroup, page: Page) -> str: + def convert(self, syntax_groups: SyntaxGroup, page: Page, depth: int) -> str: return self._convert_image_link(*syntax_groups) def _convert_image_link(self, tags: str, image_path: str) -> str: diff --git a/obsidian_support/conversion/pdf/pdf.py b/obsidian_support/conversion/pdf/pdf.py index 7026d70..bd300da 100644 --- a/obsidian_support/conversion/pdf/pdf.py +++ b/obsidian_support/conversion/pdf/pdf.py @@ -21,7 +21,7 @@ def obsidian_regex_pattern(self): return re.compile(r"!\[\[(?P[^|^\]]+\.pdf)(?P#height=\d+)?]]") @override - def convert(self, syntax_groups: SyntaxGroup, page: Page) -> str: + def convert(self, syntax_groups: SyntaxGroup, page: Page, depth: int) -> str: base_path = page.canonical_url[:-len(page.url)] return self._convert_tags(base_path, *syntax_groups) diff --git a/obsidian_support/conversion/tabs/tabs_backquotes.py b/obsidian_support/conversion/tabs/tabs_backquotes.py index 44cd4fa..bb7e7c2 100644 --- a/obsidian_support/conversion/tabs/tabs_backquotes.py +++ b/obsidian_support/conversion/tabs/tabs_backquotes.py @@ -20,7 +20,7 @@ def obsidian_regex_pattern(self): """, flags=re.VERBOSE) @override - def convert(self, syntax_groups: SyntaxGroup, page: Page) -> str: + def convert(self, syntax_groups: SyntaxGroup, page: Page, depth: int) -> str: return self._create_content_tabs(*syntax_groups) def _create_content_tabs(self, place, tabs) -> str: diff --git a/obsidian_support/conversion/tabs/tabs_tilde_block.py b/obsidian_support/conversion/tabs/tabs_tilde_block.py index 074b18b..d434a10 100644 --- a/obsidian_support/conversion/tabs/tabs_tilde_block.py +++ b/obsidian_support/conversion/tabs/tabs_tilde_block.py @@ -20,7 +20,7 @@ def obsidian_regex_pattern(self): """, flags=re.VERBOSE) @override - def convert(self, syntax_groups: SyntaxGroup, page: Page) -> str: + def convert(self, syntax_groups: SyntaxGroup, page: Page, depth: int) -> str: return self._create_content_tabs(*syntax_groups) def _create_content_tabs(self, place, tabs) -> str: diff --git a/obsidian_support/conversion/tags/tags.py b/obsidian_support/conversion/tags/tags.py index b77f608..e3bd856 100644 --- a/obsidian_support/conversion/tags/tags.py +++ b/obsidian_support/conversion/tags/tags.py @@ -20,7 +20,7 @@ def obsidian_regex_pattern(self): return re.compile(r"(?[\w\-_\/]+)(?![^\[\(]*[\]\)])") @override - def convert(self, syntax_groups: SyntaxGroup, page: Page) -> str: + def convert(self, syntax_groups: SyntaxGroup, page: Page, depth: int) -> str: return self._convert_tags(*syntax_groups) def _convert_tags(self, tags: str) -> str: diff --git a/test/conversion/admonition/test_admonition_callout.py b/test/conversion/admonition/test_admonition_callout.py index 17635d4..1be24f2 100644 --- a/test/conversion/admonition/test_admonition_callout.py +++ b/test/conversion/admonition/test_admonition_callout.py @@ -5,7 +5,7 @@ from obsidian_support.conversion.admonition.admonition_callout import AdmonitionCalloutConversion -def test_admonition_backquotes_conversion(): +def test_admonition_backquotes_conversion_1(): # given conversion = AdmonitionCalloutConversion() markdown = cleandoc(""" @@ -22,3 +22,38 @@ def test_admonition_backquotes_conversion(): some content """)) + + +def test_admonition_backquotes_conversion_2(): + # given + conversion = AdmonitionCalloutConversion() + markdown = cleandoc(""" + > [!note] some note + > some content before nested notes + > + > > [!note] nested note with no content + > + > > [!note] another nested note with some another content + > > some another content + > + > some content after nested notes + """) + + # when + converted = conversion.markdown_convert(markdown, None) + + # then + assert_that(converted).is_equal_to(cleandoc(""" + !!! note "some note" + + some content before nested notes + + !!! note "nested note with no content" + + + !!! note "another nested note with some another content" + + some another content + + some content after nested notes + """))