Fix tab width calculations when word wrapping
This commit is contained in:
parent
3b2a2105fe
commit
5957e8e550
1 changed files with 21 additions and 31 deletions
52
src/wrap.rs
52
src/wrap.rs
|
|
@ -12,10 +12,10 @@ pub fn wrap(widthdb: &mut WidthDB, text: &str, width: usize) -> Vec<usize> {
|
||||||
|
|
||||||
// The last valid break point encountered and its width
|
// The last valid break point encountered and its width
|
||||||
let mut valid_break = None;
|
let mut valid_break = None;
|
||||||
let mut valid_break_width = 0;
|
|
||||||
|
|
||||||
// Width of the line at the current grapheme (with and without trailing
|
// Starting index and width of the line at the current grapheme (with and
|
||||||
// whitespace)
|
// without trailing whitespace)
|
||||||
|
let mut current_start = 0;
|
||||||
let mut current_width = 0;
|
let mut current_width = 0;
|
||||||
let mut current_width_trimmed = 0;
|
let mut current_width_trimmed = 0;
|
||||||
|
|
||||||
|
|
@ -36,65 +36,55 @@ pub fn wrap(widthdb: &mut WidthDB, text: &str, width: usize) -> Vec<usize> {
|
||||||
BreakOpportunity::Mandatory => {
|
BreakOpportunity::Mandatory => {
|
||||||
breaks.push(bi);
|
breaks.push(bi);
|
||||||
valid_break = None;
|
valid_break = None;
|
||||||
valid_break_width = 0;
|
current_start = bi;
|
||||||
current_width = 0;
|
current_width = 0;
|
||||||
current_width_trimmed = 0;
|
current_width_trimmed = 0;
|
||||||
}
|
}
|
||||||
BreakOpportunity::Allowed => {
|
BreakOpportunity::Allowed => {
|
||||||
valid_break = Some(bi);
|
valid_break = Some(bi);
|
||||||
valid_break_width = current_width;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate widths after current grapheme
|
// Calculate widths after current grapheme
|
||||||
let g_is_whitespace = g.chars().all(|c| c.is_whitespace());
|
let g_is_whitespace = g.chars().all(|c| c.is_whitespace());
|
||||||
let g_width = if g == "\t" {
|
let g_width = widthdb.grapheme_width(g, current_width) as usize;
|
||||||
widthdb.tab_width_at_column(current_width) as usize
|
current_width += g_width;
|
||||||
} else {
|
if !g_is_whitespace {
|
||||||
widthdb.grapheme_width(g) as usize
|
current_width_trimmed = current_width;
|
||||||
};
|
}
|
||||||
let g_width_trimmed = if g_is_whitespace { 0 } else { g_width };
|
|
||||||
let mut new_width = current_width + g_width;
|
|
||||||
let mut new_width_trimmed = if g_is_whitespace {
|
|
||||||
current_width_trimmed
|
|
||||||
} else {
|
|
||||||
new_width
|
|
||||||
};
|
|
||||||
|
|
||||||
// Wrap at last break point if necessary
|
// Wrap at last break point if necessary
|
||||||
if new_width_trimmed > width {
|
if current_width_trimmed > width {
|
||||||
if let Some(bi) = valid_break {
|
if let Some(bi) = valid_break {
|
||||||
|
let new_line = &text[bi..gi + g.len()];
|
||||||
|
|
||||||
breaks.push(bi);
|
breaks.push(bi);
|
||||||
new_width -= valid_break_width;
|
|
||||||
new_width_trimmed = new_width_trimmed.saturating_sub(valid_break_width);
|
|
||||||
valid_break = None;
|
valid_break = None;
|
||||||
valid_break_width = 0;
|
current_start = bi;
|
||||||
|
current_width = widthdb.width(new_line);
|
||||||
|
current_width_trimmed = widthdb.width(new_line.trim_end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform a forced break if still necessary
|
// Perform a forced break if still necessary
|
||||||
if new_width_trimmed > width {
|
if current_width_trimmed > width {
|
||||||
if new_width == g_width {
|
if current_start == gi {
|
||||||
// The grapheme is the only thing on the current line and it is
|
// The grapheme is the only thing on the current line and it is
|
||||||
// wider than the maximum width, so we'll allow it, thereby
|
// wider than the maximum width, so we'll allow it, thereby
|
||||||
// forcing the following grapheme to break no matter what
|
// forcing the following grapheme to break no matter what
|
||||||
// (either because of a mandatory or allowed break, or via a
|
// (either because of a mandatory or allowed break, or via a
|
||||||
// forced break).
|
// forced break).
|
||||||
} else {
|
} else {
|
||||||
// Forced break in the midde of a normally non-breakable chunk
|
// Forced break in the middle of a normally non-breakable chunk
|
||||||
// because there are no valid break points.
|
// because there are no valid break points.
|
||||||
breaks.push(gi);
|
breaks.push(gi);
|
||||||
new_width = g_width;
|
|
||||||
new_width_trimmed = g_width_trimmed;
|
|
||||||
valid_break = None;
|
valid_break = None;
|
||||||
valid_break_width = 0;
|
current_start = gi;
|
||||||
|
current_width = widthdb.grapheme_width(g, 0).into();
|
||||||
|
current_width_trimmed = if g_is_whitespace { 0 } else { current_width };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update current width
|
|
||||||
current_width = new_width;
|
|
||||||
current_width_trimmed = new_width_trimmed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
breaks
|
breaks
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue