From ec323783065568683b1f347113dac6aae5f8cb8b Mon Sep 17 00:00:00 2001
From: geopanther
Date: Fri, 12 Jun 2026 21:00:12 +0200
Subject: [PATCH 1/4] chore: disable line numbers in Confluence code blocks
---
CHANGELOG.md | 1 +
mdfluence/confluence_renderer.py | 2 +-
test_package/functional/result.xml | 12 ++++++------
test_package/unit/test_renderer.py | 4 ++--
4 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1f99f3c..ab879e1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
+- Disable line numbers in Confluence code blocks for cleaner rendering
- Use stdlib `html.parser.HTMLParser` for robust HTML-to-XHTML conversion instead of regex
- Use dynamic default branch detection in publish-release script
diff --git a/mdfluence/confluence_renderer.py b/mdfluence/confluence_renderer.py
index 0bb4415..79df2ce 100644
--- a/mdfluence/confluence_renderer.py
+++ b/mdfluence/confluence_renderer.py
@@ -274,7 +274,7 @@ def block_code(self, code, info=None):
if info is not None:
lang_parameter = self.parameter(name="language", value=info)
root_element.append(lang_parameter)
- root_element.append(self.parameter(name="linenumbers", value="true"))
+ root_element.append(self.parameter(name="linenumbers", value="false"))
root_element.append(self.plain_text_body(code))
return root_element.render()
diff --git a/test_package/functional/result.xml b/test_package/functional/result.xml
index a93e555..44290d7 100644
--- a/test_package/functional/result.xml
+++ b/test_package/functional/result.xml
@@ -96,7 +96,7 @@ and code blocks:
This is the second list item.
Here's some example code:
-true
+false
@@ -205,7 +205,7 @@ inside a list item.
to be indented twice -- 8 spaces or two tabs:
A list item with a code block:
-true
+false
]]>
@@ -218,11 +218,11 @@ in both <pre> and <code> tags.
To produce a code block in Markdown, simply indent every line of the
block by at least 4 spaces or 1 tab.
This is a normal paragraph:
-true
+false
Here is an example of AppleScript:
-true
+false
@@ -234,7 +234,7 @@ are automatically converted into HTML entities. This makes it very
easy to include example HTML source code using Markdown -- just paste
it and indent it, and Markdown will handle the hassle of encoding the
ampersands and angle brackets. For example, this:
-true
+false
© 2004 Foo Corporation
]]>
@@ -242,7 +242,7 @@ ampersands and angle brackets. For example, this:
Regular Markdown syntax is not processed within code blocks. E.g.,
asterisks are just literal asterisks within a code block. This means
it's also easy to use Markdown to write about Markdown's own syntax.
-true
+false
'
- 'true\n'
+ 'false\n'
"\n"
"\n"
)
@@ -148,7 +148,7 @@ def test_renderer_block_code_with_language():
test_markup = (
''
'whitespace\n'
- 'true\n'
+ 'false\n'
"\n"
"\n"
)
From f20c81bee3e40ba4ec52a3d3f62f4b4cee3b913a Mon Sep 17 00:00:00 2001
From: geopanther
Date: Sat, 13 Jun 2026 10:02:47 +0200
Subject: [PATCH 2/4] docs: document --enable-line-numbers flag in README
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 693fe7f..4fe7090 100644
--- a/README.md
+++ b/README.md
@@ -186,6 +186,10 @@ In file.md:
By default, relative links that point to non-existent files (or files that are not being uploaded in the current batch) will result in an error. To ignore these errors and keep the links as they are, use the `--ignore-relative-link-errors` flag.
+## Code blocks
+
+By default, line numbers are disabled in Confluence code blocks for cleaner output. To render line numbers alongside your code, pass the `--enable-line-numbers` flag.
+
## Directory arguments
### Uploading Folders Recursively
From af2313069ef8903bdd513703dd284b5a67657e93 Mon Sep 17 00:00:00 2001
From: geopanther
Date: Sat, 13 Jun 2026 10:04:35 +0200
Subject: [PATCH 3/4] feat: add --enable-line-numbers flag for Confluence code
blocks
Add a CLI switch to optionally render line numbers in Confluence code
blocks. Default is off. Threads enable_line_numbers through
document parsing and ConfluenceRenderer.
---
CHANGELOG.md | 2 +-
mdfluence/__main__.py | 9 ++++++
mdfluence/confluence_renderer.py | 5 +++-
mdfluence/document.py | 8 +++++
.../functional/test_full_rendering.py | 13 ++++++++
test_package/unit/test_renderer.py | 30 +++++++++++++++++++
6 files changed, 65 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab879e1..d496933 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
-- Disable line numbers in Confluence code blocks for cleaner rendering
+- Add `--enable-line-numbers` CLI switch for Confluence code blocks (default: off)
- Use stdlib `html.parser.HTMLParser` for robust HTML-to-XHTML conversion instead of regex
- Use dynamic default branch detection in publish-release script
diff --git a/mdfluence/__main__.py b/mdfluence/__main__.py
index ca560b0..83b8867 100644
--- a/mdfluence/__main__.py
+++ b/mdfluence/__main__.py
@@ -245,6 +245,12 @@ def get_parser():
help="disable conversion of :shortcode: emoji to Unicode characters",
)
+ parser.add_argument(
+ "--enable-line-numbers",
+ action="store_true",
+ help="enable line numbers in Confluence code blocks",
+ )
+
parser.add_argument(
"--render-diagrams",
action="store_true",
@@ -710,6 +716,7 @@ def collect_pages_to_upload(args):
mmdc_path=args.mmdc_path,
plantuml_path=args.plantuml_path,
title_prefix=args.prefix,
+ enable_line_numbers=args.enable_line_numbers,
)
)
@@ -743,6 +750,7 @@ def collect_pages_to_upload(args):
mmdc_path=args.mmdc_path,
plantuml_path=args.plantuml_path,
title_prefix=args.prefix,
+ enable_line_numbers=args.enable_line_numbers,
)
else:
try:
@@ -761,6 +769,7 @@ def collect_pages_to_upload(args):
mmdc_path=args.mmdc_path,
plantuml_path=args.plantuml_path,
title_prefix=args.prefix,
+ enable_line_numbers=args.enable_line_numbers,
)
)
except FileNotFoundError:
diff --git a/mdfluence/confluence_renderer.py b/mdfluence/confluence_renderer.py
index 79df2ce..e3f248d 100644
--- a/mdfluence/confluence_renderer.py
+++ b/mdfluence/confluence_renderer.py
@@ -134,10 +134,12 @@ def __init__(
render_diagrams=False,
mmdc_path=None,
plantuml_path=None,
+ enable_line_numbers=False,
):
super().__init__(escape=False)
self.strip_header = strip_header
self.remove_text_newlines = remove_text_newlines
+ self.enable_line_numbers = enable_line_numbers
self.attachments = list()
self.title = None
self.enable_relative_links = enable_relative_links
@@ -274,7 +276,8 @@ def block_code(self, code, info=None):
if info is not None:
lang_parameter = self.parameter(name="language", value=info)
root_element.append(lang_parameter)
- root_element.append(self.parameter(name="linenumbers", value="false"))
+ linenumbers_value = "true" if self.enable_line_numbers else "false"
+ root_element.append(self.parameter(name="linenumbers", value=linenumbers_value))
root_element.append(self.plain_text_body(code))
return root_element.render()
diff --git a/mdfluence/document.py b/mdfluence/document.py
index 8dc3774..50ed1ff 100644
--- a/mdfluence/document.py
+++ b/mdfluence/document.py
@@ -131,6 +131,7 @@ def get_pages_from_directory(
mmdc_path: str | None = None,
plantuml_path: str | None = None,
title_prefix: str | None = None,
+ enable_line_numbers: bool = False,
) -> List[Page]:
"""
Collect a list of markdown files recursively under the file_path directory.
@@ -251,6 +252,7 @@ def get_pages_from_directory(
mmdc_path=mmdc_path,
plantuml_path=plantuml_path,
title_prefix=title_prefix,
+ enable_line_numbers=enable_line_numbers,
)
processed_page.parent_title = parent_page_title
processed_pages.append(processed_page)
@@ -275,6 +277,7 @@ def get_page_data_from_file_path(
mmdc_path: str | None = None,
plantuml_path: str | None = None,
title_prefix: str | None = None,
+ enable_line_numbers: bool = False,
) -> Page:
if not isinstance(file_path, Path):
file_path = Path(file_path)
@@ -299,6 +302,7 @@ def get_page_data_from_file_path(
mmdc_path=mmdc_path,
plantuml_path=plantuml_path,
title_prefix=title_prefix,
+ enable_line_numbers=enable_line_numbers,
)
if not page.title:
@@ -320,6 +324,7 @@ def get_page_data_from_lines(
mmdc_path: str | None = None,
plantuml_path: str | None = None,
title_prefix: str | None = None,
+ enable_line_numbers: bool = False,
) -> Page:
frontmatter = get_document_frontmatter(markdown_lines)
if "frontmatter_end_line" in frontmatter:
@@ -339,6 +344,7 @@ def get_page_data_from_lines(
mmdc_path=mmdc_path,
plantuml_path=plantuml_path,
title_prefix=title_prefix,
+ enable_line_numbers=enable_line_numbers,
)
if "title" in frontmatter:
@@ -366,6 +372,7 @@ def parse_page(
mmdc_path: str | None = None,
plantuml_path: str | None = None,
title_prefix: str | None = None,
+ enable_line_numbers: bool = False,
) -> Page:
markdown_text = "".join(markdown_lines)
@@ -385,6 +392,7 @@ def parse_page(
render_diagrams=render_diagrams,
mmdc_path=mmdc_path,
plantuml_path=plantuml_path,
+ enable_line_numbers=enable_line_numbers,
)
confluence_mistune = mistune.Markdown(renderer=renderer)
for plugin in [
diff --git a/test_package/functional/test_full_rendering.py b/test_package/functional/test_full_rendering.py
index e021df7..b3628d4 100644
--- a/test_package/functional/test_full_rendering.py
+++ b/test_package/functional/test_full_rendering.py
@@ -22,3 +22,16 @@ def test_full_document(script_loc):
assert page.body == result_data
assert page.title == "Markdown: Syntax"
+
+
+def test_full_document_with_line_numbers(script_loc):
+ markdown_path = script_loc.join("test.md")
+
+ page = document.get_page_data_from_file_path(
+ markdown_path, enable_line_numbers=True
+ )
+
+ # All code blocks should have linenumbers set to true
+ assert 'true' in page.body
+ assert 'false' not in page.body
+ assert page.title == "Markdown: Syntax"
diff --git a/test_package/unit/test_renderer.py b/test_package/unit/test_renderer.py
index ac00787..2fb872e 100644
--- a/test_package/unit/test_renderer.py
+++ b/test_package/unit/test_renderer.py
@@ -158,6 +158,36 @@ def test_renderer_block_code_with_language():
assert renderer.block_code(test_code, info=test_language) == test_markup
+def test_renderer_block_code_with_line_numbers():
+ test_code = "this is a piece of code"
+ test_markup = (
+ ''
+ 'true\n'
+ "\n"
+ "\n"
+ )
+
+ renderer = ConfluenceRenderer(enable_line_numbers=True)
+
+ assert renderer.block_code(test_code) == test_markup
+
+
+def test_renderer_block_code_with_language_and_line_numbers():
+ test_code = "this is a piece of code"
+ test_language = "python"
+ test_markup = (
+ ''
+ 'python\n'
+ 'true\n'
+ "\n"
+ "\n"
+ )
+
+ renderer = ConfluenceRenderer(enable_line_numbers=True)
+
+ assert renderer.block_code(test_code, info=test_language) == test_markup
+
+
def test_renderer_header_sets_title():
test_header = "this is a header"
renderer = ConfluenceRenderer()
From aa2584a86d44ca62e5afa7bf54ed96cdde78682d Mon Sep 17 00:00:00 2001
From: geopanther
Date: Sat, 13 Jun 2026 10:14:02 +0200
Subject: [PATCH 4/4] docs(changelog): split line-numbers flag, flag default
change
---
CHANGELOG.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d496933..9e9031a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
+### Added
+
+- `--enable-line-numbers` CLI flag to opt in to line numbers for Confluence code blocks
+
### Fixed
- Pass title prefix through rendering pipeline so Confluence anchors use the correct prefixed page title
@@ -15,7 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
-- Add `--enable-line-numbers` CLI switch for Confluence code blocks (default: off)
+- **BREAKING (pre-1.0):** Confluence code block line numbers are now **off by default**. Existing users will lose line numbers on their next upload unless they pass `--enable-line-numbers`.
- Use stdlib `html.parser.HTMLParser` for robust HTML-to-XHTML conversion instead of regex
- Use dynamic default branch detection in publish-release script