Skip to content

Commit 08690f0

Browse files
committed
Fix unix build
1 parent da970ec commit 08690f0

3 files changed

Lines changed: 108 additions & 24 deletions

File tree

crates/edit/src/sys/unix.rs

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ use std::ptr::{NonNull, null_mut};
1515
use std::{io, thread, time};
1616

1717
use stdext::arena::{Arena, scratch_arena};
18-
use stdext::{arena_format, collections};
18+
use stdext::arena_format;
19+
use stdext::collections::{BString, BVec};
1920

2021
use crate::helpers::*;
2122

@@ -182,11 +183,11 @@ pub fn read_stdin(arena: &Arena, mut timeout: time::Duration) -> Option<BString<
182183
// later turn it into UTF8 using `from_utf8_lossy_owned`.
183184
// It is important that we allocate the buffer with an explicit capacity,
184185
// because we later use `spare_capacity_mut` to access it.
185-
buf.reserve(4 * KIBI);
186+
buf.reserve(arena, 4 * KIBI);
186187

187188
// We got some leftover broken UTF8 from a previous read? Prepend it.
188189
if STATE.utf8_len != 0 {
189-
buf.extend_from_slice(&STATE.utf8_buf[..STATE.utf8_len]);
190+
buf.extend_from_slice(arena, &STATE.utf8_buf[..STATE.utf8_len]);
190191
STATE.utf8_len = 0;
191192
}
192193

@@ -271,7 +272,7 @@ pub fn read_stdin(arena: &Arena, mut timeout: time::Duration) -> Option<BString<
271272
}
272273
}
273274

274-
let mut result = BString::from_utf8_lossy_owned(buf);
275+
let mut result = BString::from_utf8_lossy(arena, buf);
275276

276277
// We received a SIGWINCH? Add a fake window size sequence for our input parser.
277278
// I prepend it so that on startup, the TUI system gets first initialized with a size.
@@ -280,12 +281,11 @@ pub fn read_stdin(arena: &Arena, mut timeout: time::Duration) -> Option<BString<
280281
let (w, h) = get_window_size();
281282
if w > 0 && h > 0 {
282283
let scratch = scratch_arena(Some(arena));
283-
let seq = arena_format!(&scratch, "\x1b[8;{h};{w}t");
284-
result.replace_range(0..0, &seq);
284+
let seq = arena_format!(&*scratch, "\x1b[8;{h};{w}t");
285+
result.replace_range(arena, 0..0, &seq);
285286
}
286287
}
287288

288-
result.shrink_to_fit();
289289
Some(result)
290290
}
291291
}
@@ -435,7 +435,7 @@ pub fn icu_detect_renaming_suffix(arena: &Arena, handle: NonNull<c_void>) -> BSt
435435
unsafe {
436436
type T = *const c_void;
437437

438-
let mut res = BString::new_in(arena);
438+
let mut res = BString::empty();
439439

440440
// Check if the ICU library is using unversioned symbols.
441441
// Return an empty suffix in that case.
@@ -481,8 +481,8 @@ pub fn icu_detect_renaming_suffix(arena: &Arena, handle: NonNull<c_void>) -> BSt
481481
let version_end = version.find('.').unwrap_or(version.len());
482482
let version = &version[..version_end];
483483

484-
res.push('_');
485-
res.push_str(version);
484+
res.push(arena, '_');
485+
res.push_str(arena, version);
486486
res
487487
}
488488
}
@@ -506,29 +506,35 @@ where
506506
let name = unsafe { std::ffi::CStr::from_ptr(name) };
507507
let name = unsafe { name.to_str().unwrap_unchecked() };
508508

509-
let mut res = ManuallyDrop::new(BString::new_in(arena));
510-
res.reserve(name.len() + suffix.len() + 1);
511-
res.push_str(name);
512-
res.push_str(suffix);
513-
res.push('\0');
509+
let mut res = BString::empty();
510+
res.reserve(arena, name.len() + suffix.len() + 1);
511+
res.push_str(arena, name);
512+
res.push_str(arena, suffix);
513+
res.push(arena, '\0');
514514
res.as_ptr() as *const c_char
515515
}
516516
}
517517

