Layout: a tab wraps away only from text, not from markers alone

A left tab past the right indent, or a right, centre or decimal tab whose text
doesn't fit, wrapped whenever any cluster was before it on the line, so a
bookmark before the tab was left on a line of its own. It now wraps only when
something that takes room is before it.
Test: a_bookmark_before_a_left_tab_past_the_right_indent_is_not_a_line.
This commit is contained in:
dfgodvan
2026-10-19 23:07:57 +03:00
parent a216519d44
commit 076eb68cd0
2 changed files with 28 additions and 2 deletions
+3 -2
View File
@@ -2113,7 +2113,8 @@ fn break_lines(pl: &mut ParaLayout, env: &ParaEnv, mark_style: u32, level: Optio
}
xs.push(x);
if ptab.is_none() && stop.pos > right_edge + 0.01 && stop.align == TabAlign::Left {
if j > c0 {
// Not when only markers (a bookmark, say) are before it: the line is empty.
if (c0..j).any(|k| pl.clusters.get(k).is_some_and(|c| c.kind != ClKind::Marker)) {
// Tab past the right indent wraps: like Word, it starts the next line
// and goes to the first stop there (a TOC entry's leader and page number).
xs.pop();
@@ -2196,7 +2197,7 @@ fn break_lines(pl: &mut ParaLayout, env: &ParaEnv, mark_style: u32, level: Optio
// right margin, after a leader) instead of ending this line.
if let Some((tj, ..)) = pending_tab
&& last_break == Some(tj)
&& tj > c0
&& (c0..tj).any(|k| pl.clusters.get(k).is_some_and(|c| c.kind != ClKind::Marker))
{
last_break = Some(tj - 1);
pending_tab = None;
+25
View File
@@ -1109,6 +1109,31 @@ fn left_tab_past_the_right_indent_does_not_add_a_line() {
assert!((page.x - 72.0).abs() < 0.5, "the text after the tab starts at the indent: {}", page.x);
}
/// A bookmark before such a tab is not text: the tab does not wrap away from it, and the
/// paragraph breaks as it does without the bookmark (no line holding only the bookmark).
#[test]
fn a_bookmark_before_a_left_tab_past_the_right_indent_is_not_a_line() {
use wordcraft_doc::props::{TabAlign, TabLeader, TabStop};
let lines = |mark: bool| {
let mut d = Document::from_text("\tPage");
d.format_paragraphs(&Pos::body(0, 0), &Pos::body(0, 0), &|p| {
p.tabs = Some(vec![TabStop { pos: 500.0, align: TabAlign::Left, leader: TabLeader::None }])
})
.unwrap();
if mark {
d.insert_object(&Pos::body(0, 0), InlineObject::BookmarkStart { name: "top".into() }, &Default::default()).unwrap();
}
let l = lay(&d);
let Some(para) = l.pages[0].items.iter().find_map(|i| if let Placed::Lines { para, .. } = i { Some(para.clone()) } else { None }) else {
panic!("no lines")
};
// The lines' clusters, not counting the bookmark's.
let m = usize::from(mark);
para.lines.iter().map(|l| (l.c0.saturating_sub(m), l.c1 - m)).collect::<Vec<_>>()
};
assert_eq!(lines(true), lines(false));
}
#[test]
fn lists_get_labels_and_indent() {
let mut d = Document::from_text("one\ntwo\nthree");