Skip to content

fix(docx): split paragraphs at page and column breaks - #4587

Open
ankit2235 wants to merge 3 commits into
docling-project:mainfrom
ankit2235:fix/docx-page-column-breaks
Open

ankit2235 wants to merge 3 commits into
docling-project:mainfrom
ankit2235:fix/docx-page-column-breaks

Conversation

@ankit2235

@ankit2235 ankit2235 commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Reworked as discussed in #4585: a page or column break no longer joins the text on either side; it splits the paragraph into separate text items. A line break (<w:br/>) stays \n inside one item.

Behavior

Break in a paragraph Result
Line break One item, with \n at the break
Page or column break, regular paragraph Separate text items under the same parent
Page or column break, title or heading The part before the break keeps the title or heading label; each part after it becomes a regular paragraph under it
Page or column break, list item The part before the break stays the list item; each part after it is text inside that item, so the list does not get an extra item

Each part keeps the formatting of its run, so a break inside one bold run gives two bold parts. Empty parts, for example from a break at the start or end of a paragraph, give no item.

Implementation

  • python-docx reads page and column breaks as "". _get_run_text marks them with a form feed (_BREAK_MARK), which cannot occur in DOCX text because XML 1.0 does not allow it.
  • _get_paragraph_segments splits the runs at the marks before they are grouped by formatting, so a break at a formatting boundary is kept. The grouping loop moved unchanged from _get_paragraph_elements to _group_paragraph_content.
  • _add_segment_text_items adds the items of each segment. _add_body_text_items takes an optional parent, so the text after a break in a list item goes inside that item.
  • _split_off_break_tail gives a title, heading or list item the part before its first break and returns the segments after it.
  • Paragraphs without text or without such a break take the old path, so empty paragraphs are still kept. _handle_text_elements stays under the complexity limit.

Scope

This follows points 1–5 of the contract in #4585. Out of scope: a break inside a hyperlink (point 6), and paragraphs with equations or code, which keep their current behavior.

Tests

  • test_page_and_column_breaks_split_a_paragraph covers line, page and column breaks, including a break inside one bold run.
  • test_page_break_in_a_title_heading_or_list_item covers a page break in a title, a heading and a numbered list item.
  • Both fail on main and pass with this change. The other Word tests, including the groundtruth comparisons, pass unchanged.

Resolves #4585

Checklist:

  • Documentation has been updated, if necessary. (not needed)
  • Examples have been added, if necessary. (not needed)
  • Tests have been added, if necessary.

@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

✅ DCO Check Passed

Thanks @ankit2235, all your commits are properly signed off. 🎉

@mergify

mergify Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🟢 Merge protection satisfied — ready to merge.

Show 1 satisfied protection

🟢 Enforce conventional commit

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\(.+\))?(!)?:

@codecov

codecov Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@ceberam ceberam left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ankit2235 for spotting the issue and suggesting this PR.

I think we first need to clarify the new contract for line, page, and column breaks, since I don't think \n is the right solution for all cases.

Please, check my comment and let me know what you think
#4585 (comment)

@ankit2235

Copy link
Copy Markdown
Contributor Author

Thanks @ceberam! I replied on #4585 with a proposed contract for the split; I'll rework this PR once we agree on it.

Signed-off-by: Ankit Kumar <ankitkumar19473@gmail.com>
@ankit2235
ankit2235 force-pushed the fix/docx-page-column-breaks branch from 014854b to a3d7d30 Compare October 9, 2026 11:04
@ankit2235 ankit2235 changed the title fix(docx): keep page and column breaks from joining text fix(docx): split paragraphs at page and column breaks Oct 9, 2026
@github-actions github-actions Bot added ai:ci-safe AI triage found no CI-safety concern (advisory) bug Something isn't working docx issue related to docx backend labels Oct 9, 2026
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

AI triage (advisory)

Checked commit e7ba6249a5. The analysis read the diff only. It did not run code from this pull request.

The PR splits DOCX paragraphs at page and column breaks into separate text items under the same parent, and keeps <w:br/> line breaks as \n. The diff also applies the split to titles, headings and list items, although the PR text says these stay unchanged.

CI safety: no concern found. A maintainer must still approve CI.

3 related pull request(s) in the same code
PR State Signal Assessment
#4369 open changes the same code related: It changes which XML wrappers _iter_paragraph_content reads. It does not change how breaks split paragraphs. The edits may conflict in the same function.
#4867 open changes the same code related: It is a performance change that caches style chains and paragraph content. It edits _iter_paragraph_content, _get_paragraph_text and _get_paragraph_elements, which this PR also edits. The two PRs will conflict, but they do different things.
#4863 open changes the same code related: It nests sub-lists under the list item above them in _manage_list_structure. This PR changes list item creation for break tails. Both PRs touch list handling, but they fix different problems.

The ai:* labels are advisory. They do not approve CI and they do not add tests:full. A new push runs this check again.

@ankit2235

Copy link
Copy Markdown
Contributor Author

@ceberam I reworked the PR to split paragraphs at page and column breaks, following points 1–3 of the contract in #4585. Headings, titles and list items are unchanged for now; I'm happy to extend it once you confirm points 4–5.

Signed-off-by: Ankit Kumar <ankitkumar19473@gmail.com>

# Conflicts:
#	docling/backend/msword_backend.py
#	tests/test_backend_msword.py
…reaks

Signed-off-by: Ankit Kumar <ankitkumar19473@gmail.com>
@github-actions github-actions Bot added ai:ci-safe AI triage found no CI-safety concern (advisory) and removed ai:ci-safe AI triage found no CI-safety concern (advisory) labels Oct 17, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai:ci-safe AI triage found no CI-safety concern (advisory) bug Something isn't working docx issue related to docx backend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DOCX: a page or column break between two runs joins the text on either side

2 participants