refactor: move PUA-decoding function to widestring

These functions don't depend on `wcstringutil` functionality, so there
is no need for them to be there. The advantage of putting them into our
`widestring` crate is that quite a lot of code depends on it, and
extracting some of that code would result in crate dependency cycles if
the functions stayed in the `wcstringutil` crate. Our `widestring` crate
does not depend on any of our other crates, so there won't be any cyclic
dependency issues with code in it.

Part of #12625
This commit is contained in:
Daniel Rainer
2026-04-10 22:13:23 +02:00
committed by Johannes Altmanninger
parent b7b786aabf
commit 6a5b9bcde1
28 changed files with 259 additions and 252 deletions

View File

@@ -1,12 +1,7 @@
//! Helper functions for working with wcstring. //! Helper functions for working with wcstring.
use std::{
ffi::{CStr, CString, OsString},
os::unix::ffi::OsStringExt as _,
};
use fish_fallback::{fish_wcwidth, lowercase, lowercase_rev, wcscasecmp, wcscasecmp_fuzzy}; use fish_fallback::{fish_wcwidth, lowercase, lowercase_rev, wcscasecmp, wcscasecmp_fuzzy};
use fish_widestring::{ELLIPSIS_CHAR, decode_byte_from_char, prelude::*}; use fish_widestring::{ELLIPSIS_CHAR, prelude::*};
/// Return the number of newlines in a string. /// Return the number of newlines in a string.
pub fn count_newlines(s: &wstr) -> usize { pub fn count_newlines(s: &wstr) -> usize {
@@ -340,145 +335,6 @@ pub fn string_fuzzy_match_string(
StringFuzzyMatch::try_create(string, match_against, anchor_start) StringFuzzyMatch::try_create(string, match_against, anchor_start)
} }
/// Implementation of wcs2bytes that accepts a callback.
/// The first argument can be either a `&str` or `&wstr`.
/// This invokes `func` with byte slices containing the UTF-8 encoding of the characters in the
/// input, doing one invocation per character.
/// If `func` returns false, it stops; otherwise it continues.
/// Return false if the callback returned false, otherwise true.
pub fn str2bytes_callback(input: impl IntoCharIter, mut func: impl FnMut(&[u8]) -> bool) -> bool {
// A `char` represents an Unicode scalar value, which takes up at most 4 bytes when encoded in UTF-8.
let mut converted = [0_u8; 4];
for c in input.chars() {
let bytes = if let Some(byte) = decode_byte_from_char(c) {
converted[0] = byte;
&converted[..=0]
} else {
c.encode_utf8(&mut converted).as_bytes()
};
if !func(bytes) {
return false;
}
}
true
}
/// Returns a newly allocated multibyte character string equivalent of the specified wide character
/// string.
///
/// This function decodes illegal character sequences in a reversible way using the private use
/// area.
pub fn wcs2bytes(input: impl IntoCharIter) -> Vec<u8> {
let mut result = vec![];
wcs2bytes_appending(&mut result, input);
result
}
pub fn wcs2osstring(input: &wstr) -> OsString {
if input.is_empty() {
return OsString::new();
}
let mut result = vec![];
wcs2bytes_appending(&mut result, input);
OsString::from_vec(result)
}
/// Same as [`wcs2bytes`]. Meant to be used when we need a zero-terminated string to feed legacy APIs.
/// Note: if `input` contains any interior NUL bytes, the result will be truncated at the first!
pub fn wcs2zstring(input: &wstr) -> CString {
if input.is_empty() {
return CString::default();
}
let mut vec = Vec::with_capacity(input.len() + 1);
str2bytes_callback(input, |buff| {
vec.extend_from_slice(buff);
true
});
vec.push(b'\0');
match CString::from_vec_with_nul(vec) {
Ok(cstr) => cstr,
Err(err) => {
// `input` contained a NUL in the middle; we can retrieve `vec`, though
let mut vec = err.into_bytes();
let pos = vec.iter().position(|c| *c == b'\0').unwrap();
vec.truncate(pos + 1);
// Safety: We truncated after the first NUL
unsafe { CString::from_vec_with_nul_unchecked(vec) }
}
}
}
/// Like [`wcs2bytes`], but appends to `output` instead of returning a new string.
pub fn wcs2bytes_appending(output: &mut Vec<u8>, input: impl IntoCharIter) {
str2bytes_callback(input, |buff| {
output.extend_from_slice(buff);
true
});
}
/// A trait to make it more convenient to pass ascii/Unicode strings to functions that can take
/// non-Unicode values. The result is nul-terminated and can be passed to OS functions.
///
/// This is only implemented for owned types where an owned instance will skip allocations (e.g.
/// `CString` can return `self`) but not implemented for owned instances where a new allocation is
/// always required (e.g. implemented for `&wstr` but not `WideString`) because you might as well be
/// left with the original item if we're going to allocate from scratch in all cases.
pub trait ToCString {
/// Correctly convert to a nul-terminated [`CString`] that can be passed to OS functions.
fn to_cstring(self) -> CString;
}
impl ToCString for CString {
fn to_cstring(self) -> CString {
self
}
}
impl ToCString for &CStr {
fn to_cstring(self) -> CString {
self.to_owned()
}
}
/// Safely converts from `&wstr` to a `CString` to a nul-terminated `CString` that can be passed to
/// OS functions, taking into account non-Unicode values that have been shifted into the private-use
/// range by using [`wcs2zstring()`].
impl ToCString for &wstr {
/// The wide string may contain non-Unicode bytes mapped to the private-use Unicode range, so we
/// have to use [`wcs2zstring()`](self::wcs2zstring) to convert it correctly.
fn to_cstring(self) -> CString {
self::wcs2zstring(self)
}
}
/// Safely converts from `&WString` to a nul-terminated `CString` that can be passed to OS
/// functions, taking into account non-Unicode values that have been shifted into the private-use
/// range by using [`wcs2zstring()`].
impl ToCString for &WString {
fn to_cstring(self) -> CString {
self.as_utfstr().to_cstring()
}
}
/// Convert a (probably ascii) string to CString that can be passed to OS functions.
impl ToCString for Vec<u8> {
fn to_cstring(mut self) -> CString {
self.push(b'\0');
CString::from_vec_with_nul(self).unwrap()
}
}
/// Convert a (probably ascii) string to nul-terminated CString that can be passed to OS functions.
impl ToCString for &[u8] {
fn to_cstring(self) -> CString {
CString::new(self).unwrap()
}
}
/// Split a string by runs of any of the separator characters provided in `seps`. /// Split a string by runs of any of the separator characters provided in `seps`.
/// Note the delimiters are the characters in `seps`, not `seps` itself. /// Note the delimiters are the characters in `seps`, not `seps` itself.
/// `seps` may contain the NUL character. /// `seps` may contain the NUL character.

View File

@@ -6,7 +6,12 @@
pub mod word_char; pub mod word_char;
use std::{iter, slice}; use std::{
ffi::{CStr, CString, OsString},
iter,
os::unix::ffi::OsStringExt as _,
slice,
};
pub use widestring::{Utf32Str as wstr, Utf32String as WString, utf32str as L, utfstr::CharsUtf32}; pub use widestring::{Utf32Str as wstr, Utf32String as WString, utf32str as L, utfstr::CharsUtf32};
pub mod prelude { pub mod prelude {
@@ -44,6 +49,86 @@ pub fn encode_byte_to_char(byte: u8) -> char {
.expect("private-use codepoint should be valid char") .expect("private-use codepoint should be valid char")
} }
/// Returns a newly allocated multibyte character string equivalent of the specified wide character
/// string.
///
/// This function decodes illegal character sequences in a reversible way using the private use
/// area.
pub fn wcs2bytes(input: impl IntoCharIter) -> Vec<u8> {
let mut result = vec![];
wcs2bytes_appending(&mut result, input);
result
}
pub fn wcs2osstring(input: &wstr) -> OsString {
if input.is_empty() {
return OsString::new();
}
let mut result = vec![];
wcs2bytes_appending(&mut result, input);
OsString::from_vec(result)
}
/// Same as [`wcs2bytes`]. Meant to be used when we need a zero-terminated string to feed legacy APIs.
/// Note: if `input` contains any interior NUL bytes, the result will be truncated at the first!
pub fn wcs2zstring(input: &wstr) -> CString {
if input.is_empty() {
return CString::default();
}
let mut vec = Vec::with_capacity(input.len() + 1);
str2bytes_callback(input, |buff| {
vec.extend_from_slice(buff);
true
});
vec.push(b'\0');
match CString::from_vec_with_nul(vec) {
Ok(cstr) => cstr,
Err(err) => {
// `input` contained a NUL in the middle; we can retrieve `vec`, though
let mut vec = err.into_bytes();
let pos = vec.iter().position(|c| *c == b'\0').unwrap();
vec.truncate(pos + 1);
// Safety: We truncated after the first NUL
unsafe { CString::from_vec_with_nul_unchecked(vec) }
}
}
}
/// Like [`wcs2bytes`], but appends to `output` instead of returning a new string.
pub fn wcs2bytes_appending(output: &mut Vec<u8>, input: impl IntoCharIter) {
str2bytes_callback(input, |buff| {
output.extend_from_slice(buff);
true
});
}
/// Implementation of wcs2bytes that accepts a callback.
/// The first argument can be either a `&str` or `&wstr`.
/// This invokes `func` with byte slices containing the UTF-8 encoding of the characters in the
/// input, doing one invocation per character.
/// If `func` returns false, it stops; otherwise it continues.
/// Return false if the callback returned false, otherwise true.
pub fn str2bytes_callback(input: impl IntoCharIter, mut func: impl FnMut(&[u8]) -> bool) -> bool {
// A `char` represents an Unicode scalar value, which takes up at most 4 bytes when encoded in UTF-8.
let mut converted = [0_u8; 4];
for c in input.chars() {
let bytes = if let Some(byte) = decode_byte_from_char(c) {
converted[0] = byte;
&converted[..=0]
} else {
c.encode_utf8(&mut converted).as_bytes()
};
if !func(bytes) {
return false;
}
}
true
}
/// Decode a literal byte from a UTF-32 character. /// Decode a literal byte from a UTF-32 character.
pub fn decode_byte_from_char(c: char) -> Option<u8> { pub fn decode_byte_from_char(c: char) -> Option<u8> {
if c >= ENCODE_DIRECT_BASE && c < ENCODE_DIRECT_END { if c >= ENCODE_DIRECT_BASE && c < ENCODE_DIRECT_END {
@@ -57,6 +142,65 @@ pub fn decode_byte_from_char(c: char) -> Option<u8> {
} }
} }
/// A trait to make it more convenient to pass ascii/Unicode strings to functions that can take
/// non-Unicode values. The result is nul-terminated and can be passed to OS functions.
///
/// This is only implemented for owned types where an owned instance will skip allocations (e.g.
/// `CString` can return `self`) but not implemented for owned instances where a new allocation is
/// always required (e.g. implemented for `&wstr` but not `WideString`) because you might as well be
/// left with the original item if we're going to allocate from scratch in all cases.
pub trait ToCString {
/// Correctly convert to a nul-terminated [`CString`] that can be passed to OS functions.
fn to_cstring(self) -> CString;
}
impl ToCString for CString {
fn to_cstring(self) -> CString {
self
}
}
impl ToCString for &CStr {
fn to_cstring(self) -> CString {
self.to_owned()
}
}
/// Safely converts from `&wstr` to a `CString` to a nul-terminated `CString` that can be passed to
/// OS functions, taking into account non-Unicode values that have been shifted into the private-use
/// range by using [`wcs2zstring()`].
impl ToCString for &wstr {
/// The wide string may contain non-Unicode bytes mapped to the private-use Unicode range, so we
/// have to use [`wcs2zstring()`](self::wcs2zstring) to convert it correctly.
fn to_cstring(self) -> CString {
self::wcs2zstring(self)
}
}
/// Safely converts from `&WString` to a nul-terminated `CString` that can be passed to OS
/// functions, taking into account non-Unicode values that have been shifted into the private-use
/// range by using [`wcs2zstring()`].
impl ToCString for &WString {
fn to_cstring(self) -> CString {
self.as_utfstr().to_cstring()
}
}
/// Convert a (probably ascii) string to CString that can be passed to OS functions.
impl ToCString for Vec<u8> {
fn to_cstring(mut self) -> CString {
self.push(b'\0');
CString::from_vec_with_nul(self).unwrap()
}
}
/// Convert a (probably ascii) string to nul-terminated CString that can be passed to OS functions.
impl ToCString for &[u8] {
fn to_cstring(self) -> CString {
CString::new(self).unwrap()
}
}
mod decoder { mod decoder {
use crate::{ENCODE_DIRECT_BASE, ENCODE_DIRECT_END, char_offset, wstr}; use crate::{ENCODE_DIRECT_BASE, ENCODE_DIRECT_END, char_offset, wstr};
use buffer::Buffer; use buffer::Buffer;

View File

@@ -9,8 +9,7 @@
wutil::{FileId, INVALID_FILE_ID, file_id_for_path}, wutil::{FileId, INVALID_FILE_ID, file_id_for_path},
}; };
use fish_common::ScopeGuard; use fish_common::ScopeGuard;
use fish_wcstringutil::wcs2bytes; use fish_widestring::{L, WExt as _, WString, wcs2bytes, wstr};
use fish_widestring::{L, WExt as _, WString, wstr};
use lru::LruCache; use lru::LruCache;
use rust_embed::RustEmbed; use rust_embed::RustEmbed;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
@@ -467,7 +466,7 @@ mod tests {
fn test_autoload() { fn test_autoload() {
let _cleanup = test_init(); let _cleanup = test_init();
use crate::fds::wopen_cloexec; use crate::fds::wopen_cloexec;
use fish_wcstringutil::wcs2zstring; use fish_widestring::wcs2zstring;
use nix::fcntl::OFlag; use nix::fcntl::OFlag;
macro_rules! run { macro_rules! run {

View File

@@ -59,7 +59,7 @@
wutil::waccess, wutil::waccess,
}; };
use fish_common::save_term_foreground_process_group; use fish_common::save_term_foreground_process_group;
use fish_wcstringutil::wcs2bytes; use fish_widestring::wcs2bytes;
use libc::{STDERR_FILENO, STDIN_FILENO}; use libc::{STDERR_FILENO, STDIN_FILENO};
use nix::{ use nix::{
sys::resource::{UsageWho, getrusage}, sys::resource::{UsageWho, getrusage},

View File

@@ -24,8 +24,9 @@
}; };
use assert_matches::assert_matches; use assert_matches::assert_matches;
use fish_common::{ReadExt as _, UnescapeFlags, UnescapeStringStyle}; use fish_common::{ReadExt as _, UnescapeFlags, UnescapeStringStyle};
use fish_wcstringutil::{count_preceding_backslashes, wcs2bytes}; use fish_wcstringutil::count_preceding_backslashes;
use fish_wgetopt::{ArgType, WGetopter, WOption, wopt}; use fish_wgetopt::{ArgType, WGetopter, WOption, wopt};
use fish_widestring::wcs2bytes;
use std::{ use std::{
ffi::OsStr, ffi::OsStr,
fmt::Write as _, fmt::Write as _,

View File

@@ -14,7 +14,7 @@
use cfg_if::cfg_if; use cfg_if::cfg_if;
use fish_feature_flags::{self as features, feature_test}; use fish_feature_flags::{self as features, feature_test};
use fish_util::wcsfilecmp_glob; use fish_util::wcsfilecmp_glob;
use fish_wcstringutil::wcs2bytes; use fish_widestring::wcs2bytes;
use nix::unistd::AccessFlags; use nix::unistd::AccessFlags;
use rust_embed::RustEmbed; use rust_embed::RustEmbed;

View File

@@ -4,23 +4,24 @@
BRACE_BEGIN, BRACE_END, BRACE_SEP, BRACE_SPACE, HOME_DIRECTORY, INTERNAL_SEPARATOR, BRACE_BEGIN, BRACE_END, BRACE_SEP, BRACE_SPACE, HOME_DIRECTORY, INTERNAL_SEPARATOR,
PROCESS_EXPAND_SELF, PROCESS_EXPAND_SELF_STR, VARIABLE_EXPAND, VARIABLE_EXPAND_SINGLE, PROCESS_EXPAND_SELF, PROCESS_EXPAND_SELF_STR, VARIABLE_EXPAND, VARIABLE_EXPAND_SINGLE,
}; };
use crate::global_safety::AtomicRef; use crate::{
use crate::global_safety::RelaxedAtomicBool; global_safety::{AtomicRef, RelaxedAtomicBool},
use crate::prelude::*; prelude::*,
use crate::terminal::Outputter; terminal::Outputter,
use crate::termsize::Termsize; termsize::Termsize,
use crate::wildcard::{ANY_CHAR, ANY_STRING, ANY_STRING_RECURSIVE}; wildcard::{ANY_CHAR, ANY_STRING, ANY_STRING_RECURSIVE},
use crate::wutil::fish_iswalnum; wutil::fish_iswalnum,
};
use fish_fallback::fish_wcwidth; use fish_fallback::fish_wcwidth;
use fish_feature_flags::{FeatureFlag, feature_test}; use fish_feature_flags::{FeatureFlag, feature_test};
use fish_wcstringutil::wcs2bytes; use fish_widestring::{decode_byte_from_char, encode_byte_to_char, subslice_position, wcs2bytes};
use fish_widestring::{decode_byte_from_char, encode_byte_to_char, subslice_position};
use nix::sys::termios::Termios; use nix::sys::termios::Termios;
use std::env; use std::{
use std::ffi::{CStr, OsStr}; env,
use std::os::unix::prelude::*; ffi::{CStr, OsStr},
use std::sync::atomic::Ordering; os::unix::prelude::*,
use std::sync::{MutexGuard, OnceLock}; sync::{MutexGuard, OnceLock, atomic::Ordering},
};
use fish_common::*; use fish_common::*;

View File

@@ -13,7 +13,7 @@
use crate::reader::{commandline_get_state, reader_status_count}; use crate::reader::{commandline_get_state, reader_status_count};
use crate::threads::{is_forked_child, is_main_thread}; use crate::threads::{is_forked_child, is_main_thread};
use crate::wutil::fish_wcstol_radix; use crate::wutil::fish_wcstol_radix;
use fish_wcstringutil::wcs2zstring; use fish_widestring::wcs2zstring;
use nix::sys::stat::{Mode, umask}; use nix::sys::stat::{Mode, umask};
use std::cell::{RefCell, UnsafeCell}; use std::cell::{RefCell, UnsafeCell};
use std::collections::HashSet; use std::collections::HashSet;

4
src/env/mod.rs vendored
View File

@@ -4,7 +4,7 @@
pub mod var; pub mod var;
pub use environment::*; pub use environment::*;
use fish_wcstringutil::ToCString; use fish_widestring::ToCString;
use std::sync::{Mutex, atomic::AtomicUsize}; use std::sync::{Mutex, atomic::AtomicUsize};
pub use var::*; pub use var::*;
@@ -22,7 +22,7 @@
/// environment variables. /// environment variables.
/// ///
/// As values could contain non-unicode characters, they must first be converted from &wstr to a /// As values could contain non-unicode characters, they must first be converted from &wstr to a
/// `CString` with [`fish_wcstringutil::wcs2zstring()`]. /// `CString` with [`fish_widestring::wcs2zstring()`].
pub fn setenv_lock<S1: ToCString, S2: ToCString>(name: S1, value: S2, overwrite: bool) { pub fn setenv_lock<S1: ToCString, S2: ToCString>(name: S1, value: S2, overwrite: bool) {
let name = name.to_cstring(); let name = name.to_cstring();
let value = value.to_cstring(); let value = value.to_cstring();

View File

@@ -6,8 +6,8 @@
use crate::prelude::*; use crate::prelude::*;
use crate::wutil::{FileId, INVALID_FILE_ID, file_id_for_file, file_id_for_path_narrow, wrealpath}; use crate::wutil::{FileId, INVALID_FILE_ID, file_id_for_file, file_id_for_path_narrow, wrealpath};
use fish_common::{UnescapeFlags, UnescapeStringStyle}; use fish_common::{UnescapeFlags, UnescapeStringStyle};
use fish_wcstringutil::{LineIterator, join_strings, wcs2zstring}; use fish_wcstringutil::{LineIterator, join_strings};
use fish_widestring::decode_byte_from_char; use fish_widestring::{decode_byte_from_char, wcs2zstring};
use itertools::Itertools as _; use itertools::Itertools as _;
use std::collections::HashSet; use std::collections::HashSet;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
@@ -814,8 +814,7 @@ mod tests {
use crate::tests::prelude::*; use crate::tests::prelude::*;
use crate::wutil::{INVALID_FILE_ID, file_id_for_path}; use crate::wutil::{INVALID_FILE_ID, file_id_for_path};
use fish_tempfile::TempDir; use fish_tempfile::TempDir;
use fish_wcstringutil::wcs2osstring; use fish_widestring::{ENCODE_DIRECT_BASE, char_offset, wcs2osstring};
use fish_widestring::{ENCODE_DIRECT_BASE, char_offset};
const UVARS_PER_THREAD: usize = 8; const UVARS_PER_THREAD: usize = 8;

View File

@@ -45,8 +45,7 @@
use crate::wutil::{fish_wcstol, perror_io}; use crate::wutil::{fish_wcstol, perror_io};
use errno::{errno, set_errno}; use errno::{errno, set_errno};
use fish_common::{ScopeGuard, exit_without_destructors, truncate_at_nul, write_loop}; use fish_common::{ScopeGuard, exit_without_destructors, truncate_at_nul, write_loop};
use fish_wcstringutil::{wcs2bytes, wcs2zstring}; use fish_widestring::{ToWString as _, wcs2bytes, wcs2zstring};
use fish_widestring::ToWString as _;
use libc::{ use libc::{
EACCES, ENOENT, ENOEXEC, ENOTDIR, EPIPE, EXIT_FAILURE, EXIT_SUCCESS, STDERR_FILENO, EACCES, ENOENT, ENOEXEC, ENOTDIR, EPIPE, EXIT_FAILURE, EXIT_SUCCESS, STDERR_FILENO,
STDIN_FILENO, STDOUT_FILENO, STDIN_FILENO, STDOUT_FILENO,

View File

@@ -1,20 +1,20 @@
use crate::flog::flog; use crate::{flog::flog, prelude::*, signal::signal_check_cancel, wutil::perror_nix};
use crate::prelude::*;
use crate::signal::signal_check_cancel;
use crate::wutil::perror_nix;
use cfg_if::cfg_if; use cfg_if::cfg_if;
use fish_util::perror; use fish_util::perror;
use fish_wcstringutil::wcs2zstring; use fish_widestring::wcs2zstring;
use libc::{EINTR, F_GETFD, F_GETFL, F_SETFD, F_SETFL, FD_CLOEXEC, O_NONBLOCK, c_int}; use libc::{EINTR, F_GETFD, F_GETFL, F_SETFD, F_SETFL, FD_CLOEXEC, O_NONBLOCK, c_int};
use nix::fcntl::FcntlArg; use nix::fcntl::{FcntlArg, OFlag};
use nix::fcntl::OFlag; use std::{
use std::ffi::CStr; ffi::CStr,
use std::fs::File; fs::File,
use std::io; io,
use std::mem::ManuallyDrop; mem::ManuallyDrop,
use std::ops::{Deref, DerefMut}; ops::{Deref, DerefMut},
use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd}; os::{
use std::os::unix::prelude::*; fd::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd},
unix::prelude::*,
},
};
localizable_consts!( localizable_consts!(
pub PIPE_ERROR pub PIPE_ERROR

View File

@@ -2,7 +2,7 @@
use crate::wildcard::wildcard_match; use crate::wildcard::wildcard_match;
use crate::{parse_util::unescape_wildcards, wutil::unescape_bytes_and_write_to_fd}; use crate::{parse_util::unescape_wildcards, wutil::unescape_bytes_and_write_to_fd};
use fish_util::write_to_fd; use fish_util::write_to_fd;
use fish_wcstringutil::wcs2bytes; use fish_widestring::wcs2bytes;
use libc::c_int; use libc::c_int;
use std::sync::atomic::{AtomicI32, Ordering}; use std::sync::atomic::{AtomicI32, Ordering};

View File

@@ -7,7 +7,7 @@
wutil::{FileId, INVALID_FILE_ID, file_id_for_file, file_id_for_path, wdirname, wunlink}, wutil::{FileId, INVALID_FILE_ID, file_id_for_file, file_id_for_path, wdirname, wunlink},
}; };
use fish_tempfile::random_filename; use fish_tempfile::random_filename;
use fish_wcstringutil::{wcs2bytes, wcs2osstring}; use fish_widestring::{wcs2bytes, wcs2osstring};
use libc::{LOCK_EX, LOCK_SH, c_int}; use libc::{LOCK_EX, LOCK_SH, c_int};
use nix::{fcntl::OFlag, sys::stat::Mode}; use nix::{fcntl::OFlag, sys::stat::Mode};
use std::{ use std::{

View File

@@ -2,24 +2,28 @@
// autoloading functions in the $fish_function_path. Actual function evaluation is taken care of by // autoloading functions in the $fish_function_path. Actual function evaluation is taken care of by
// the parser and to some degree the builtin handling library. // the parser and to some degree the builtin handling library.
use crate::ast::{self, Node as _}; use crate::{
use crate::autoload::{Autoload, AutoloadResult}; ast::{self, Node as _},
use crate::common::{escape, valid_func_name}; autoload::{Autoload, AutoloadResult},
use crate::complete::complete_wrap_map; common::{escape, valid_func_name},
use crate::env::{EnvStack, Environment}; complete::complete_wrap_map,
use crate::event::{self, EventDescription}; env::{EnvStack, Environment},
use crate::global_safety::RelaxedAtomicBool; event::{self, EventDescription},
use crate::parse_tree::NodeRef; global_safety::RelaxedAtomicBool,
use crate::parser::Parser; parse_tree::NodeRef,
use crate::parser_keywords::parser_keywords_is_reserved; parser::Parser,
use crate::prelude::*; parser_keywords::parser_keywords_is_reserved,
use crate::proc::Pid; prelude::*,
use crate::wutil::dir_iter::DirIter; proc::Pid,
wutil::dir_iter::DirIter,
};
use fish_common::{FilenameRef, assert_sync}; use fish_common::{FilenameRef, assert_sync};
use fish_wcstringutil::wcs2bytes; use fish_widestring::wcs2bytes;
use std::collections::{HashMap, HashSet}; use std::{
use std::num::NonZeroU32; collections::{HashMap, HashSet},
use std::sync::{Arc, LazyLock, Mutex}; num::NonZeroU32,
sync::{Arc, LazyLock, Mutex},
};
#[derive(Clone)] #[derive(Clone)]
pub struct FunctionProperties { pub struct FunctionProperties {

View File

@@ -9,7 +9,7 @@
path::{DirRemoteness, path_get_data_remoteness}, path::{DirRemoteness, path_get_data_remoteness},
wutil::FileId, wutil::FileId,
}; };
use fish_wcstringutil::wcs2bytes; use fish_widestring::wcs2bytes;
use libc::{ENODEV, MAP_ANONYMOUS, MAP_FAILED, MAP_PRIVATE, PROT_READ, PROT_WRITE}; use libc::{ENODEV, MAP_ANONYMOUS, MAP_FAILED, MAP_PRIVATE, PROT_READ, PROT_WRITE};
use std::{ use std::{
fs::File, fs::File,

View File

@@ -1805,9 +1805,8 @@ mod tests {
use crate::prelude::*; use crate::prelude::*;
use crate::tests::prelude::test_init; use crate::tests::prelude::test_init;
use fish_build_helper::workspace_root; use fish_build_helper::workspace_root;
use fish_wcstringutil::{ use fish_wcstringutil::{string_prefixes_string, string_prefixes_string_case_insensitive};
string_prefixes_string, string_prefixes_string_case_insensitive, wcs2bytes, use fish_widestring::wcs2bytes;
};
use rand::Rng as _; use rand::Rng as _;
use rand::rngs::ThreadRng; use rand::rngs::ThreadRng;
use std::collections::VecDeque; use std::collections::VecDeque;

View File

@@ -1,26 +1,27 @@
use crate::builtins::shared::{STATUS_CMD_ERROR, STATUS_CMD_OK, STATUS_READ_TOO_MUCH}; use crate::{
use crate::common::bytes2wcstring; builtins::shared::{STATUS_CMD_ERROR, STATUS_CMD_OK, STATUS_READ_TOO_MUCH},
use crate::fd_monitor::{Callback, FdMonitor, FdMonitorItemId}; common::bytes2wcstring,
use crate::fds::{ fd_monitor::{Callback, FdMonitor, FdMonitorItemId},
BorrowedFdFile, PIPE_ERROR, make_autoclose_pipes, make_fd_nonblocking, wopen_cloexec, fds::{BorrowedFdFile, PIPE_ERROR, make_autoclose_pipes, make_fd_nonblocking, wopen_cloexec},
flog::{flog, flogf, should_flog},
nix::isatty,
path::path_apply_working_directory,
prelude::*,
proc::JobGroupRef,
redirection::{RedirectionMode, RedirectionSpecList},
wutil::{perror_io, unescape_bytes_and_write_to_fd, wdirname, wstat},
}; };
use crate::flog::{flog, flogf, should_flog};
use crate::nix::isatty;
use crate::path::path_apply_working_directory;
use crate::prelude::*;
use crate::proc::JobGroupRef;
use crate::redirection::{RedirectionMode, RedirectionSpecList};
use crate::wutil::{perror_io, unescape_bytes_and_write_to_fd, wdirname, wstat};
use errno::Errno; use errno::Errno;
use fish_util::perror; use fish_util::perror;
use fish_wcstringutil::wcs2bytes; use fish_widestring::wcs2bytes;
use libc::{EAGAIN, EINTR, ENOENT, ENOTDIR, EWOULDBLOCK, STDOUT_FILENO}; use libc::{EAGAIN, EINTR, ENOENT, ENOTDIR, EWOULDBLOCK, STDOUT_FILENO};
use nix::fcntl::OFlag; use nix::{fcntl::OFlag, sys::stat::Mode};
use nix::sys::stat::Mode; use std::{
use std::fs::File; fs::File,
use std::io; io,
use std::os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, OwnedFd, RawFd}; os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, OwnedFd, RawFd},
use std::sync::{Arc, LazyLock, Mutex, MutexGuard}; sync::{Arc, LazyLock, Mutex, MutexGuard},
};
/// separated_buffer_t represents a buffer of output from commands, prepared to be turned into a /// separated_buffer_t represents a buffer of output from commands, prepared to be turned into a
/// variable. For example, command substitutions output into one of these. Most commands just /// variable. For example, command substitutions output into one of these. Most commands just

View File

@@ -36,8 +36,7 @@
EscapeFlags, EscapeStringStyle, FilenameRef, ScopeGuarding, ScopedCell, ScopedRefCell, EscapeFlags, EscapeStringStyle, FilenameRef, ScopeGuarding, ScopedCell, ScopedRefCell,
}; };
use fish_util::get_time; use fish_util::get_time;
use fish_wcstringutil::wcs2bytes; use fish_widestring::{WExt as _, wcs2bytes};
use fish_widestring::WExt as _;
use libc::c_int; use libc::c_int;
use std::cell::{Ref, RefCell, RefMut}; use std::cell::{Ref, RefCell, RefMut};
use std::ffi::OsStr; use std::ffi::OsStr;

View File

@@ -9,7 +9,7 @@
use crate::wutil::{normalize_path, path_normalize_for_cd, waccess, wdirname, wstat}; use crate::wutil::{normalize_path, path_normalize_for_cd, waccess, wdirname, wstat};
use cfg_if::cfg_if; use cfg_if::cfg_if;
use errno::{Errno, errno, set_errno}; use errno::{Errno, errno, set_errno};
use fish_wcstringutil::{wcs2osstring, wcs2zstring}; use fish_widestring::{wcs2osstring, wcs2zstring};
use libc::{EACCES, ENOENT, ENOTDIR, X_OK}; use libc::{EACCES, ENOENT, ENOTDIR, X_OK};
use nix::unistd::AccessFlags; use nix::unistd::AccessFlags;
use std::ffi::OsStr; use std::ffi::OsStr;

View File

@@ -26,8 +26,8 @@
use crate::wutil::fstat; use crate::wutil::fstat;
use fish_common::write_loop; use fish_common::write_loop;
use fish_fallback::{fish_wcswidth_canonicalizing, fish_wcwidth}; use fish_fallback::{fish_wcswidth_canonicalizing, fish_wcwidth};
use fish_wcstringutil::{fish_wcwidth_visible, string_prefixes_string, wcs2bytes}; use fish_wcstringutil::{fish_wcwidth_visible, string_prefixes_string};
use fish_widestring::ELLIPSIS_CHAR; use fish_widestring::{ELLIPSIS_CHAR, wcs2bytes};
use libc::{STDERR_FILENO, STDOUT_FILENO}; use libc::{STDERR_FILENO, STDOUT_FILENO};
use nix::sys::termios; use nix::sys::termios;
use std::cell::RefCell; use std::cell::RefCell;

View File

@@ -8,7 +8,7 @@
use fish_color::{Color, Color24}; use fish_color::{Color, Color24};
use fish_common::{EscapeStringStyle, write_loop}; use fish_common::{EscapeStringStyle, write_loop};
use fish_feature_flags::FeatureFlag; use fish_feature_flags::FeatureFlag;
use fish_wcstringutil::{wcs2bytes, wcs2bytes_appending}; use fish_widestring::{wcs2bytes, wcs2bytes_appending};
use std::cell::{RefCell, RefMut}; use std::cell::{RefCell, RefMut};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::os::fd::RawFd; use std::os::fd::RawFd;

View File

@@ -2,7 +2,7 @@
use crate::prelude::*; use crate::prelude::*;
use crate::universal_notifier::UniversalNotifier; use crate::universal_notifier::UniversalNotifier;
use crate::wutil::{wbasename, wdirname}; use crate::wutil::{wbasename, wdirname};
use fish_wcstringutil::wcs2osstring; use fish_widestring::wcs2osstring;
use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify}; use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify};
use std::ffi::OsString; use std::ffi::OsString;
use std::os::fd::{AsFd as _, AsRawFd as _, RawFd}; use std::os::fd::{AsFd as _, AsRawFd as _, RawFd};

View File

@@ -3,7 +3,7 @@
use crate::prelude::*; use crate::prelude::*;
use crate::universal_notifier::UniversalNotifier; use crate::universal_notifier::UniversalNotifier;
use crate::wutil::wdirname; use crate::wutil::wdirname;
use fish_wcstringutil::wcs2osstring; use fish_widestring::wcs2osstring;
use nix::sys::event::{EvFlags, EventFilter, FilterFlag, KEvent, Kqueue}; use nix::sys::event::{EvFlags, EventFilter, FilterFlag, KEvent, Kqueue};
use std::fs::File; use std::fs::File;
use std::os::fd::AsFd; use std::os::fd::AsFd;

View File

@@ -17,7 +17,7 @@ pub fn test_notifiers(notifiers: &[&dyn UniversalNotifier], fish_variables_path:
// Helper to simulate modifying a file, using the atomic rename() approach. // Helper to simulate modifying a file, using the atomic rename() approach.
let modify_path = |path: &wstr| -> Result<(), std::io::Error> { let modify_path = |path: &wstr| -> Result<(), std::io::Error> {
use fish_wcstringutil::wcs2osstring; use fish_widestring::wcs2osstring;
use std::fs; use std::fs;
use std::io::Write as _; use std::io::Write as _;
let path = wcs2osstring(path); let path = wcs2osstring(path);

View File

@@ -2,8 +2,7 @@
use crate::common::bytes2wcstring; use crate::common::bytes2wcstring;
use crate::wutil::DevInode; use crate::wutil::DevInode;
use cfg_if::cfg_if; use cfg_if::cfg_if;
use fish_wcstringutil::wcs2zstring; use fish_widestring::{WString, wcs2zstring, wstr};
use fish_widestring::{WString, wstr};
use libc::{ use libc::{
EACCES, EIO, ELOOP, ENAMETOOLONG, ENODEV, ENOENT, ENOTDIR, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, EACCES, EIO, ELOOP, ENAMETOOLONG, ENODEV, ENOENT, ENOTDIR, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO,
S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK,

View File

@@ -1,8 +1,10 @@
use crate::wutil::wstr; use crate::wutil::wstr;
use fish_wcstringutil::wcs2zstring; use fish_widestring::wcs2zstring;
use std::ffi::{CStr, OsStr}; use std::{
use std::fs::{self, File, Metadata}; ffi::{CStr, OsStr},
use std::os::unix::prelude::*; fs::{self, File, Metadata},
os::unix::prelude::*,
};
/// Struct for representing a file's inode. We use this to detect and avoid symlink loops, among /// Struct for representing a file's inode. We use this to detect and avoid symlink loops, among
/// other things. /// other things.

View File

@@ -17,13 +17,17 @@
use errno::{Errno, set_errno}; use errno::{Errno, set_errno};
use fish_common::fish_reserved_codepoint; use fish_common::fish_reserved_codepoint;
use fish_util::{perror, write_to_fd}; use fish_util::{perror, write_to_fd};
use fish_wcstringutil::{join_strings, str2bytes_callback, wcs2osstring, wcs2zstring}; use fish_wcstringutil::join_strings;
use fish_widestring::{IntoCharIter, L, WExt as _, WString, wstr}; use fish_widestring::{
IntoCharIter, L, WExt as _, WString, str2bytes_callback, wcs2osstring, wcs2zstring, wstr,
};
use nix::unistd::AccessFlags; use nix::unistd::AccessFlags;
use std::ffi::OsStr; use std::{
use std::fs::{self, canonicalize}; ffi::OsStr,
use std::io; fs::{self, canonicalize},
use std::os::unix::prelude::*; io,
os::unix::prelude::*,
};
pub use crate::wutil::printf::{eprintf, fprintf, printf, sprintf}; pub use crate::wutil::printf::{eprintf, fprintf, printf, sprintf};