From 69479aa1b9b71eef23da0d5f0faecc2be343f95a Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Wed, 19 Feb 2025 00:12:23 +0300 Subject: [PATCH] tabled/ Refactorings wrap --- tabled/src/settings/width/wrap.rs | 191 ++++++++++++++---------------- 1 file changed, 90 insertions(+), 101 deletions(-) diff --git a/tabled/src/settings/width/wrap.rs b/tabled/src/settings/width/wrap.rs index 13899009..60f26a8d 100644 --- a/tabled/src/settings/width/wrap.rs +++ b/tabled/src/settings/width/wrap.rs @@ -462,130 +462,94 @@ fn split_keeping_words(text: &str, width: usize, prefix: &str, suffix: &str) -> return String::new(); } - let stripped_text = ansi_str::AnsiStr::ansi_strip(text); - let mut word_width = 0; - let mut word_chars = 0; - let mut blocks = parsing::Blocks::new(ansi_str::get_blocks(text)); - let mut buf = parsing::MultilineBuffer::new(width); - buf.set_prefix(prefix); - buf.set_suffix(suffix); - - for c in stripped_text.chars() { - match c { - ' ' => { - parsing::handle_word(&mut buf, &mut blocks, word_chars, word_width, 1); - word_chars = 0; - word_width = 0; - } - '\n' => { - parsing::handle_word(&mut buf, &mut blocks, word_chars, word_width, 1); - word_chars = 0; - word_width = 0; - } - _ => { - word_width += std::cmp::max(1, get_char_width(c)); - word_chars += 1; - } - } - } - - if word_chars > 0 { - parsing::handle_word(&mut buf, &mut blocks, word_chars, word_width, 0); - buf.finish_line(&blocks); - } - - buf.into_string() + parsing::split_text(text, width, prefix, suffix) } #[cfg(feature = "ansi")] mod parsing { use super::get_char_width; - use ansi_str::{AnsiBlock, AnsiBlockIter, Style}; + use ansi_str::{get_blocks, AnsiBlock, AnsiBlockIter, Style}; use std::fmt::Write; - pub(super) struct Blocks<'a> { + struct TextBlocks<'a> { iter: AnsiBlockIter<'a>, current: Option>, } - impl<'a> Blocks<'a> { - pub(super) fn new(iter: AnsiBlockIter<'a>) -> Self { + impl<'a> TextBlocks<'a> { + fn new(text: &'a str) -> Self { Self { - iter, + iter: get_blocks(text), current: None, } } - pub(super) fn next_block(&mut self) -> Option> { + fn next(&mut self) -> Option> { self.current .take() .or_else(|| self.iter.next().map(RelativeBlock::new)) } } - pub(super) struct RelativeBlock<'a> { + struct RelativeBlock<'a> { block: AnsiBlock<'a>, pos: usize, } impl<'a> RelativeBlock<'a> { - pub(super) fn new(block: AnsiBlock<'a>) -> Self { + fn new(block: AnsiBlock<'a>) -> Self { Self { block, pos: 0 } } - pub(super) fn get_text(&self) -> &str { + fn get_text(&self) -> &str { &self.block.text()[self.pos..] } - pub(super) fn get_origin(&self) -> &str { + fn get_origin(&self) -> &str { self.block.text() } - pub(super) fn get_style(&self) -> &Style { + fn get_style(&self) -> &Style { self.block.style() } } - pub(super) struct MultilineBuffer<'a> { - pub buf: String, - pub width_last: usize, - pub width: usize, - pub prefix: &'a str, - pub suffix: &'a str, + struct MultilineBuffer<'text, 'color> { + buf: String, + width_last: usize, + width: usize, + prefix: &'color str, + suffix: &'color str, + blocks: TextBlocks<'text>, } - impl<'a> MultilineBuffer<'a> { - pub(super) fn new(width: usize) -> Self { + impl<'text, 'color> MultilineBuffer<'text, 'color> { + fn new(text: &'text str, width: usize, prefix: &'color str, suffix: &'color str) -> Self { + let blocks = TextBlocks::new(text); + Self { buf: String::new(), width_last: 0, - prefix: "", - suffix: "", + prefix, + suffix, width, + blocks, } } - pub(super) fn into_string(self) -> String { + fn into_string(self) -> String { self.buf } - pub(super) fn set_suffix(&mut self, suffix: &'a str) { - self.suffix = suffix; - } - - pub(super) fn set_prefix(&mut self, prefix: &'a str) { - self.prefix = prefix; - } - - pub(super) fn max_width(&self) -> usize { + fn max_width(&self) -> usize { self.width } - pub(super) fn available_width(&self) -> usize { + fn available_width(&self) -> usize { self.width - self.width_last } - pub(super) fn fill(&mut self, c: char) -> usize { + fn fill(&mut self, c: char) -> usize { debug_assert_eq!(get_char_width(c), 1); let rest_width = self.available_width(); @@ -596,8 +560,8 @@ mod parsing { rest_width } - pub(super) fn set_next_line(&mut self, blocks: &Blocks<'_>) { - if let Some(block) = &blocks.current { + fn set_next_line(&mut self) { + if let Some(block) = &self.blocks.current { let _ = self .buf .write_fmt(format_args!("{}", block.get_style().end())); @@ -611,15 +575,15 @@ mod parsing { self.buf.push_str(self.prefix); - if let Some(block) = &blocks.current { + if let Some(block) = &self.blocks.current { let _ = self .buf .write_fmt(format_args!("{}", block.get_style().start())); } } - pub(super) fn finish_line(&mut self, blocks: &Blocks<'_>) { - if let Some(block) = &blocks.current { + fn finish_line(&mut self) { + if let Some(block) = &self.blocks.current { let _ = self .buf .write_fmt(format_args!("{}", block.get_style().end())); @@ -631,7 +595,7 @@ mod parsing { self.width_last = 0; } - pub(super) fn read_chars(&mut self, block: &RelativeBlock<'_>, n: usize) -> (usize, usize) { + fn read_chars(&mut self, block: &RelativeBlock<'_>, n: usize) -> (usize, usize) { let mut count_chars = 0; let mut count_bytes = 0; for c in block.get_text().chars() { @@ -675,11 +639,7 @@ mod parsing { (count_chars, count_bytes) } - pub(super) fn read_chars_unchecked( - &mut self, - block: &RelativeBlock<'_>, - n: usize, - ) -> (usize, usize) { + fn read_chars_unchecked(&mut self, block: &RelativeBlock<'_>, n: usize) -> (usize, usize) { let mut count_chars = 0; let mut count_bytes = 0; for c in block.get_text().chars() { @@ -702,11 +662,12 @@ mod parsing { } } - pub(super) fn read_chars(buf: &mut MultilineBuffer<'_>, blocks: &mut Blocks<'_>, n: usize) { + fn read_chars(buf: &mut MultilineBuffer<'_, '_>, n: usize) { let mut n = n; while n > 0 { - let is_new_block = blocks.current.is_none(); - let mut block = blocks.next_block().expect("Must never happen"); + let is_new_block = buf.blocks.current.is_none(); + let mut block = buf.blocks.next().expect("Must never happen"); + if is_new_block { buf.buf.push_str(buf.prefix); let _ = buf @@ -722,22 +683,18 @@ mod parsing { .write_fmt(format_args!("{}", block.get_style().end())); } else { block.pos += read_bytes; - blocks.current = Some(block); + buf.blocks.current = Some(block); } n -= read_count; } } - pub(super) fn read_chars_unchecked( - buf: &mut MultilineBuffer<'_>, - blocks: &mut Blocks<'_>, - n: usize, - ) { + fn read_chars_unchecked(buf: &mut MultilineBuffer<'_, '_>, n: usize) { let mut n = n; while n > 0 { - let is_new_block = blocks.current.is_none(); - let mut block = blocks.next_block().expect("Must never happen"); + let is_new_block = buf.blocks.current.is_none(); + let mut block = buf.blocks.next().expect("Must never happen"); if is_new_block { buf.buf.push_str(buf.prefix); @@ -754,16 +711,15 @@ mod parsing { .write_fmt(format_args!("{}", block.get_style().end())); } else { block.pos += read_bytes; - blocks.current = Some(block); + buf.blocks.current = Some(block); } n -= read_count; } } - pub(super) fn handle_word( - buf: &mut MultilineBuffer<'_>, - blocks: &mut Blocks<'_>, + fn handle_word( + buf: &mut MultilineBuffer<'_, '_>, word_chars: usize, word_width: usize, additional_read: usize, @@ -773,17 +729,17 @@ mod parsing { let is_word_too_big = word_width > buf.max_width(); if is_word_too_big { - read_chars(buf, blocks, word_chars + additional_read); + read_chars(buf, word_chars + additional_read); } else if has_line_space { - read_chars_unchecked(buf, blocks, word_chars); + read_chars_unchecked(buf, word_chars); if additional_read > 0 { - read_chars(buf, blocks, additional_read); + read_chars(buf, additional_read); } } else { - buf.set_next_line(&*blocks); - read_chars_unchecked(buf, blocks, word_chars); + buf.set_next_line(); + read_chars_unchecked(buf, word_chars); if additional_read > 0 { - read_chars(buf, blocks, additional_read); + read_chars(buf, additional_read); } } @@ -792,12 +748,45 @@ mod parsing { let has_current_line_space = additional_read <= buf.available_width(); if has_current_line_space { - read_chars_unchecked(buf, blocks, additional_read); + read_chars_unchecked(buf, additional_read); } else { - buf.set_next_line(&*blocks); - read_chars_unchecked(buf, blocks, additional_read); + buf.set_next_line(); + read_chars_unchecked(buf, additional_read); } } + + pub(super) fn split_text(text: &str, width: usize, prefix: &str, suffix: &str) -> String { + let mut word_width = 0; + let mut word_chars = 0; + let mut buf = MultilineBuffer::new(text, width, prefix, suffix); + + let stripped_text = ansi_str::AnsiStr::ansi_strip(text); + for c in stripped_text.chars() { + match c { + ' ' => { + handle_word(&mut buf, word_chars, word_width, 1); + word_chars = 0; + word_width = 0; + } + '\n' => { + handle_word(&mut buf, word_chars, word_width, 1); + word_chars = 0; + word_width = 0; + } + _ => { + word_width += std::cmp::max(1, get_char_width(c)); + word_chars += 1; + } + } + } + + if word_chars > 0 { + handle_word(&mut buf, word_chars, word_width, 0); + buf.finish_line(); + } + + buf.into_string() + } } fn split_string_at(text: &str, at: usize) -> (&str, &str, (usize, usize)) {