Repository: sxyazi/yazi
File: yazi-plugin/src/external/highlighter.rs (Rust)

Code before:
		line: &mut Vec<u8>,
		before: &mut Vec<String>,
		after: &mut Vec<String>,
	) -> bool {
		if line.is_empty() || lines_handled > skip + limit {
			return true;
		}

		if line.ends_with(b"\r\n") {
			line.pop();
			line.pop();
			line.push(b'\n');
		} else if !line.ends_with(b"\n") {
			line.push(b'\n')
		}

		let text = String::from_utf8_lossy(line).into_owned();
		if lines_handled > skip {
			after.push(text);
		} else if !plain {
			before.push(text);
		}
		false
	}

	fn chunk_by_width(line: Vec<u8>, width: usize) -> Vec<Vec<u8>> {
		if String::from_utf8_lossy(&line).width() <= width {
			return vec![line];
		}

		let mut resulted_lines = vec![];
		let mut buf_line = vec![];
		let mut buf_char = vec![];
		let mut last_break_char_idx = 0;
		let mut last_break_idx = 0;
		for (i, byte) in line.iter().enumerate() {
			let byte = *byte;

			buf_line.push(byte);
			buf_char.push(byte);

			if let Ok(char) = String::from_utf8(buf_char.clone()) {
				if ",.; ".contains(&char) {
					last_break_char_idx = i + 1
				}

				let buf_line_width = String::from_utf8_lossy(&buf_line).width();
				if buf_line_width < width {
					buf_char.clear();
					continue;
				}

Review comment (suggestion):
Please combine all instances of `String::from_utf8` and `String::from_utf8_lossy` in this function into a single one, as it is a time-consuming operation.

Code after:
			*c = b'\n';
		}
	}
}

impl Highlighter {
	pub fn to_line_widget(regions: Vec<(highlighting::Style, &str)>, indent: &str) -> Line<'static> {
		let spans: Vec<_> = regions
			.into_iter()
			.map(|(style, s)| {
				let mut modifier = ratatui::style::Modifier::empty();
				if style.font_style.contains(highlighting::FontStyle::BOLD) {
					modifier |= ratatui::style::Modifier::BOLD;
				}
				if style.font_style.contains(highlighting::FontStyle::ITALIC) {
					modifier |= ratatui::style::Modifier::ITALIC;
				}
				if style.font_style.contains(highlighting::FontStyle::UNDERLINE) {
					modifier |= ratatui::style::Modifier::UNDERLINED;
				}

				Span {
					content: s.replace('\t', indent).into(),
					style:   ratatui::style::Style {
						fg: Self::to_ansi_color(style.foreground),
						// bg: Self::to_ansi_color(style.background),
						add_modifier: modifier,
						..Default::default()
					},
				}
			})
			.collect();

		Line::from(spans)
	}

	// Copy from https://github.com/sharkdp/bat/blob/master/src/terminal.rs
	fn to_ansi_color(color: highlighting::Color) -> Option<ratatui::style::Color> {
		if color.a == 0 {
			// Themes can specify one of the user-configurable terminal colors by
			// encoding them as #RRGGBBAA with AA set to 00 (transparent) and RR set
			// to the 8-bit color palette number. The built-in themes ansi, base16,
			// and base16-256 use this.
			Some(match color.r {
				// For the first 8 colors, use the Color enum to produce ANSI escape
				// sequences using codes 30-37 (foreground) and 40-47 (background).
				// For example, red foreground is \x1b[31m. This works on terminals
				// without 256-color support.
				0x00 => ratatui::style::Color::Black,
				0x01 => ratatui::style::Color::Red,
				0x02 => ratatui::style::Color::Green,