summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Otto <th1000s@posteo.net>2021-11-01 22:31:33 +0100
committerDan Davison <dandavison7@gmail.com>2021-11-10 20:08:28 -0500
commit93d37649ae63312548bb319e5d6d7305834e502f (patch)
tree22f54397bed36d19f3667d80ffeca0e618901286
parent54bab7051774c82d5af9d6024f03529008254657 (diff)
Remove +/- line prefix instead of substituting a space
Simplifies line handling and printing by removing a "magical" 1-offset previously required in various locations. Now explicitly prepend "" in `tokenize()`.
-rw-r--r--src/align.rs8
-rw-r--r--src/edits.rs31
-rw-r--r--src/features/side_by_side.rs18
-rw-r--r--src/handlers/hunk_header.rs11
-rw-r--r--src/paint.rs59
-rw-r--r--src/tests/ansi_test_utils.rs2
-rw-r--r--src/tests/test_example_diffs.rs7
-rw-r--r--src/wrapping.rs228
8 files changed, 179 insertions, 185 deletions
diff --git a/src/align.rs b/src/align.rs
index 4cd102c6..6da05cc1 100644
--- a/src/align.rs
+++ b/src/align.rs
@@ -17,13 +17,14 @@ use Operation::*;
/// Needleman-Wunsch / Wagner-Fischer table for computation of edit distance and associated
/// alignment.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
struct Cell {
parent: usize,
operation: Operation,
cost: usize,
}
+#[derive(Debug)]
pub struct Alignment<'a> {
pub x: Vec<&'a str>,
pub y: Vec<&'a str>,
@@ -34,9 +35,8 @@ pub struct Alignment<'a> {
impl<'a> Alignment<'a> {
/// Fill table for Levenshtein distance / alignment computation
pub fn new(x: Vec<&'a str>, y: Vec<&'a str>) -> Self {
- // TODO: Something about the alignment algorithm requires that the first two items in the
- // token stream are ["", " "]. In practice this means that the line must have a leading
- // space, and that the tokenization regex cooperates.
+ // TODO: Something downstream of the alignment algorithm requires that the first token in
+ // both x and y is "", so this is explicitly inserted in `tokenize()`.
let dim = [y.len() + 1, x.len() + 1];
let table = vec![
Cell {
diff --git a/src/edits.rs b/src/edits.rs
index 06d934ff..11979aa8 100644
--- a/src/edits.rs
+++ b/src/edits.rs
@@ -30,8 +30,7 @@ pub fn infer_edits<'a, EditOperation>(
Vec<(Option<usize>, Option<usize>)>, // line alignment
)
where
- EditOperation: Copy,
- EditOperation: PartialEq,
+ EditOperation: Copy + PartialEq + std::fmt::Debug,
{
let mut annotated_minus_lines = Vec::<Vec<(EditOperation, &str)>>::new();
let mut annotated_plus_lines = Vec::<Vec<(EditOperation, &str)>>::new();
@@ -95,7 +94,9 @@ where
/// Split line into tokens for alignment. The alignment algorithm aligns sequences of substrings;
/// not individual characters.
fn tokenize<'a>(line: &'a str, regex: &Regex) -> Vec<&'a str> {
- let mut tokens = Vec::new();
+ // Starting with "", see comment in Alignment::new(). Historical note: Replacing the '+/-'
+ // prefix with a space implicitly generated this.
+ let mut tokens = vec![""];
let mut offset = 0;
for m in regex.find_iter(line) {
if offset == 0 && m.start() > 0 {
@@ -136,8 +137,7 @@ fn annotate<'a, Annotation>(
plus_line: &'a str,
) -> (Vec<(Annotation, &'a str)>, Vec<(Annotation, &'a str)>, f64)
where
- Annotation: Copy,
- Annotation: PartialEq,
+ Annotation: Copy + PartialEq + std::fmt::Debug,
{
let mut annotated_minus_line = Vec::new();
let mut annotated_plus_line = Vec::new();
@@ -467,7 +467,10 @@ mod tests {
fn assert_tokenize(text: &str, expected_tokens: &[&str]) {
let actual_tokens = tokenize(text, &*DEFAULT_TOKENIZATION_REGEXP);
assert_eq!(text, expected_tokens.iter().join(""));
- assert_eq!(actual_tokens, expected_tokens);
+ // tokenize() guarantees that the first element of the token stream is "".
+ // See comment in Alignment::new()
+ assert_eq!(actual_tokens[0], "");
+ assert_eq!(&actual_tokens[1..], expected_tokens);
}
#[test]
@@ -476,8 +479,8 @@ mod tests {
vec!["aaa"],
vec!["aba"],
(
- vec![vec![(Deletion, "aaa")]],
- vec![vec![(Insertion, "aba")]],
+ vec![vec![(MinusNoop, ""), (Deletion, "aaa")]],
+ vec![vec![(PlusNoop, ""), (Insertion, "aba")]],
),
)
}
@@ -488,8 +491,12 @@ mod tests {
vec!["aaa ccc"],
vec!["aba ccc"],
(
- vec![vec![(Deletion, "aaa"), (MinusNoop, " ccc")]],
- vec![vec![(Insertion, "aba"), (PlusNoop, " ccc")]],
+ vec![vec![
+ (MinusNoop, ""),
+ (Deletion, "aaa"),
+ (MinusNoop, " ccc"),
+ ]],
+ vec![vec![(PlusNoop, ""), (Insertion, "aba"), (PlusNoop, " ccc")]],
),
)
}
@@ -500,8 +507,8 @@ mod tests {
vec!["áaa"],
vec!["ááb"],
(
- vec![vec![(Deletion, "áaa")]],
- vec![vec![(Insertion, "ááb")]],
+ vec![vec![(MinusNoop, ""), (Deletion, "áaa")]],
+ vec![vec![(PlusNoop, ""), (Insertion, "ááb")]],
),
)
}
diff --git a/src/features/side_by_side.rs b/src/features/side_by_side.rs
index ddc7f55d..7f944772 100644
--- a/src/features/side_by_side.rs
+++ b/src/features/side_by_side.rs
@@ -62,7 +62,8 @@ pub fn available_line_width(
) -> line_numbers::SideBySideLineWidth {
let linennumbers_width = data.formatted_width();
- // The width can be reduced by the line numbers and/or a possibly kept 1-wide "+/-/ " prefix.
+ // The width can be reduced by the line numbers and/or
+ // a possibly added/restored 1-wide "+/-/ " prefix.
let line_width = |side: PanelSide| {
config.side_by_side_data[side]
.width
@@ -76,15 +77,15 @@ pub fn available_line_width(
pub fn line_is_too_long(line: &str, line_width: usize) -> bool {
let line_sum = line.graphemes(true).count();
- // `line_sum` is too large, because both a leading "+/-/ " and a trailing
- // newline are present, counted, but are never printed. So allow two more
- // characters.
- line_sum > line_width + 2
+ debug_assert!(line.ends_with('\n'));
+ // `line_sum` is too large because a trailing newline is present,
+ // so allow one more character.
+ line_sum > line_width + 1
}
/// Return whether any of the input lines is too long, and a data
-/// structure indicating which are too long. This avoids
-/// calculating the length again later.
+/// structure indicating which of the input lines are too long. This avoids
+/// recalculating the length later.
pub fn has_long_lines(
lines: &LeftRight<&Vec<(String, State)>>,
line_width: &line_numbers::SideBySideLineWidth,
@@ -325,8 +326,7 @@ fn get_right_fill_style_for_panel<'a>(
// wish to display the right panel, with its line number container, but without any line number
// (and without any line contents). We do this by passing (HunkMinus, Right) to `paint_line`, since
// what this will do is set the line number pair in that function to `(Some(minus_number), None)`,
-// and then only emit the right field (which has a None number, i.e. blank). However, it will also
-// increment the minus line number, so we need to knock that back down.
+// and then only emit the right field (which has a None number, i.e. blank).
#[allow(clippy::too_many_arguments)]
fn paint_minus_or_plus_panel_line<'a>(
line_index: Option<usize>,
diff --git a/src/handlers/hunk_header.rs b/src/handlers/hunk_header.rs
index a48ad834..525b749d 100644
--- a/src/handlers/hunk_header.rs
+++ b/src/handlers/hunk_header.rs
@@ -166,7 +166,7 @@ fn write_hunk_header(
let (mut draw_fn, _, decoration_ansi_term_style) =
draw::get_draw_function(config.hunk_header_style.decoration_style);
let line = if config.color_only {
- format!(" {}", &line)
+ line.to_string()
} else if !code_fragment.is_empty() {
format!("{} ", code_fragment)
} else {
@@ -242,7 +242,14 @@ fn write_to_output_buffer(
);
}
if !file_with_line_number.is_empty() {
- let _ = write!(&mut painter.output_buffer, "{}: ", file_with_line_number);
+ // The code fragment in "line" adds whitespace, but if only a line number is printed
+ // then the trailing space must be added.
+ let space = if line.is_empty() { " " } else { "" };
+ let _ = write!(
+ &mut painter.output_buffer,
+ "{}:{}",
+ file_with_line_number, space
+ );
}
if !line.is_empty() {
painter.syntax_highlight_and_paint_line(
diff --git a/src/paint.rs b/src/paint.rs
index 0315b19f..264cecdc 100644
--- a/src/paint.rs
+++ b/src/paint.rs
@@ -109,8 +109,7 @@ impl<'p> Painter<'p> {
};
}
- /// Replace initial -/+ character with ' ', expand tabs as spaces, and optionally terminate with
- /// newline.
+ /// Remove initial -/+ character, expand tabs as spaces, and terminate with newline.
// Terminating with newline character is necessary for many of the sublime syntax definitions to
// highlight correctly.
// See https://docs.rs/syntect/3.2.0/syntect/parsing/struct.SyntaxSetBuilder.html#method.add_from_folder
@@ -118,15 +117,11 @@ impl<'p> Painter<'p> {
if !line.is_empty() {
let mut line = line.graphemes(true);
- // The first column contains a -/+/space character, added by git. We substitute it for
- // a space now, so that it is not present during syntax highlighting. When emitting the
- // line in Painter::paint_line, we drop the space (unless --keep-plus-minus-markers is
- // in effect in which case we replace it with the appropriate marker).
- // TODO: Things should, but do not, work if this leading space is omitted at this stage.
- // See comment in align::Alignment::new.
- // Note that a wrapped line also has a leading character added to remain compatible.
+ // The first column contains a -/+/space character, added by git. We remove it now so that
+ // it is not present during syntax highlighting or wrapping. If --keep-plus-minus-markers is
+ // in effect this character is re-inserted in Painter::paint_line.
line.next();
- format!(" {}\n", self.expand_tabs(line))
+ format!("{}\n", self.expand_tabs(line))
} else {
"\n".to_string()
}
@@ -301,10 +296,12 @@ impl<'p> Painter<'p> {
pub fn paint_zero_line(&mut self, line: &str) {
let state = State::HunkZero;
let painted_prefix = if self.config.keep_plus_minus_markers && !line.is_empty() {
+ // A zero line here still contains the " " prefix, so use it.
Some(self.config.zero_style.paint(&line[..1]))
} else {
None
};
+
let lines = vec![(self.prepare(line), state.clone())];
let syntax_style_sections = Painter::get_syntax_style_sections_for_lines(
&lines,
@@ -567,11 +564,7 @@ impl<'p> Painter<'p> {
// This line has been identified as one which should be emitted unchanged,
// including any ANSI escape sequences that it has.
return (
- format!(
- "{}{}",
- ansi_term::ANSIStrings(&ansi_strings).to_string(),
- raw_line
- ),
+ format!("{}{}", ansi_term::ANSIStrings(&ansi_strings), raw_line),
false,
);
}
@@ -587,24 +580,15 @@ impl<'p> Painter<'p> {
let mut handled_prefix = false;
for (section_style, text) in &superimposed {
- let text = if handled_prefix {
- &text
- } else {
- // Remove what was originally the +/- prefix, see `prepare()`, after
- // (if requested) re-inserting it with proper styling.
+ // If requested re-insert the +/- prefix with proper styling.
+ if !handled_prefix {
if let Some(ref painted_prefix) = painted_prefix {
ansi_strings.push(painted_prefix.clone());
}
-
- if !text.is_empty() {
- &text[1..]
- } else {
- &text
- }
- };
+ }
if !text.is_empty() {
- ansi_strings.push(section_style.paint(text));
+ ansi_strings.push(section_style.paint(text.as_str()));
}
handled_prefix = true;
}
@@ -656,13 +640,8 @@ impl<'p> Painter<'p> {
Painter::should_compute_syntax_highlighting(state, config),
) {
(Some(highlighter), true) => {
- // The first character is a space injected by delta. See comment in
- // Painter:::prepare.
for (line, _) in lines.iter() {
- let mut this_line_sections =
- highlighter.highlight(&line[1..], &config.syntax_set);
- this_line_sections.insert(0, (config.null_syntect_style, &line[..1]));
- line_sections.push(this_line_sections);
+ line_sections.push(highlighter.highlight(line, &config.syntax_set));
}
}
_ => {
@@ -774,16 +753,14 @@ fn style_sections_contain_more_than_one_style(sections: &[(Style, &str)]) -> boo
}
/// True iff the line represented by `sections` constitutes a whitespace error.
-// Note that a space is always present as the first character in the line (it was put there as a
-// replacement for the leading +/- marker; see paint::prepare()). A line is a whitespace error iff,
-// beyond the initial space character, (a) there are more characters and (b) they are all
-// whitespace characters.
-// TODO: Git recognizes blank lines at end of file (blank-at-eof) as a whitespace error but delta
-// does not yet.
+// A line is a whitespace error iff it is non-empty and contains only whitespace
+// characters.
+// TODO: Git recognizes blank lines at end of file (blank-at-eof)
+// as a whitespace error but delta does not yet.
// https://git-scm.com/docs/git-config#Documentation/git-config.txt-corewhitespace
fn is_whitespace_error(sections: &[(Style, &str)]) -> bool {
let mut any_chars = false;
- for c in sections.iter().flat_map(|(_, s)| s.chars()).skip(1) {
+ for c in sections.iter().flat_map(|(_, s)| s.chars()) {
if c == '\n' {
return any_chars;
} else if c != ' ' && c != '\t' {
diff --git a/src/tests/ansi_test_utils.rs b/src/tests/ansi_test_utils.rs
index 3f4fbe96..e63f0ea1 100644
--- a/src/tests/ansi_test_utils.rs
+++ b/src/tests/ansi_test_utils.rs
@@ -129,7 +129,7 @@ pub mod ansi_test_utils {
};
painter.set_syntax(Some(language_extension));
painter.set_highlighter();
- let lines = vec![(format!(" {}", line), state.clone())];
+ let lines = vec![(line.to_string(), state.clone())];
let syntax_style_sections = paint::Painter::get_syntax_style_sections_for_lines(
&lines,
&state,
diff --git a/src/tests/test_example_diffs.rs b/src/tests/test_example_diffs.rs
index d60067b6..dda5bcf6 100644
--- a/src/tests/test_example_diffs.rs
+++ b/src/tests/test_example_diffs.rs
@@ -972,11 +972,10 @@ src/align.rs
if args.contains(&"--max-line-length") {
return;
}
- for n in 0..input_lines.len() {
- let input_line = input_lines[n];
+ for (n, input_line) in input_lines.into_iter().enumerate() {
// If config.line_numbers is enabled,
// we should remove line_numbers decoration while checking.
- let output_line = if config.line_numbers && n > 11 && n < input_lines.len() {
+ let output_line = if config.line_numbers && n > 11 {
&output_lines[n][14..]
} else {
output_lines[n]
@@ -1532,7 +1531,7 @@ src/align.rs:71: impl<'a> Alignment<'a> { │
}
#[test]
- fn test_color_only() {
+ fn test_color_only_mode() {
let config = integration_test_utils::make_config_from_args(&["--color-only"]);
let output = integration_test_utils::run_delta(GIT_DIFF_SINGLE_HUNK, &config);
ansi_test_utils::assert_line_has_syntax_highlighted_substring(
diff --git a/src/wrapping.rs b/src/wrapping.rs
index d4fd851a..5dc44701 100644
--- a/src/wrapping.rs
+++ b/src/wrapping.rs
@@ -29,6 +29,12 @@ pub struct WrapConfig {
pub inline_hint_syntect_style: SyntectStyle,
}
+#[derive(PartialEq)]
+enum Stop {
+ StackEmpty,
+ LineLimit,
+}
+
/// Wrap the given `line` if it is longer than `line_width`. Wrap to at most
/// [Config::WrapConfig::max_lines](WrapConfig::max_lines) lines,
/// then truncate again - but never truncate if it is `0`. Place
@@ -40,9 +46,6 @@ pub struct WrapConfig {
/// on the next line [right_prefix_symbol](WrapConfig::right_prefix_symbol).
/// The inserted characters will follow the
/// [inline_hint_syntect_style](WrapConfig::inline_hint_syntect_style).
-///
-/// The input `line` is expected to start with an (ultimately not printed) `+`, `-` or ` ` prefix.
-/// The prefix `_` is also added to the start of wrapped lines.
pub fn wrap_line<'a, I, S>(
config: &'a Config,
line: I,
@@ -59,18 +62,6 @@ where
let wrap_config = &config.wrap_config;
- // Symbol which:
- // - represents the additional "+/-/ " prefix on the unwrapped input line, its
- // length is added to the line_width.
- // - can be more prominent than a space because syntax highlighting has already
- // been done.
- // - is added at the beginning of wrapped lines so the wrapped lines also have
- // a prefix (which is not printed).
- const LINEPREFIX: &str = "_";
- assert_eq!(LINEPREFIX.len(), INLINE_SYMBOL_WIDTH_1); // (args are const, optimized out)
-
- let max_len = line_width + LINEPREFIX.len();
-
// The current line being assembled from the input to fit exactly into the given width.
// A somewhat leaky abstraction as the fields are also accessed directly.
struct CurrLine<'a, S: Default> {
@@ -80,8 +71,8 @@ where
impl<'a, S: Default> CurrLine<'a, S> {
fn reset() -> Self {
CurrLine {
- line_segments: vec![(S::default(), LINEPREFIX)],
- len: LINEPREFIX.len(),
+ line_segments: Vec::new(),
+ len: 0,
}
}
fn push_and_set_len(&mut self, text: (S, &'a str), len: usize) {
@@ -89,24 +80,14 @@ where
self.len = len;
}
fn has_text(&self) -> bool {
- self.len > LINEPREFIX.len()
+ self.len > 0
}
fn text_len(&self) -> usize {
- if self.len > LINEPREFIX.len() {
- self.len - LINEPREFIX.len()
- } else {
- debug_assert!(false, "push or reset first");
- 0
- }
+ self.len
}
}
- // The first `push_and_set_len` will include the "+/-/ " prefix, subsequent
- // `reset()` add `LINEPREFIX`. Thus each line starts with a prefix.
- let mut curr_line: CurrLine<S> = CurrLine {
- line_segments: Vec::new(),
- len: 0,
- };
+ let mut curr_line = CurrLine::reset();
// Determine the background (diff) and color (syntax) of an inserted symbol.
let symbol_style = match inline_hint_style {
@@ -116,18 +97,22 @@ where
let mut stack = line.into_iter().rev().collect::<Vec<_>>();
- let line_limit_reached = |result: &Vec<_>| {
- // If only the wrap symbol and no extra text fits, then wrapping is not possible.
- let max_lines = if line_width <= INLINE_SYMBOL_WIDTH_1 {
- 1
- } else {
- wrap_config.max_lines
- };
-
- max_lines > 0 && result.len() + 1 >= max_lines
+ // If only the wrap symbol and no extra text fits, then wrapping is not possible.
+ let max_lines = if line_width <= INLINE_SYMBOL_WIDTH_1 {
+ 1
+ } else {
+ wrap_config.max_lines
};
- while !stack.is_empty() && !line_limit_reached(&result) && max_len > LINEPREFIX.len() {
+ let line_limit_reached = |result: &Vec<_>| max_lines > 0 && result.len() + 1 >= max_lines;
+
+ let stop = loop {
+ if stack.is_empty() {
+ break Stop::StackEmpty;
+ } else if line_limit_reached(&result) {
+ break Stop::LineLimit;
+ }
+
let (style, text, graphemes) = stack
.pop()
.map(|(style, text)| (style, text, text.grapheme_indices(true).collect::<Vec<_>>()))
@@ -135,10 +120,10 @@ where
let new_len = curr_line.len + graphemes.len();
- let must_split = if new_len < max_len {
+ let must_split = if new_len < line_width {
curr_line.push_and_set_len((style, text), new_len);
false
- } else if new_len == max_len {
+ } else if new_len == line_width {
match stack.last() {
// Perfect fit, no need to make space for a `wrap_symbol`.
None => {
@@ -156,7 +141,7 @@ where
}
_ => true,
}
- } else if new_len == max_len + 1 && stack.is_empty() {
+ } else if new_len == line_width + 1 && stack.is_empty() {
// If the one overhanging char is '\n' then keep it on the current line.
if text.ends_with('\n') {
// Do not count the included '\n': - 1
@@ -172,7 +157,7 @@ where
// Text must be split, one part (or just `wrap_symbol`) is added to the
// current line, the other is pushed onto the stack.
if must_split {
- let grapheme_split_pos = graphemes.len() - (new_len - max_len) - 1;
+ let grapheme_split_pos = graphemes.len() - (new_len - line_width) - 1;
// The length does not matter anymore and `curr_line` will be reset
// at the end, so move the line segments out.
@@ -193,18 +178,17 @@ where
curr_line = CurrLine::reset();
}
- }
+ };
// Right-align wrapped line:
// Done if wrapping adds exactly one line and this line is less than the given
// permille wide. Also change the wrap symbol at the end of the previous (first) line.
if result.len() == 1 && curr_line.has_text() {
- let current_permille = (curr_line.text_len() * 1000) / max_len;
+ let current_permille = (curr_line.text_len() * 1000) / line_width;
- let pad_len = max_len.saturating_sub(curr_line.text_len() + INLINE_SYMBOL_WIDTH_1);
+ let pad_len = line_width.saturating_sub(curr_line.text_len());
- if wrap_config.use_wrap_right_permille > current_permille && pad_len > INLINE_SYMBOL_WIDTH_1
- {
+ if wrap_config.use_wrap_right_permille > current_permille && pad_len > 0 {
// The inserted spaces, which align a line to the right, point into this string.
const SPACES: &str = " ";
@@ -215,7 +199,7 @@ where
_ => unreachable!("wrap result must not be empty"),
}
- let mut right_aligned_line = vec![(S::default(), LINEPREFIX)];
+ let mut right_aligned_line = Vec::new();
for _ in 0..(pad_len / SPACES.len()) {
right_aligned_line.push((*fill_style, SPACES));
@@ -228,19 +212,22 @@ where
right_aligned_line.push((symbol_style, &wrap_config.right_prefix_symbol));
- // skip LINEPREFIX which `CurrLine::reset()` adds
- right_aligned_line.extend(curr_line.line_segments.into_iter().skip(1));
+ right_aligned_line.extend(curr_line.line_segments.into_iter());
curr_line.line_segments = right_aligned_line;
- // curr_line.len not updated, as only 0 / 1 / > 1 is required now
+ // curr_line.len not updated, as only 0 / >0 for `has_text()` is required.
}
}
- if curr_line.len > 0 {
+ if curr_line.has_text() {
result.push(curr_line.line_segments);
}
+ if stop == Stop::LineLimit && result.len() != max_lines {
+ result.push(Vec::new());
+ }
+
// Anything that is left will be added to the (last) line. If this is too long it will
// be truncated later.
if !stack.is_empty() {
@@ -641,60 +628,83 @@ mod tests {
let cfg = mk_wrap_cfg(&TEST_WRAP_CFG);
{
- // Empty input without a "+/-/ "-prefix usually does not happen
- let line = vec![(*S1, "")];
+ let line = vec![(*SY, "0")];
let lines = wrap_test(&cfg, line, 6);
- assert!(lines.is_empty());
+ assert_eq!(lines, vec![vec![(*SY, "0")]]);
}
-
{
- let line = vec![(*SY, "_0")];
+ let line = vec![(*S1, "012"), (*S2, "34")];
let lines = wrap_test(&cfg, line, 6);
- assert_eq!(lines, vec![vec![(*SY, "_0")]]);
+ assert_eq!(lines, vec![vec![(*S1, "012"), (*S2, "34")]]);
}
-
{
- let line = vec![(*S1, "_")];
+ let line = vec![(*S1, "012"), (*S2, "345")];
let lines = wrap_test(&cfg, line, 6);
- assert_eq!(lines, vec![vec![(*S1, "_")]]);
+ assert_eq!(lines, vec![vec![(*S1, "012"), (*S2, "345")]]);
+ }
+ {
+ // Empty input usually does not happen
+ let line = vec![(*S1, "")];
+ let lines = wrap_test(&cfg, line, 6);
+ assert!(lines.is_empty());
}
-
{
- let line = vec![(*S1, "_"), (*S2, "0")];
+ // Partially empty should not happen either
+ let line = vec![(*S1, ""), (*S2, "0")];
let lines = wrap_test(&cfg, line, 6);
- assert_eq!(lines, vec![vec![(*S1, "_"), (*S2, "0")]]);
+ assert_eq!(lines, vec![vec![(*S1, ""), (*S2, "0")]]);
}
-
{
- let line = vec![(*S1, "_012"), (*S2, "34")];
+ let line = vec![(*S1, "0"), (*S2, "")];
let lines = wrap_test(&cfg, line, 6);
- assert_eq!(lines, vec![vec![(*S1, "_012"), (*S2, "34")]]);
+ assert_eq!(lines, vec![vec![(*S1, "0"), (*S2, "")]]);
}
-
{
- let line = vec![(*S1, "_012"), (*S2, "345")];
+ let line = vec![
+ (*S1, "0"),
+ (*S2, ""),
+ (*S1, ""),
+ (*S2, ""),
+ (*S1, ""),
+ (*S2, ""),
+ (*S1, ""),
+ (*S2, ""),
+ (*S1, ""),
+ (*S2, ""),
+ ];
let lines = wrap_test(&cfg, line, 6);
- assert_eq!(lines, vec![vec![(*S1, "_012"), (*S2, "345")]]);
+ assert_eq!(
+ lines,
+ vec![vec![
+ (*S1, "0"),
+ (*S2, ""),
+ (*S1, ""),
+ (*S2, ""),
+ (*S1, ""),
+ (*S2, ""),
+ (*S1, ""),
+ (*S2, ""),
+ (*S1, ""),
+ (*S2, "")
+ ]]
+ );
}
}
#[test]
- fn test_wrap_line_align_right() {
+ fn test_wrap_line_align_right_1() {
let cfg = mk_wrap_cfg(&TEST_WRAP_CFG);
- let line = vec![(*S1, "_0123456789ab")];
+ let line = vec![(*S1, "0123456789ab")];
let lines = wrap_test(&cfg, line, 11);
assert_eq!(lines.len(), 2);
assert_eq!(lines[0].last().unwrap().1, WR);
- assert_eq!(
- lines[1],
- vec![(*SD, "_"), (*SD, " "), (*SD, ">"), (*S1, "ab")]
- );
+ assert_eq!(lines[1], [(*SD, " "), (*SD, ">"), (*S1, "ab")]);
}
#[test]
fn test_wrap_line_align_right_2() {
- let line = vec![(*S1, "_012"), (*S2, "3456")];
+ let line = vec![(*S1, "012"), (*S2, "3456")];
{
// Right align lines on the second line
@@ -704,8 +714,8 @@ mod tests {
assert_eq!(
lines,
vec![
- vec![(*S1, "_012"), (*S2, "34"), (*SD, WR)],
- vec![(*SD, "_"), (*SD, " "), (*SD, RA), (*S2, "56")]
+ vec![(*S1, "012"), (*S2, "34"), (*SD, WR)],
+ vec![(*SD, " "), (*SD, RA), (*S2, "56")]
]
);
}
@@ -719,10 +729,7 @@ mod tests {
let lines = wrap_test(&cfg_no_align_right, line, 6);
assert_eq!(
lines,
- vec![
- vec![(*S1, "_012"), (*S2, "34"), (*SD, W)],
- vec![(*SD, "_"), (*S2, "56")]
- ]
+ vec![vec![(*S1, "012"), (*S2, "34"), (*SD, W)], vec![(*S2, "56")]]
);
}
}
@@ -730,7 +737,7 @@ mod tests {
#[test]
fn test_wrap_line_newlines<'a>() {
fn mk_input(len: usize) -> LineSegments<'static, Style> {
- const IN: &str = "_0123456789abcdefZ";
+ const IN: &str = "0123456789abcdefZ";
let v = &[*S1, *S2];
let s1s2 = v.iter().cycle();
let text: Vec<_> = IN.matches(|_| true).take(len + 1).collect();
@@ -745,7 +752,6 @@ mod tests {
line
}
fn mk_expected<'a>(
- prepend: Option<(Style, &'a str)>,
vec: &LineSegments<'a, Style>,
from: usize,
to: usize,
@@ -755,22 +761,19 @@ mod tests {
if let Some(val) = append {
result.push(val);
}
- if let Some(val) = prepend {
- result.insert(0, val);
- }
result
}
let cfg = mk_wrap_cfg(&TEST_WRAP_CFG);
{
- let line = vec![(*S1, "_012"), (*S2, "345\n")];
+ let line = vec![(*S1, "012"), (*S2, "345\n")];
let lines = wrap_test(&cfg, line, 6);
- assert_eq!(lines, vec![vec![(*S1, "_012"), (*S2, "345\n")]]);
+ assert_eq!(lines, vec![vec![(*S1, "012"), (*S2, "345\n")]]);
}
{
- for i in 0..=6 {
+ for i in 0..=5 {
let line = mk_input(i);
let lines = wrap_test(&cfg, line, 6);
assert_eq!(lines, vec![mk_input(i)]);
@@ -785,27 +788,28 @@ mod tests {
let line = mk_input_nl(9);
let lines = wrap_test(&cfg, line, 3);
let expected = mk_input_nl(9);
- let line1 = mk_expected(None, &expected, 0, 3, Some((*SD, &W)));
- let line2 = mk_expected(Some((*SD, "_")), &expected, 3, 5