518-
pub fn preferred_languages(arena: &Arena) -> Vec<BString<'_>, &Arena> {
518+
pub fn preferred_languages(arena: &Arena) -> BVec<'_, BString<'_>> {
519519
let mut locales = BVec::empty();
520520

521521
for key in ["LANGUAGE", "LC_ALL", "LANG"] {
522522
if let Ok(val) = std::env::var(key)
523523
&& !val.is_empty()
524524
{
525-
locales.extend(val.split(':').filter(|s| !s.is_empty()).map(|s| {
526-
// Replace all underscores with dashes,
527-
// because the localization code expects pt-br, not pt_BR.
528-
let mut res = BVec::empty();
529-
res.extend(s.as_bytes().iter().map(|&b| if b == b'_' { b'-' } else { b }));
530-
unsafe { BString::from_utf8_unchecked(res) }
531-
}));
525+
locales.extend_sloppy(
526+
arena,
527+
val.split(':').filter(|s| !s.is_empty()).map(|s| {
528+
// Replace all underscores with dashes,
529+
// because the localization code expects pt-br, not pt_BR.
530+
let mut res = BVec::empty();
531+
res.extend(
532+
arena,
533+
s.as_bytes().iter().map(|&b| if b == b'_' { b'-' } else { b }),
534+
);
535+
unsafe { BString::from_utf8_unchecked(res) }
536+
}),
537+
);
532538
break;
533539
}
534540
}

crates/stdext/src/collections/string.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use std::fmt::{self};
2-
use std::ops::{Deref, DerefMut};
2+
use std::ops::{Bound, Deref, DerefMut, RangeBounds};
33
use std::slice;
44
use std::str::Utf8Error;
55

66
use crate::alloc::Allocator;
7+
use crate::cold_path;
78
use crate::collections::BVec;
89

910
/// Like a `String` but on borrowed memory. Built on top of [`BVec<u8>`].
@@ -34,6 +35,38 @@ impl<'a> BString<'a> {
3435
Ok(Self { vec })
3536
}
3637

38+
/// Validates UTF-8, replacing invalid sequences with U+FFFD.
39+
pub fn from_utf8_lossy(alloc: &'a dyn Allocator, vec: BVec<'a, u8>) -> Self {
40+
let mut iter = vec.utf8_chunks();
41+
42+
if let Some(mut chunk) = iter.next()
43+
&& !chunk.invalid().is_empty()
44+
{
45+
// We only need to create a copy if the input is non-empty
46+
// and contains at least some invalid UTF-8.
47+
cold_path();
48+
49+
let mut res = Self::empty();
50+
res.reserve(alloc, vec.len());
51+
52+
loop {
53+
res.push_str(alloc, chunk.valid());
54+
if !chunk.invalid().is_empty() {
55+
res.push_str(alloc, "\u{FFFD}");
56+
}
57+
chunk = match iter.next() {
58+
Some(chunk) => chunk,
59+
None => break,
60+
};
61+
}
62+
63+
res
64+
} else {
65+
// Otherwise, we can just return the `vec` as-is.
66+
Self { vec }
67+
}
68+
}
69+
3770
/// Wraps a byte vec as UTF-8 without validating it.
3871
///
3972
/// # Safety
@@ -206,6 +239,26 @@ impl<'a> BString<'a> {
206239
iterator.for_each(move |c| self.push(alloc, c));
207240
}
208241

242+
/// Replaces a range of characters with a new string.
243+
pub fn replace_range<R: RangeBounds<usize>>(
244+
&mut self,
245+
alloc: &'a dyn Allocator,
246+
range: R,
247+
replace_with: &str,
248+
) {
249+
match range.start_bound() {
250+
Bound::Included(&n) => assert!(self.is_char_boundary(n)),
251+
Bound::Excluded(&n) => assert!(self.is_char_boundary(n + 1)),
252+
Bound::Unbounded => {}
253+
};
254+
match range.end_bound() {
255+
Bound::Included(&n) => assert!(self.is_char_boundary(n + 1)),
256+
Bound::Excluded(&n) => assert!(self.is_char_boundary(n)),
257+
Bound::Unbounded => {}
258+
};
259+
unsafe { self.as_mut_vec() }.replace_range(alloc, range, replace_with.as_bytes());
260+
}
261+
209262
/// Finds `old` in the string and replaces it with `new`.
210263
/// Only performs one replacement.
211264
pub fn replace_once_in_place(&mut self, alloc: &'a dyn Allocator, old: &str, new: &str) {

crates/stdext/src/collections/vec.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ impl<'a, T> BVec<'a, T> {
4343
}
4444
}
4545

46+
pub fn from_slice(slice: &'a mut [T]) -> Self {
47+
let slice = NonNull::from_mut(slice);
48+
Self {
49+
ptr: slice.cast(),
50+
len: slice.len(),
51+
cap: slice.len(),
52+
_marker: PhantomData,
53+
#[cfg(debug_assertions)]
54+
alloc: None,
55+
}
56+
}
57+
4658
/// Leaks a `Vec` and turns it into a "borrowed" `BVec`.
4759
pub fn from_std_vec(vec: Vec<T>) -> Self {
4860
let (ptr, len, cap) = vec.into_raw_parts();
@@ -112,6 +124,19 @@ impl<'a, T> BVec<'a, T> {
112124
self.len = new_len;
113125
}
114126

127+
/// Shortens the vector.
128+
pub fn truncate(&mut self, len: usize) {
129+
unsafe {
130+
// NOTE: It's intentional that this doesn't avoid drops when `len == self.len`,
131+
// because that would introduce a branch for the common case of `truncate(0)`.
132+
if let Some(r) = self.len.checked_sub(len) {
133+
let s = ptr::slice_from_raw_parts_mut(self.as_mut_ptr().add(len), r);
134+
self.len = len;
135+
ptr::drop_in_place(s);
136+
}
137+
}
138+
}
139+
115140
/// Raw pointer to the backing buffer.
116141
#[inline]
117142
pub fn as_ptr(&self) -> *const T {

0 commit comments

Comments
 (0)