annotate rust/hg-core/src/utils/strings.rs @ 53042:cdd7bf612c7b stable tip

bundle-spec: properly format boolean parameter (issue6960) This was breaking automatic clone bundle generation. This changeset fixes it and add a test to catch it in the future.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Tue, 11 Mar 2025 02:29:42 +0100
parents 874c64e041b5
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
52760
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
1 //! Contains string-related utilities.
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
2
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
3 use crate::utils::hg_path::HgPath;
52969
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
4 use lazy_static::lazy_static;
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
5 use regex::bytes::Regex;
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
6 use std::{borrow::Cow, cell::Cell, fmt, io::Write as _, ops::Deref as _};
52760
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
7
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
8 /// Useful until rust/issues/56345 is stable
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
9 ///
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
10 /// # Examples
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
11 ///
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
12 /// ```
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
13 /// use hg::utils::strings::find_slice_in_slice;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
14 ///
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
15 /// let haystack = b"This is the haystack".to_vec();
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
16 /// assert_eq!(find_slice_in_slice(&haystack, b"the"), Some(8));
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
17 /// assert_eq!(find_slice_in_slice(&haystack, b"not here"), None);
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
18 /// ```
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
19 pub fn find_slice_in_slice<T>(slice: &[T], needle: &[T]) -> Option<usize>
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
20 where
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
21 for<'a> &'a [T]: PartialEq,
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
22 {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
23 slice
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
24 .windows(needle.len())
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
25 .position(|window| window == needle)
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
26 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
27
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
28 /// Replaces the `from` slice with the `to` slice inside the `buf` slice.
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
29 ///
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
30 /// # Examples
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
31 ///
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
32 /// ```
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
33 /// use hg::utils::strings::replace_slice;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
34 /// let mut line = b"I hate writing tests!".to_vec();
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
35 /// replace_slice(&mut line, b"hate", b"love");
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
36 /// assert_eq!(
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
37 /// line,
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
38 /// b"I love writing tests!".to_vec()
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
39 /// );
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
40 /// ```
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
41 pub fn replace_slice<T>(buf: &mut [T], from: &[T], to: &[T])
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
42 where
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
43 T: Clone + PartialEq,
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
44 {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
45 if buf.len() < from.len() || from.len() != to.len() {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
46 return;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
47 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
48 for i in 0..=buf.len() - from.len() {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
49 if buf[i..].starts_with(from) {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
50 buf[i..(i + from.len())].clone_from_slice(to);
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
51 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
52 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
53 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
54
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
55 pub trait SliceExt {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
56 fn trim_end(&self) -> &Self;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
57 fn trim_start(&self) -> &Self;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
58 fn trim_end_matches(&self, f: impl FnMut(u8) -> bool) -> &Self;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
59 fn trim_start_matches(&self, f: impl FnMut(u8) -> bool) -> &Self;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
60 fn trim(&self) -> &Self;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
61 fn drop_prefix(&self, needle: &Self) -> Option<&Self>;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
62 fn split_2(&self, separator: u8) -> Option<(&[u8], &[u8])>;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
63 fn split_2_by_slice(&self, separator: &[u8]) -> Option<(&[u8], &[u8])>;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
64 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
65
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
66 impl SliceExt for [u8] {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
67 fn trim_end(&self) -> &[u8] {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
68 self.trim_end_matches(|byte| byte.is_ascii_whitespace())
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
69 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
70
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
71 fn trim_start(&self) -> &[u8] {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
72 self.trim_start_matches(|byte| byte.is_ascii_whitespace())
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
73 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
74
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
75 fn trim_end_matches(&self, mut f: impl FnMut(u8) -> bool) -> &Self {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
76 if let Some(last) = self.iter().rposition(|&byte| !f(byte)) {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
77 &self[..=last]
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
78 } else {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
79 &[]
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
80 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
81 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
82
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
83 fn trim_start_matches(&self, mut f: impl FnMut(u8) -> bool) -> &Self {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
84 if let Some(first) = self.iter().position(|&byte| !f(byte)) {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
85 &self[first..]
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
86 } else {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
87 &[]
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
88 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
89 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
90
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
91 /// ```
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
92 /// use hg::utils::strings::SliceExt;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
93 /// assert_eq!(
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
94 /// b" to trim ".trim(),
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
95 /// b"to trim"
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
96 /// );
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
97 /// assert_eq!(
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
98 /// b"to trim ".trim(),
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
99 /// b"to trim"
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
100 /// );
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
101 /// assert_eq!(
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
102 /// b" to trim".trim(),
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
103 /// b"to trim"
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
104 /// );
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
105 /// ```
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
106 fn trim(&self) -> &[u8] {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
107 self.trim_start().trim_end()
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
108 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
109
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
110 fn drop_prefix(&self, needle: &Self) -> Option<&Self> {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
111 if self.starts_with(needle) {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
112 Some(&self[needle.len()..])
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
113 } else {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
114 None
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
115 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
116 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
117
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
118 fn split_2(&self, separator: u8) -> Option<(&[u8], &[u8])> {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
119 let pos = memchr::memchr(separator, self)?;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
120 Some((&self[..pos], &self[pos + 1..]))
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
121 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
122
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
123 fn split_2_by_slice(&self, separator: &[u8]) -> Option<(&[u8], &[u8])> {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
124 find_slice_in_slice(self, separator)
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
125 .map(|pos| (&self[..pos], &self[pos + separator.len()..]))
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
126 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
127 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
128
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
129 pub trait Escaped {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
130 /// Return bytes escaped for display to the user
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
131 fn escaped_bytes(&self) -> Vec<u8>;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
132 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
133
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
134 impl Escaped for u8 {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
135 fn escaped_bytes(&self) -> Vec<u8> {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
136 let mut acc = vec![];
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
137 match self {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
138 c @ b'\'' | c @ b'\\' => {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
139 acc.push(b'\\');
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
140 acc.push(*c);
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
141 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
142 b'\t' => {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
143 acc.extend(br"\\t");
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
144 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
145 b'\n' => {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
146 acc.extend(br"\\n");
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
147 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
148 b'\r' => {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
149 acc.extend(br"\\r");
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
150 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
151 c if (*c < b' ' || *c >= 127) => {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
152 write!(acc, "\\x{:x}", self).unwrap();
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
153 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
154 c => {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
155 acc.push(*c);
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
156 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
157 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
158 acc
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
159 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
160 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
161
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
162 impl<'a, T: Escaped> Escaped for &'a [T] {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
163 fn escaped_bytes(&self) -> Vec<u8> {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
164 self.iter().flat_map(Escaped::escaped_bytes).collect()
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
165 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
166 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
167
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
168 impl<T: Escaped> Escaped for Vec<T> {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
169 fn escaped_bytes(&self) -> Vec<u8> {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
170 self.deref().escaped_bytes()
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
171 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
172 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
173
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
174 impl<'a> Escaped for &'a HgPath {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
175 fn escaped_bytes(&self) -> Vec<u8> {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
176 self.as_bytes().escaped_bytes()
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
177 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
178 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
179
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
180 #[cfg(unix)]
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
181 pub fn shell_quote(value: &[u8]) -> Vec<u8> {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
182 if value.iter().all(|&byte| {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
183 matches!(
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
184 byte,
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
185 b'a'..=b'z'
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
186 | b'A'..=b'Z'
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
187 | b'0'..=b'9'
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
188 | b'.'
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
189 | b'_'
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
190 | b'/'
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
191 | b'+'
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
192 | b'-'
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
193 )
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
194 }) {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
195 value.to_owned()
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
196 } else {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
197 let mut quoted = Vec::with_capacity(value.len() + 2);
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
198 quoted.push(b'\'');
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
199 for &byte in value {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
200 if byte == b'\'' {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
201 quoted.push(b'\\');
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
202 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
203 quoted.push(byte);
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
204 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
205 quoted.push(b'\'');
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
206 quoted
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
207 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
208 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
209
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
210 /// Expand `$FOO` and `${FOO}` environment variables in the given byte string
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
211 pub fn expand_vars(s: &[u8]) -> std::borrow::Cow<[u8]> {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
212 lazy_static::lazy_static! {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
213 /// https://github.com/python/cpython/blob/3.9/Lib/posixpath.py#L301
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
214 /// The `x` makes whitespace ignored.
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
215 /// `-u` disables the Unicode flag, which makes `\w` like Python with the ASCII flag.
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
216 static ref VAR_RE: regex::bytes::Regex =
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
217 regex::bytes::Regex::new(r"(?x-u)
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
218 \$
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
219 (?:
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
220 (\w+)
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
221 |
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
222 \{
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
223 ([^}]*)
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
224 \}
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
225 )
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
226 ").unwrap();
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
227 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
228 VAR_RE.replace_all(s, |captures: &regex::bytes::Captures| {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
229 let var_name = crate::utils::files::get_os_str_from_bytes(
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
230 captures
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
231 .get(1)
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
232 .or_else(|| captures.get(2))
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
233 .expect("either side of `|` must participate in match")
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
234 .as_bytes(),
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
235 );
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
236 std::env::var_os(var_name)
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
237 .map(crate::utils::files::get_bytes_from_os_str)
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
238 .unwrap_or_else(|| {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
239 // Referencing an environment variable that does not exist.
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
240 // Leave the $FOO reference as-is.
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
241 captures[0].to_owned()
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
242 })
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
243 })
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
244 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
245
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
246 /// Join items of the iterable with the given separator, similar to Python’s
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
247 /// `separator.join(iter)`.
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
248 ///
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
249 /// Formatting the return value consumes the iterator.
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
250 /// Formatting it again will produce an empty string.
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
251 pub fn join_display(
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
252 iter: impl IntoIterator<Item = impl fmt::Display>,
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
253 separator: impl fmt::Display,
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
254 ) -> impl fmt::Display {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
255 JoinDisplay {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
256 iter: Cell::new(Some(iter.into_iter())),
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
257 separator,
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
258 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
259 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
260
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
261 struct JoinDisplay<I, S> {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
262 iter: Cell<Option<I>>,
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
263 separator: S,
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
264 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
265
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
266 impl<I, T, S> fmt::Display for JoinDisplay<I, S>
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
267 where
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
268 I: Iterator<Item = T>,
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
269 T: fmt::Display,
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
270 S: fmt::Display,
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
271 {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
272 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
273 if let Some(mut iter) = self.iter.take() {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
274 if let Some(first) = iter.next() {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
275 first.fmt(f)?;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
276 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
277 for value in iter {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
278 self.separator.fmt(f)?;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
279 value.fmt(f)?;
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
280 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
281 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
282 Ok(())
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
283 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
284 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
285
52759
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
286 /// Returns a short representation of a user name or email address.
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
287 pub fn short_user(user: &[u8]) -> &[u8] {
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
288 let mut str = user;
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
289 if let Some(i) = memchr::memchr(b'@', str) {
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
290 str = &str[..i];
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
291 }
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
292 if let Some(i) = memchr::memchr(b'<', str) {
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
293 str = &str[i + 1..];
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
294 }
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
295 if let Some(i) = memchr::memchr(b' ', str) {
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
296 str = &str[..i];
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
297 }
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
298 if let Some(i) = memchr::memchr(b'.', str) {
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
299 str = &str[..i];
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
300 }
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
301 str
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
302 }
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
303
52969
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
304 /// Options for [`clean_whitespace`].
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
305 #[derive(Copy, Clone)]
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
306 pub enum CleanWhitespace {
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
307 /// Do nothing.
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
308 None,
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
309 /// Remove whitespace at ends of lines.
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
310 AtEol,
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
311 /// Collapse consecutive whitespace characters into a single space.
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
312 Collapse,
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
313 /// Remove all whitespace characters.
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
314 All,
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
315 }
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
316
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
317 /// Normalizes whitespace in text so that it won't apppear in diffs.
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
318 /// Returns `Cow::Borrowed(text)` if the result is unchanged.
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
319 pub fn clean_whitespace(text: &[u8], how: CleanWhitespace) -> Cow<[u8]> {
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
320 lazy_static! {
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
321 // To match wsclean in mdiff.py, this includes "\f".
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
322 static ref AT_EOL: Regex =
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
323 Regex::new(r"(?m)[ \t\r\f]+$").expect("valid regex");
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
324 // To match fixws in cext/bdiff.c, this does *not* include "\f".
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
325 static ref MULTIPLE: Regex =
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
326 Regex::new(r"[ \t\r]+").expect("valid regex");
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
327 }
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
328 let replacement: &[u8] = match how {
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
329 CleanWhitespace::None => return Cow::Borrowed(text),
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
330 CleanWhitespace::AtEol => return AT_EOL.replace_all(text, b""),
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
331 CleanWhitespace::Collapse => b" ",
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
332 CleanWhitespace::All => b"",
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
333 };
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
334 let text = MULTIPLE.replace_all(text, replacement);
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
335 replace_all_cow(&AT_EOL, text, b"")
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
336 }
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
337
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
338 /// Helper to call [`Regex::replace_all`] with `Cow` as input and output.
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
339 fn replace_all_cow<'a>(
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
340 regex: &Regex,
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
341 haystack: Cow<'a, [u8]>,
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
342 replacement: &[u8],
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
343 ) -> Cow<'a, [u8]> {
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
344 match haystack {
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
345 Cow::Borrowed(haystack) => regex.replace_all(haystack, replacement),
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
346 Cow::Owned(haystack) => {
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
347 Cow::Owned(regex.replace_all(&haystack, replacement).into_owned())
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
348 }
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
349 }
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
350 }
874c64e041b5 rhg-annotate: support whitespace options
Mitchell Kember <mkember@janestreet.com>
parents: 52760
diff changeset
351
52759
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
352 #[cfg(test)]
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
353 mod tests {
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
354 use super::*;
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
355
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
356 #[test]
52760
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
357 fn test_expand_vars() {
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
358 // Modifying process-global state in a test isn’t great,
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
359 // but hopefully this won’t collide with anything.
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
360 std::env::set_var("TEST_EXPAND_VAR", "1");
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
361 assert_eq!(
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
362 expand_vars(b"before/$TEST_EXPAND_VAR/after"),
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
363 &b"before/1/after"[..]
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
364 );
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
365 assert_eq!(
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
366 expand_vars(b"before${TEST_EXPAND_VAR}${TEST_EXPAND_VAR}${TEST_EXPAND_VAR}after"),
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
367 &b"before111after"[..]
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
368 );
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
369 let s = b"before $SOME_LONG_NAME_THAT_WE_ASSUME_IS_NOT_AN_ACTUAL_ENV_VAR after";
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
370 assert_eq!(expand_vars(s), &s[..]);
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
371 }
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
372
94e2547e6f3d rust: move code from utils to utils::strings
Mitchell Kember <mkember@janestreet.com>
parents: 52759
diff changeset
373 #[test]
52759
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
374 fn test_short_user() {
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
375 assert_eq!(short_user(b""), b"");
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
376 assert_eq!(short_user(b"Name"), b"Name");
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
377 assert_eq!(short_user(b"First Last"), b"First");
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
378 assert_eq!(short_user(b"First Last <user@example.com>"), b"user");
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
379 assert_eq!(short_user(b"First Last <user.name@example.com>"), b"user");
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
380 }
36d39726c0af rust: add utils::strings module
Mitchell Kember <mkember@janestreet.com>
parents:
diff changeset
381 }