// yt - A fully featured command line YouTube client // // Copyright (C) 2025 Benedikt Peetz // Copyright (C) 2025 uutils developers // SPDX-License-Identifier: MIT // // This file is part of Yt. // // You should have received a copy of the License along with this program. // If not, see . // This file is part of the uutils coreutils package. // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. use std::fmt::Write; use linebreak::break_lines; use parasplit::ParagraphStream; mod linebreak; mod parasplit; #[derive(Debug)] #[allow(clippy::struct_excessive_bools)] pub struct FmtOptions { /// First and second line of paragraph /// may have different indentations, in which /// case the first line's indentation is preserved, /// and each subsequent line's indentation matches the second line. pub crown_margin: bool, /// Like the [`crown_margin`], except that the first and second line of a paragraph *must* /// have different indentation or they are treated as separate paragraphs. pub tagged_paragraph: bool, /// Attempt to detect and preserve mail headers in the input. /// Be careful when combining this with [`prefix`]. pub mail: bool, /// Split lines only, do not reflow. pub split_only: bool, /// Insert exactly one space between words, and two between sentences. /// Sentence breaks in the input are detected as [?!.] followed by two spaces or a newline; /// other punctuation is not interpreted as a sentence break. pub uniform: bool, /// Reformat only lines beginning with PREFIX, reattaching PREFIX to reformatted lines. /// Unless [`exact_prefix`] is specified, leading whitespace will be ignored when matching PREFIX. pub prefix: Option, /// Do not reformat lines beginning with ``ANTI_PREFIX``. /// Unless [`exact_anti_prefix`] is specified, leading whitespace will be ignored when matching ``ANTI_PREFIX``. pub anti_prefix: Option, /// [`prefix`] must match at the beginning of the line with no preceding whitespace. pub exact_prefix: bool, /// [`anti_prefix`] must match at the beginning of the line with no preceding whitespace. pub exact_anti_prefix: bool, /// Fill output lines up to a maximum of WIDTH columns, default 75. pub width: usize, /// Goal width, default of 93% of WIDTH. /// Must be less than or equal to WIDTH. pub goal: usize, /// Break lines more quickly at the expense of a potentially more ragged appearance. pub quick: bool, /// Treat tabs as TABWIDTH spaces for determining line length, default 8. /// Note that this is used only for calculating line lengths; tabs are preserved in the output. pub tabwidth: usize, } impl FmtOptions { #[must_use] #[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_precision_loss)] pub fn new(width: Option, goal: Option, tabwidth: Option) -> Self { // by default, goal is 93% of width const DEFAULT_GOAL_TO_WIDTH_RATIO: f64 = 0.93; const DEFAULT_WIDTH: usize = 75; FmtOptions { crown_margin: false, tagged_paragraph: false, mail: false, split_only: false, uniform: false, prefix: None, anti_prefix: None, exact_prefix: false, exact_anti_prefix: false, width: width.unwrap_or(DEFAULT_WIDTH), goal: goal.unwrap_or( ((width.unwrap_or(DEFAULT_WIDTH) as f64) * DEFAULT_GOAL_TO_WIDTH_RATIO).floor() as usize, ), quick: false, tabwidth: tabwidth.unwrap_or(8), } } } /// Process text and format it according to the provided options. /// /// # Arguments /// /// * `text` - The text to process. /// * `fmt_opts` - A reference to a [`FmtOptions`] structure containing the formatting options. /// /// # Returns /// /// The formatted [`String`]. #[must_use] pub fn process_text(text: &str, fmt_opts: &FmtOptions) -> String { let mut output = String::new(); let p_stream = ParagraphStream::new(fmt_opts, text); for para_result in p_stream { match para_result { Err(s) => { output.push_str(&s); output.push('\n'); } Ok(para) => write!(output, "{}", break_lines(¶, fmt_opts)) .expect("This is in-memory. It should not fail"), } } output }