Use Rust for executables

Use Rust for executables

Drops the C++ entry points and restructures the Rust package into a
library and three binary crates.

Renames the fish-rust package to fish.

At least on Ubuntu, "fish_indent" is built before "fish".
Make sure export CURSES_LIBRARY_LIST to all binaries to make sure
that "cached-curses-libnames" is populated.

Closes #10198
This commit is contained in:
David Adam 2024-01-12 13:08:41 +01:00 committed by Johannes Altmanninger
parent 4a2edbf97e
commit 1683e720a8
24 changed files with 197 additions and 193 deletions

View File

@ -138,7 +138,9 @@ include(cmake/PCRE2.cmake)
# Define a function to link dependencies.
function(FISH_LINK_DEPS_AND_SIGN target)
target_link_libraries(${target} fishlib)
# Tell Cargo where our build directory is so it can find config.h.
corrosion_set_env_vars(${target} ${VARS_FOR_CARGO})
corrosion_link_libraries(${target} fishlib)
codesign_on_mac(${target})
endfunction(FISH_LINK_DEPS_AND_SIGN)
@ -146,25 +148,18 @@ endfunction(FISH_LINK_DEPS_AND_SIGN)
add_library(fishlib STATIC ${FISH_SRCS})
target_sources(fishlib PRIVATE ${FISH_HEADERS})
target_link_libraries(fishlib
fish-rust
${CURSES_LIBRARY} ${CURSES_EXTRA_LIBRARY} Threads::Threads ${CMAKE_DL_LIBS}
${PCRE2_LIB} ${Intl_LIBRARIES} ${ATOMIC_LIBRARY}
"fish-rust")
${PCRE2_LIB} ${Intl_LIBRARIES} ${ATOMIC_LIBRARY})
target_include_directories(fishlib PRIVATE
${CURSES_INCLUDE_DIRS})
# Define fish.
add_executable(fish src/fish.cpp)
fish_link_deps_and_sign(fish)
# Define fish_indent.
add_executable(fish_indent
src/fish_indent.cpp)
fish_link_deps_and_sign(fish_indent)
# Define fish_key_reader.
add_executable(fish_key_reader
src/fish_key_reader.cpp)
fish_link_deps_and_sign(fish_key_reader)
# Set up the docs.

2
Cargo.lock generated
View File

@ -95,7 +95,7 @@ version = "0.2.0"
source = "git+https://github.com/fish-shell/fast-float-rust?branch=fish#9590c33a3f166a3533ba1cbb7a03e1105acec034"
[[package]]
name = "fish-rust"
name = "fish"
version = "0.1.0"
dependencies = [
"bitflags 2.4.0",

View File

@ -14,7 +14,7 @@ edition = "2021"
overflow-checks = true
[package]
name = "fish-rust"
name = "fish"
version = "0.1.0"
edition.workspace = true
rust-version.workspace = true
@ -50,10 +50,22 @@ cc = "1.0.83"
rsconf = "0.1.1"
[lib]
crate-type = ["staticlib"]
crate-type = ["rlib"]
path = "fish-rust/src/lib.rs"
doctest = false
[[bin]]
name = "fish"
path = "fish-rust/src/bin/fish.rs"
[[bin]]
name = "fish_indent"
path = "fish-rust/src/bin/fish_indent.rs"
[[bin]]
name = "fish_key_reader"
path = "fish-rust/src/bin/fish_key_reader.rs"
[features]
default = []
benchmark = []

View File

@ -77,7 +77,7 @@ function(FISH_TRY_CREATE_DIRS)
endforeach()
endfunction(FISH_TRY_CREATE_DIRS)
install(TARGETS ${PROGRAMS}
install(IMPORTED_RUNTIME_ARTIFACTS ${PROGRAMS}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ
GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
DESTINATION ${bindir})

View File

@ -21,7 +21,7 @@ else()
)
endif()
set(fish_rust_target "fish-rust")
set(fish_rust_target "fish")
set(FISH_CRATE_FEATURES)
if(NOT DEFINED CARGO_FLAGS)
@ -36,7 +36,7 @@ endif()
corrosion_import_crate(
MANIFEST_PATH "${CMAKE_SOURCE_DIR}/Cargo.toml"
CRATES "fish-rust"
CRATES "fish"
"${FISH_CRATE_FEATURES}"
FLAGS "${CARGO_FLAGS}"
)
@ -56,7 +56,6 @@ endif()
# CMAKE_BINARY_DIR can include symlinks, since we want to compare this to the dir fish is executed in we need to canonicalize it.
file(REAL_PATH "${CMAKE_BINARY_DIR}" fish_binary_dir)
string(JOIN "," CURSES_LIBRARY_LIST ${CURSES_LIBRARY} ${CURSES_EXTRA_LIBRARY})
# Tell Cargo where our build directory is so it can find config.h.
@ -72,5 +71,3 @@ set(VARS_FOR_CARGO
"LOCALEDIR=${CMAKE_INSTALL_FULL_LOCALEDIR}"
"CURSES_LIBRARY_LIST=${CURSES_LIBRARY_LIST}"
)
corrosion_set_env_vars(${fish_rust_target} ${VARS_FOR_CARGO})

View File

@ -159,7 +159,7 @@ endif()
add_test(
NAME "cargo-test"
COMMAND env ${VARS_FOR_CARGO} cargo test ${CARGO_FLAGS} --package fish-rust --target-dir ${rust_target_dir} ${cargo_target_opt}
COMMAND env ${VARS_FOR_CARGO} cargo test ${CARGO_FLAGS} --package fish --target-dir ${rust_target_dir} ${cargo_target_opt}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
set_tests_properties("cargo-test" PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE})

View File

@ -45,7 +45,7 @@ ENV \
RUSTFLAGS=-Zsanitizer=address \
CC=clang \
CXX=clang++ \
CXXFLAGS="-fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address -DFISH_CI_SAN" \
CXXFLAGS=-DFISH_CI_SAN \
ASAN_OPTIONS=check_initialization_order=1:detect_stack_use_after_return=1:detect_leaks=1 \
LSAN_OPTIONS=verbosity=0:log_threads=0:use_tls=1:print_suppressions=0:suppressions=/fish-source/build_tools/lsan_suppressions.txt \
FISH_CI_SAN=1

View File

@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
use crate::{
use fish::{
ast::Ast,
builtins::shared::{
BUILTIN_ERR_MISSING, BUILTIN_ERR_UNKNOWN, STATUS_CMD_OK, STATUS_CMD_UNKNOWN,
@ -25,17 +25,19 @@ use crate::{
common::{
escape, exit_without_destructors, get_executable_path,
restore_term_foreground_process_group_for_exit, save_term_foreground_process_group,
scoped_push_replacer, str2wcstring, wcs2string, PROFILING_ACTIVE, PROGRAM_NAME,
scoped_push_replacer, str2wcstring, wcs2string, PACKAGE_NAME, PROFILING_ACTIVE,
PROGRAM_NAME,
},
env::Statuses,
env::{
environment::{env_init, EnvStack, Environment},
ConfigPaths, EnvMode,
},
eprintf,
event::{self, Event},
fds::set_cloexec,
flog::{self, activate_flog_categories_by_pattern, set_flog_file_fd, FLOG, FLOGF},
function, future_feature_flags as features, history,
fprintf, function, future_feature_flags as features, history,
history::start_private_mode,
io::IoChain,
libc::setlinebuf,
@ -45,6 +47,7 @@ use crate::{
parse_util::parse_util_detect_errors_in_ast,
parser::{BlockType, Parser},
path::path_get_config,
printf,
proc::{
get_login, is_interactive_session, mark_login, mark_no_exec, proc_init,
set_interactive_session,
@ -65,11 +68,6 @@ use std::path::{Path, PathBuf};
use std::sync::atomic::Ordering;
use std::sync::Arc;
// FIXME: when the crate is actually called fish and not fish-rust, read this from cargo
// See: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates
// for reference
pub const PACKAGE_NAME: &str = "fish"; // env!("CARGO_PKG_NAME");
// FIXME: the following should just use env!(), this is to make `cargo test` work without CMake for now
const DOC_DIR: &str = {
match option_env!("DOCDIR") {
@ -341,7 +339,7 @@ fn run_command_list(parser: &Parser, cmds: &[OsString]) -> i32 {
}
fn fish_parse_opt(args: &mut [WString], opts: &mut FishCmdOpts) -> usize {
use crate::wgetopt::{wgetopter_t, wopt, woption, woption_argument_t::*};
use fish::wgetopt::{wgetopter_t, wopt, woption, woption_argument_t::*};
const RUSAGE_ARG: char = 1 as char;
const PRINT_DEBUG_CATEGORIES_ARG: char = 2 as char;
@ -436,7 +434,7 @@ fn fish_parse_opt(args: &mut [WString], opts: &mut FishCmdOpts) -> usize {
'v' => {
printf!(
"%s",
wgettext_fmt!("%s, version %s\n", PACKAGE_NAME, crate::BUILD_VERSION)
wgettext_fmt!("%s, version %s\n", PACKAGE_NAME, fish::BUILD_VERSION)
);
std::process::exit(0);
}
@ -491,8 +489,7 @@ fn cstr_from_osstr(s: &OsStr) -> CString {
.unwrap()
}
#[no_mangle]
extern "C" fn fish_main() -> i32 {
fn main() {
let mut args: Vec<WString> = env::args_os()
.map(|osstr| str2wcstring(osstr.as_bytes()))
.collect();
@ -633,7 +630,7 @@ extern "C" fn fish_main() -> i32 {
}
features::set_from_string(opts.features.as_utfstr());
proc_init();
crate::env::misc_init();
fish::env::misc_init();
reader_init();
let parser = Parser::principal_parser();
@ -706,7 +703,7 @@ extern "C" fn fish_main() -> i32 {
"no-execute mode enabled and no script given. Exiting"
);
// above line should always exit
return libc::EXIT_FAILURE;
std::process::exit(libc::EXIT_FAILURE);
}
res = reader_read(parser, libc::STDIN_FILENO, &IoChain::new());
} else {

View File

@ -7,37 +7,40 @@ use std::sync::atomic::Ordering;
use libc::{LC_ALL, STDOUT_FILENO};
use crate::ast::{
use fish::ast::{
self, Ast, Category, Leaf, List, Node, NodeVisitor, SourceRangeList, Traversal, Type,
};
use crate::builtins::shared::{STATUS_CMD_ERROR, STATUS_CMD_OK};
use crate::common::{
use fish::builtins::shared::{STATUS_CMD_ERROR, STATUS_CMD_OK};
use fish::common::{
str2wcstring, unescape_string, wcs2string, wcs2zstring, UnescapeFlags, UnescapeStringStyle,
PROGRAM_NAME,
};
use crate::env::env_init;
use crate::env::environment::Environment;
use crate::env::EnvStack;
use crate::expand::INTERNAL_SEPARATOR;
use crate::fds::set_cloexec;
use fish::env::env_init;
use fish::env::environment::Environment;
use fish::env::EnvStack;
use fish::eprintf;
use fish::expand::INTERNAL_SEPARATOR;
use fish::fds::set_cloexec;
use fish::fprintf;
#[allow(unused_imports)]
use crate::future::{IsOkAnd, IsSomeAnd, IsSorted};
use crate::global_safety::RelaxedAtomicBool;
use crate::highlight::{colorize, highlight_shell, HighlightRole, HighlightSpec};
use crate::libc::setlinebuf;
use crate::operation_context::OperationContext;
use crate::parse_constants::{ParseTokenType, ParseTreeFlags, SourceRange};
use crate::parse_util::parse_util_compute_indents;
use crate::print_help::print_help;
use crate::threads;
use crate::tokenizer::{TokenType, Tokenizer, TOK_SHOW_BLANK_LINES, TOK_SHOW_COMMENTS};
use crate::topic_monitor::topic_monitor_init;
use crate::wchar::prelude::*;
use crate::wcstringutil::count_preceding_backslashes;
use crate::wgetopt::{wgetopter_t, wopt, woption, woption_argument_t};
use crate::wutil::perror;
use crate::wutil::{fish_iswalnum, write_to_fd};
use crate::{
use fish::future::{IsOkAnd, IsSomeAnd, IsSorted};
use fish::global_safety::RelaxedAtomicBool;
use fish::highlight::{colorize, highlight_shell, HighlightRole, HighlightSpec};
use fish::libc::setlinebuf;
use fish::operation_context::OperationContext;
use fish::parse_constants::{ParseTokenType, ParseTreeFlags, SourceRange};
use fish::parse_util::parse_util_compute_indents;
use fish::print_help::print_help;
use fish::printf;
use fish::threads;
use fish::tokenizer::{TokenType, Tokenizer, TOK_SHOW_BLANK_LINES, TOK_SHOW_COMMENTS};
use fish::topic_monitor::topic_monitor_init;
use fish::wchar::prelude::*;
use fish::wcstringutil::count_preceding_backslashes;
use fish::wgetopt::{wgetopter_t, wopt, woption, woption_argument_t};
use fish::wutil::perror;
use fish::wutil::{fish_iswalnum, write_to_fd};
use fish::{
flog::{self, activate_flog_categories_by_pattern, set_flog_file_fd},
future_feature_flags,
};
@ -728,8 +731,7 @@ fn char_is_escaped(text: &wstr, idx: usize) -> bool {
count_preceding_backslashes(text, idx) % 2 == 1
}
#[no_mangle]
extern "C" fn fish_indent_main() -> i32 {
fn main() {
PROGRAM_NAME.set(L!("fish_indent")).unwrap();
topic_monitor_init();
@ -804,7 +806,7 @@ extern "C" fn fish_indent_main() -> i32 {
'P' => DUMP_PARSE_TREE.store(true),
'h' => {
print_help("fish_indent");
return STATUS_CMD_OK.unwrap();
std::process::exit(STATUS_CMD_OK.unwrap());
}
'v' => {
printf!(
@ -812,10 +814,10 @@ extern "C" fn fish_indent_main() -> i32 {
wgettext_fmt!(
"%s, version %s\n",
PROGRAM_NAME.get().unwrap(),
crate::BUILD_VERSION
fish::BUILD_VERSION
)
);
return STATUS_CMD_OK.unwrap();
std::process::exit(STATUS_CMD_OK.unwrap());
}
'w' => output_type = OutputType::File,
'i' => do_indent = false,
@ -838,7 +840,7 @@ extern "C" fn fish_indent_main() -> i32 {
'o' => {
debug_output = Some(w.woptarg.unwrap());
}
_ => return STATUS_CMD_ERROR.unwrap(),
_ => std::process::exit(STATUS_CMD_ERROR.unwrap()),
}
}
@ -854,7 +856,7 @@ extern "C" fn fish_indent_main() -> i32 {
if file.is_null() {
eprintf!("Could not open file %s\n", debug_output);
perror("fopen");
return -1;
std::process::exit(-1);
}
let fd = unsafe { libc::fileno(file) };
set_cloexec(fd, true);
@ -876,11 +878,11 @@ extern "C" fn fish_indent_main() -> i32 {
PROGRAM_NAME.get().unwrap()
)
);
return STATUS_CMD_ERROR.unwrap();
std::process::exit(STATUS_CMD_ERROR.unwrap());
}
match read_file(stdin()) {
Ok(s) => src = s,
Err(()) => return STATUS_CMD_ERROR.unwrap(),
Err(()) => std::process::exit(STATUS_CMD_ERROR.unwrap()),
}
} else {
let arg = args[i];
@ -888,7 +890,7 @@ extern "C" fn fish_indent_main() -> i32 {
Ok(file) => {
match read_file(file) {
Ok(s) => src = s,
Err(()) => return STATUS_CMD_ERROR.unwrap(),
Err(()) => std::process::exit(STATUS_CMD_ERROR.unwrap()),
}
output_location = arg;
}
@ -897,7 +899,7 @@ extern "C" fn fish_indent_main() -> i32 {
"%s",
wgettext_fmt!("Opening \"%s\" failed: %s\n", arg, err.to_string())
);
return STATUS_CMD_ERROR.unwrap();
std::process::exit(STATUS_CMD_ERROR.unwrap());
}
}
}
@ -942,7 +944,7 @@ extern "C" fn fish_indent_main() -> i32 {
err.to_string()
)
);
return STATUS_CMD_ERROR.unwrap();
std::process::exit(STATUS_CMD_ERROR.unwrap());
}
}
}
@ -972,7 +974,7 @@ extern "C" fn fish_indent_main() -> i32 {
let _ = write_to_fd(&colored_output, STDOUT_FILENO);
i += 1;
}
retval
std::process::exit(retval)
}
static DUMP_PARSE_TREE: RelaxedAtomicBool = RelaxedAtomicBool::new(false);

View File

@ -15,16 +15,19 @@ use std::{
use libc::{STDIN_FILENO, TCSANOW, VEOF, VINTR};
#[allow(unused_imports)]
use crate::future::IsSomeAnd;
use crate::{
use fish::future::IsSomeAnd;
use fish::{
builtins::shared::BUILTIN_ERR_UNKNOWN,
common::{scoped_push_replacer, shell_modes, str2wcstring, PROGRAM_NAME},
env::env_init,
eprintf,
fallback::fish_wcwidth,
fprintf,
input::input_terminfo_get_name,
input_common::{CharEvent, InputEventQueue, InputEventQueuer},
parser::Parser,
print_help::print_help,
printf,
proc::set_interactive_session,
reader::{
check_exit_loop_maybe_warning, reader_init, reader_test_and_clear_interrupted,
@ -335,7 +338,7 @@ fn parse_flags(continuous_mode: &mut bool, verbose: &mut bool) -> bool {
wgettext_fmt!(
"%ls, version %s\n",
PROGRAM_NAME.get().unwrap(),
crate::BUILD_VERSION
fish::BUILD_VERSION
)
);
}
@ -366,19 +369,18 @@ fn parse_flags(continuous_mode: &mut bool, verbose: &mut bool) -> bool {
true
}
#[no_mangle]
extern "C" fn fish_key_reader_main() -> i32 {
fn main() {
PROGRAM_NAME.set(L!("fish_key_reader")).unwrap();
let mut continuous_mode = false;
let mut verbose = false;
if !parse_flags(&mut continuous_mode, &mut verbose) {
return 1;
std::process::exit(1);
}
if unsafe { libc::isatty(STDIN_FILENO) } == 0 {
eprintf!("Stdin must be attached to a tty.\n");
return 1;
std::process::exit(1);
}
setup_and_process_keys(continuous_mode, verbose);

View File

@ -31,6 +31,8 @@ use std::sync::atomic::{AtomicI32, AtomicU32, Ordering};
use std::sync::{Arc, Mutex, MutexGuard, TryLockError};
use std::time;
pub const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");
// Highest legal ASCII value.
pub const ASCII_MAX: char = 127 as char;
@ -1177,7 +1179,7 @@ pub fn cstr2wcstring(input: &[u8]) -> WString {
str2wcstring(&input[0..strlen])
}
pub fn charptr2wcstring(input: *const libc::c_char) -> WString {
pub(crate) fn charptr2wcstring(input: *const libc::c_char) -> WString {
let input: &[u8] = unsafe {
let strlen = libc::strlen(input);
slice::from_raw_parts(input.cast(), strlen)
@ -2144,21 +2146,24 @@ macro_rules! err {
}
}
#[macro_export]
macro_rules! fprintf {
($fd:expr, $format:expr $(, $arg:expr)* $(,)?) => {
{
let wide = crate::wutil::sprintf!($format, $( $arg ),*);
crate::wutil::wwrite_to_fd(&wide, $fd);
let wide = $crate::wutil::sprintf!($format, $( $arg ),*);
$crate::wutil::wwrite_to_fd(&wide, $fd);
}
}
}
#[macro_export]
macro_rules! printf {
($format:expr $(, $arg:expr)* $(,)?) => {
fprintf!(libc::STDOUT_FILENO, $format $(, $arg)*)
}
}
#[macro_export]
macro_rules! eprintf {
($format:expr $(, $arg:expr)* $(,)?) => {
fprintf!(libc::STDERR_FILENO, $format $(, $arg)*)

View File

@ -724,7 +724,7 @@ fn fork_child_for_process(
job.job_id().as_num(),
narrow_cmd.as_ptr(),
narrow_argv0.as_ptr(),
);
)
}
}
}

View File

@ -172,12 +172,13 @@ pub fn flog_impl(s: &str) {
}
/// The entry point for flogging.
#[macro_export]
macro_rules! FLOG {
($category:ident, $($elem:expr),+ $(,)*) => {
if crate::flog::categories::$category.enabled.load(std::sync::atomic::Ordering::Relaxed) {
if $crate::flog::categories::$category.enabled.load(std::sync::atomic::Ordering::Relaxed) {
#[allow(unused_imports)]
use crate::flog::{FloggableDisplay, FloggableDebug};
let mut vs = vec![format!("{}:", crate::flog::categories::$category.name)];
use $crate::flog::{FloggableDisplay, FloggableDebug};
let mut vs = vec![format!("{}:", $crate::flog::categories::$category.name)];
$(
{
vs.push($elem.to_flog_str())
@ -186,26 +187,28 @@ macro_rules! FLOG {
// We don't use locking here so we have to append our own newline to avoid multiple writes.
let mut v = vs.join(" ");
v.push('\n');
crate::flog::flog_impl(&v);
$crate::flog::flog_impl(&v);
}
};
}
#[macro_export]
macro_rules! FLOGF {
($category:ident, $fmt: expr, $($elem:expr),+ $(,)*) => {
crate::flog::FLOG!($category, crate::wutil::sprintf!($fmt, $($elem),*))
$crate::flog::FLOG!($category, $crate::wutil::sprintf!($fmt, $($elem),*))
}
}
#[macro_export]
macro_rules! should_flog {
($category:ident) => {
crate::flog::categories::$category
$crate::flog::categories::$category
.enabled
.load(std::sync::atomic::Ordering::Relaxed)
};
}
pub(crate) use {should_flog, FLOG, FLOGF};
pub use {should_flog, FLOG, FLOGF};
/// For each category, if its name matches the wildcard, set its enabled to the given sense.
fn apply_one_wildcard(wc_esc: &wstr, sense: bool) {

View File

@ -46,7 +46,7 @@ fn strlen_safe(s: *const libc::c_char) -> usize {
}
/// Report the error code for a failed setpgid call.
pub fn report_setpgid_error(
pub(crate) fn report_setpgid_error(
err: i32,
is_parent: bool,
pid: pid_t,
@ -243,7 +243,7 @@ pub fn execute_fork() -> pid_t {
exit_without_destructors(1)
}
pub fn safe_report_exec_error(
pub(crate) fn safe_report_exec_error(
err: i32,
actual_cmd: *const c_char,
argvv: *const *const c_char,

View File

@ -162,7 +162,7 @@ impl PosixSpawner {
}
// Attempt to spawn a new process.
pub fn spawn(
pub(crate) fn spawn(
&mut self,
cmd: *const c_char,
argv: *const *mut c_char,

View File

@ -28,83 +28,80 @@ pub const BUILD_VERSION: &str = match option_env!("FISH_BUILD_VERSION") {
};
#[macro_use]
mod common;
pub mod common;
mod abbrs;
mod ast;
mod autoload;
mod builtins;
mod color;
mod complete;
mod curses;
mod editable_line;
mod env;
mod env_dispatch;
mod env_universal_common;
mod event;
mod exec;
mod expand;
mod fallback;
mod fd_monitor;
mod fd_readable_set;
mod fds;
mod fish;
mod fish_indent;
mod fish_key_reader;
mod flog;
mod fork_exec;
mod function;
mod future;
mod future_feature_flags;
mod global_safety;
mod highlight;
mod history;
mod input;
mod input_common;
mod io;
mod job_group;
mod kill;
pub mod abbrs;
pub mod ast;
pub mod autoload;
pub mod builtins;
pub mod color;
pub mod complete;
pub mod curses;
pub mod editable_line;
pub mod env;
pub mod env_dispatch;
pub mod env_universal_common;
pub mod event;
pub mod exec;
pub mod expand;
pub mod fallback;
pub mod fd_monitor;
pub mod fd_readable_set;
pub mod fds;
pub mod flog;
pub mod fork_exec;
pub mod function;
pub mod future;
pub mod future_feature_flags;
pub mod global_safety;
pub mod highlight;
pub mod history;
pub mod input;
pub mod input_common;
pub mod io;
pub mod job_group;
pub mod kill;
#[allow(non_snake_case)]
mod libc;
mod locale;
mod nix;
mod null_terminated_array;
mod operation_context;
mod output;
mod pager;
mod parse_constants;
mod parse_execution;
mod parse_tree;
mod parse_util;
mod parser;
mod parser_keywords;
mod path;
mod pointer;
mod print_help;
mod proc;
mod re;
mod reader;
mod reader_history_search;
mod redirection;
mod screen;
mod signal;
mod termsize;
mod threads;
mod timer;
mod tinyexpr;
mod tokenizer;
mod topic_monitor;
mod trace;
mod universal_notifier;
mod util;
mod wait_handle;
mod wchar;
mod wchar_ext;
mod wcstringutil;
mod wgetopt;
mod widecharwidth;
mod wildcard;
mod wutil;
pub mod libc;
pub mod locale;
pub mod nix;
pub mod null_terminated_array;
pub mod operation_context;
pub mod output;
pub mod pager;
pub mod parse_constants;
pub mod parse_execution;
pub mod parse_tree;
pub mod parse_util;
pub mod parser;
pub mod parser_keywords;
pub mod path;
pub mod pointer;
pub mod print_help;
pub mod proc;
pub mod re;
pub mod reader;
pub mod reader_history_search;
pub mod redirection;
pub mod screen;
pub mod signal;
pub mod termsize;
pub mod threads;
pub mod timer;
pub mod tinyexpr;
pub mod tokenizer;
pub mod topic_monitor;
pub mod trace;
pub mod universal_notifier;
pub mod util;
pub mod wait_handle;
pub mod wchar;
pub mod wchar_ext;
pub mod wcstringutil;
pub mod wgetopt;
pub mod widecharwidth;
pub mod wildcard;
pub mod wutil;
#[cfg(test)]
#[allow(unused_imports)] // Easy way to suppress warnings while we have two testing modes.

View File

@ -127,7 +127,7 @@ impl OwningNullTerminatedArray {
}
/// Return the length of a null-terminated array of pointers to something.
pub fn null_terminated_array_length<T>(mut arr: *const *const T) -> usize {
pub(crate) fn null_terminated_array_length<T>(mut arr: *const *const T) -> usize {
let mut len = 0;
// Safety: caller must ensure that arr is null-terminated.
unsafe {

View File

@ -10,24 +10,25 @@ pub use widestring::{Utf32Str as wstr, Utf32String as WString};
/// Pull in our extensions.
pub use crate::wchar_ext::IntoCharIter;
pub(crate) mod prelude {
pub(crate) use crate::{
pub mod prelude {
pub use crate::{
wchar::{wstr, IntoCharIter, WString, L},
wchar_ext::{ToWString, WExt},
wutil::{sprintf, wgettext, wgettext_fmt, wgettext_maybe_fmt, wgettext_str},
};
pub(crate) use widestring_suffix::widestrs;
pub use widestring_suffix::widestrs;
}
/// Creates a wstr string slice, like the "L" prefix of C++.
/// The result is of type wstr.
/// It is NOT nul-terminated.
#[macro_export]
macro_rules! L {
($string:expr) => {
widestring::utf32str!($string)
};
}
pub(crate) use L;
pub use L;
/// A proc-macro for creating wide string literals using an L *suffix*.
/// Example usage:

View File

@ -2,8 +2,7 @@ use std::collections::HashMap;
use std::ffi::CString;
use std::sync::Mutex;
use crate::common::{charptr2wcstring, truncate_at_nul, wcs2zstring};
use crate::fish::PACKAGE_NAME;
use crate::common::{charptr2wcstring, truncate_at_nul, wcs2zstring, PACKAGE_NAME};
#[cfg(test)]
use crate::tests::prelude::*;
use crate::wchar::prelude::*;
@ -130,38 +129,41 @@ pub fn wgettext_str(s: &wstr) -> &'static wstr {
/// Get a (possibly translated) string from a string literal.
/// This returns a &'static wstr.
#[macro_export]
macro_rules! wgettext {
($string:expr) => {
crate::wutil::gettext::wgettext_static_str(widestring::utf32str!($string))
$crate::wutil::gettext::wgettext_static_str(widestring::utf32str!($string))
};
}
pub(crate) use wgettext;
pub use wgettext;
/// Like wgettext, but applies a sprintf format string.
/// The result is a WString.
#[macro_export]
macro_rules! wgettext_fmt {
(
$string:expr, // format string
$($args:expr),+ // list of expressions
$(,)? // optional trailing comma
) => {
crate::wutil::sprintf!(&crate::wutil::wgettext!($string), $($args),+)
$crate::wutil::sprintf!(&$crate::wutil::wgettext!($string), $($args),+)
};
}
pub(crate) use wgettext_fmt;
pub use wgettext_fmt;
/// Like wgettext_fmt, but doesn't require an argument to format.
/// For use in macros.
#[macro_export]
macro_rules! wgettext_maybe_fmt {
(
$string:expr // format string
$(, $args:expr)* // list of expressions
$(,)? // optional trailing comma
) => {
crate::wutil::sprintf!(&crate::wutil::wgettext!($string), $($args),*)
$crate::wutil::sprintf!(&$crate::wutil::wgettext!($string), $($args),*)
};
}
pub(crate) use wgettext_maybe_fmt;
pub use wgettext_maybe_fmt;
#[test]
#[serial]

View File

@ -20,8 +20,8 @@ use crate::wchar::{wstr, WString, L};
use crate::wchar_ext::WExt;
use crate::wcstringutil::{join_strings, split_string, wcs2string_callback};
use errno::errno;
pub(crate) use gettext::{wgettext, wgettext_fmt, wgettext_maybe_fmt, wgettext_str};
pub(crate) use printf::sprintf;
pub use gettext::{wgettext, wgettext_fmt, wgettext_maybe_fmt, wgettext_str};
pub use printf::sprintf;
use std::ffi::{CStr, OsStr};
use std::fs::{self, canonicalize};
use std::io::{self, Write};

View File

@ -1,5 +1,5 @@
// Re-export sprintf macro.
pub(crate) use printf_compat::sprintf;
pub use printf_compat::sprintf;
#[cfg(test)]
mod tests {

View File

@ -1,3 +0,0 @@
extern "C" int fish_main();
int main() { return fish_main(); }

View File

@ -1,3 +0,0 @@
extern "C" int fish_indent_main();
int main() { return fish_indent_main(); }

View File

@ -1,3 +0,0 @@
extern "C" int fish_key_reader_main();
int main() { return fish_key_reader_main(); }