yazi_shared/
chars.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use core::str;
use std::borrow::Cow;

pub const MIME_DIR: &str = "inode/directory";

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum CharKind {
	Space,
	Punct,
	Other,
}

impl CharKind {
	pub fn new(c: char) -> Self {
		if c.is_whitespace() {
			Self::Space
		} else if c.is_ascii_punctuation() {
			Self::Punct
		} else {
			Self::Other
		}
	}

	pub fn vary(self, other: Self, far: bool) -> bool {
		if far { (self == Self::Space) != (other == Self::Space) } else { self != other }
	}
}

pub fn strip_trailing_newline(mut s: String) -> String {
	while s.ends_with('\n') || s.ends_with('\r') {
		s.pop();
	}
	s
}

pub fn replace_cow<'a>(s: &'a str, from: &str, to: &str) -> Cow<'a, str> {
	replace_cow_impl(s, s.match_indices(from), to)
}

pub fn replacen_cow<'a>(s: &'a str, from: &str, to: &str, n: usize) -> Cow<'a, str> {
	replace_cow_impl(s, s.match_indices(from).take(n), to)
}

fn replace_cow_impl<'s>(
	src: &'s str,
	mut indices: impl Iterator<Item = (usize, &'s str)>,
	to: &str,
) -> Cow<'s, str> {
	let Some((first_idx, first_sub)) = indices.next() else {
		return Cow::Borrowed(src);
	};

	let mut result = Cow::Owned(String::with_capacity(src.len()));
	result += unsafe { src.get_unchecked(..first_idx) };
	result.to_mut().push_str(to);

	let mut last = first_idx + first_sub.len();
	for (idx, sub) in indices {
		result += unsafe { src.get_unchecked(last..idx) };
		result.to_mut().push_str(to);
		last = idx + sub.len();
	}

	result + unsafe { src.get_unchecked(last..) }
}

pub fn replace_vec_cow<'a>(v: &'a [u8], from: &[u8], to: &[u8]) -> Cow<'a, [u8]> {
	let mut it = memchr::memmem::find_iter(v, from);
	let Some(mut last) = it.next() else { return Cow::Borrowed(v) };

	let mut out = Vec::with_capacity(v.len());
	out.extend_from_slice(&v[..last]);
	out.extend_from_slice(to);
	last += from.len();

	for idx in it {
		out.extend_from_slice(&v[last..idx]);
		out.extend_from_slice(to);
		last = idx + from.len();
	}

	out.extend_from_slice(&v[last..]);
	Cow::Owned(out)
}

pub fn replace_to_printable(s: &[String], tab_size: u8) -> String {
	let mut buf = Vec::new();
	buf.try_reserve_exact(s.iter().map(|s| s.len()).sum::<usize>() | 15).unwrap_or_else(|_| panic!());

	for &b in s.iter().flat_map(|s| s.as_bytes()) {
		match b {
			b'\n' => buf.push(b'\n'),
			b'\t' => {
				buf.extend((0..tab_size).map(|_| b' '));
			}
			b'\0'..=b'\x1F' => {
				buf.push(b'^');
				buf.push(b + b'@');
			}
			0x7f => {
				buf.push(b'^');
				buf.push(b'?');
			}
			_ => buf.push(b),
		}
	}
	unsafe { String::from_utf8_unchecked(buf) }
}