diff --git a/src/multimark/_cli.py b/src/multimark/_cli.py index 34acc4c..2339015 100644 --- a/src/multimark/_cli.py +++ b/src/multimark/_cli.py @@ -51,6 +51,7 @@ @click.option("--hardbreaks", is_flag=True, help="Render softbreaks as hard line breaks.") @click.option("--sourcepos", is_flag=True, help="Include source position attributes (html/xml only).") @click.option("--footnotes", is_flag=True, help="Enable footnote parsing.") +@click.option("--width", type=int, default=0, help="Wrap output at this column width (latex/man/commonmark only).") @click.version_option(__version__, prog_name="multimark") def main( file, @@ -62,6 +63,7 @@ def main( hardbreaks: bool, sourcepos: bool, footnotes: bool, + width: int, ) -> None: """Convert CommonMark/GFM Markdown to various output formats. @@ -83,5 +85,9 @@ def main( if format in ("html", "xml"): kwargs["sourcepos"] = sourcepos + # width is only supported by latex, man, and commonmark renderers + if format in ("latex", "man", "commonmark"): + kwargs["width"] = width + result = renderer(text, **kwargs) output.write(result) diff --git a/tests/test_cli.py b/tests/test_cli.py index 22bbbd0..72ec714 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -138,3 +138,38 @@ def test_help(self, runner): assert result.exit_code == 0 assert "Convert CommonMark/GFM" in result.output assert "--to" in result.output + + +class TestWidth: + def test_width_latex(self, runner): + long_text = "word " * 50 + "\n" + result = runner.invoke(main, ["--to", "latex", "--width", "40"], input=long_text) + assert result.exit_code == 0 + content_lines = [l for l in result.output.split("\n") if "word" in l] + assert all(len(l) <= 40 for l in content_lines) + + def test_width_man(self, runner): + long_text = "word " * 50 + "\n" + result = runner.invoke(main, ["--to", "man", "--width", "60"], input=long_text) + assert result.exit_code == 0 + content_lines = [l for l in result.output.split("\n") if "word" in l] + assert all(len(l) <= 60 for l in content_lines) + + def test_width_commonmark(self, runner): + long_text = "word " * 50 + "\n" + result = runner.invoke(main, ["--to", "commonmark", "--width", "72"], input=long_text) + assert result.exit_code == 0 + content_lines = [l for l in result.output.split("\n") if "word" in l] + assert all(len(l) <= 72 for l in content_lines) + + def test_width_ignored_for_html(self, runner): + result = runner.invoke(main, ["--to", "html", "--width", "40"], input="hello\n") + assert result.exit_code == 0 + assert "
hello
" in result.output + + def test_width_default_no_wrap(self, runner): + long_text = "word " * 50 + "\n" + result = runner.invoke(main, ["--to", "latex"], input=long_text) + assert result.exit_code == 0 + content_lines = [l for l in result.output.split("\n") if "word" in l] + assert any(len(l) > 80 for l in content_lines) diff --git a/tests/test_html.py b/tests/test_html.py index 262f38c..a02c792 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -101,3 +101,74 @@ def test_newline_variations(): """Handles different line ending styles.""" assert markdown_to_html("hello\r\nworld\n") == markdown_to_html("hello\nworld\n") + +# --- GFM-specific Options flags --- + + +def test_github_pre_lang(): + """GITHUB_PRE_LANG adds language as a class on instead of ."""
+ md = "```python\ncode\n```\n"
+ result = markdown_to_html(md, options=Options.GITHUB_PRE_LANG)
+ assert 'lang="python"' in result or 'class="language-python"' in result.replace(
+ "
+ default = markdown_to_html(md)
+ assert 'class="language-python"' in default
+
+
+def test_liberal_html_tag():
+ """LIBERAL_HTML_TAG allows non-standard HTML tags."""
+ result = markdown_to_html(
+ "text \n",
+ options=Options.LIBERAL_HTML_TAG | Options.UNSAFE,
+ )
+ assert "" in result
+
+
+def test_full_info_string():
+ """FULL_INFO_STRING preserves the full info string on code blocks."""
+ md = "```python extra-info\ncode\n```\n"
+ result = markdown_to_html(md, options=Options.FULL_INFO_STRING)
+ assert "extra-info" in result or "data-meta" in result
+
+
+def test_strikethrough_double_tilde():
+ """STRIKETHROUGH_DOUBLE_TILDE requires ~~ (not ~) for strikethrough."""
+ md_double = "~~deleted~~\n"
+ md_single = "~deleted~\n"
+ result_double = markdown_to_html(
+ md_double,
+ extensions=["strikethrough"],
+ options=Options.STRIKETHROUGH_DOUBLE_TILDE,
+ )
+ result_single = markdown_to_html(
+ md_single,
+ extensions=["strikethrough"],
+ options=Options.STRIKETHROUGH_DOUBLE_TILDE,
+ )
+ assert "" in result_double
+ assert "" not in result_single
+
+
+def test_table_prefer_style_attributes():
+ """TABLE_PREFER_STYLE_ATTRIBUTES uses style= instead of align=."""
+ md = "| left | center | right |\n|:-----|:------:|------:|\n| a | b | c |\n"
+ result = markdown_to_html(
+ md, extensions=["table"], options=Options.TABLE_PREFER_STYLE_ATTRIBUTES
+ )
+ assert "style=" in result
+
+
+# --- Footnotes keyword argument ---
+
+
+def test_footnotes_keyword():
+ """footnotes=True enables footnote parsing without extensions list."""
+ md = "Text[^1]\n\n[^1]: A footnote.\n"
+ result = markdown_to_html(md, footnotes=True)
+ assert "footnote" in result.lower()
+ # Without footnotes, the marker is treated as regular text
+ result_no = markdown_to_html(md, footnotes=False)
+ assert "[^1]" in result_no
+
diff --git a/tests/test_latex.py b/tests/test_latex.py
index 15e6129..589c7be 100644
--- a/tests/test_latex.py
+++ b/tests/test_latex.py
@@ -49,6 +49,11 @@ def test_unicode_passthrough():
assert "é" in result
+def test_empty_input():
+ """Empty string produces empty output."""
+ assert markdown_to_latex("") == ""
+
+
def test_empty_input():
assert markdown_to_latex("") == "\n"
diff --git a/tests/test_xml.py b/tests/test_xml.py
index e3d6b15..9ea61db 100644
--- a/tests/test_xml.py
+++ b/tests/test_xml.py
@@ -38,6 +38,18 @@ def test_sourcepos():
assert "sourcepos=\"" in result
+def test_sourcepos_keyword():
+ """sourcepos=True adds sourcepos attributes (keyword form)."""
+ result = markdown_to_xml("Hello\n", sourcepos=True)
+ assert 'sourcepos="1:1-1:5"' in result
+
+
+def test_sourcepos_on_multiple_blocks():
+ """sourcepos is present on each block-level element."""
+ result = markdown_to_xml("# Title\n\nParagraph\n", sourcepos=True)
+ assert result.count('sourcepos="') >= 3 # document, heading, paragraph
+
+
# --- Edge cases ---