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. # Define a function to link dependencies.
function(FISH_LINK_DEPS_AND_SIGN target) 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}) codesign_on_mac(${target})
endfunction(FISH_LINK_DEPS_AND_SIGN) endfunction(FISH_LINK_DEPS_AND_SIGN)
@ -146,25 +148,18 @@ endfunction(FISH_LINK_DEPS_AND_SIGN)
add_library(fishlib STATIC ${FISH_SRCS}) add_library(fishlib STATIC ${FISH_SRCS})
target_sources(fishlib PRIVATE ${FISH_HEADERS}) target_sources(fishlib PRIVATE ${FISH_HEADERS})
target_link_libraries(fishlib target_link_libraries(fishlib
fish-rust
${CURSES_LIBRARY} ${CURSES_EXTRA_LIBRARY} Threads::Threads ${CMAKE_DL_LIBS} ${CURSES_LIBRARY} ${CURSES_EXTRA_LIBRARY} Threads::Threads ${CMAKE_DL_LIBS}
${PCRE2_LIB} ${Intl_LIBRARIES} ${ATOMIC_LIBRARY} ${PCRE2_LIB} ${Intl_LIBRARIES} ${ATOMIC_LIBRARY})
"fish-rust")
target_include_directories(fishlib PRIVATE target_include_directories(fishlib PRIVATE
${CURSES_INCLUDE_DIRS}) ${CURSES_INCLUDE_DIRS})
# Define fish. # Define fish.
add_executable(fish src/fish.cpp)
fish_link_deps_and_sign(fish) fish_link_deps_and_sign(fish)
# Define fish_indent. # Define fish_indent.
add_executable(fish_indent
src/fish_indent.cpp)
fish_link_deps_and_sign(fish_indent) fish_link_deps_and_sign(fish_indent)
# Define fish_key_reader. # Define fish_key_reader.
add_executable(fish_key_reader
src/fish_key_reader.cpp)
fish_link_deps_and_sign(fish_key_reader) fish_link_deps_and_sign(fish_key_reader)
# Set up the docs. # 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" source = "git+https://github.com/fish-shell/fast-float-rust?branch=fish#9590c33a3f166a3533ba1cbb7a03e1105acec034"
[[package]] [[package]]
name = "fish-rust" name = "fish"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bitflags 2.4.0", "bitflags 2.4.0",

View File

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

View File

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

View File

@ -21,7 +21,7 @@ else()
) )
endif() endif()
set(fish_rust_target "fish-rust") set(fish_rust_target "fish")
set(FISH_CRATE_FEATURES) set(FISH_CRATE_FEATURES)
if(NOT DEFINED CARGO_FLAGS) if(NOT DEFINED CARGO_FLAGS)
@ -36,7 +36,7 @@ endif()
corrosion_import_crate( corrosion_import_crate(
MANIFEST_PATH "${CMAKE_SOURCE_DIR}/Cargo.toml" MANIFEST_PATH "${CMAKE_SOURCE_DIR}/Cargo.toml"
CRATES "fish-rust" CRATES "fish"
"${FISH_CRATE_FEATURES}" "${FISH_CRATE_FEATURES}"
FLAGS "${CARGO_FLAGS}" 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. # 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) file(REAL_PATH "${CMAKE_BINARY_DIR}" fish_binary_dir)
string(JOIN "," CURSES_LIBRARY_LIST ${CURSES_LIBRARY} ${CURSES_EXTRA_LIBRARY}) string(JOIN "," CURSES_LIBRARY_LIST ${CURSES_LIBRARY} ${CURSES_EXTRA_LIBRARY})
# Tell Cargo where our build directory is so it can find config.h. # 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}" "LOCALEDIR=${CMAKE_INSTALL_FULL_LOCALEDIR}"
"CURSES_LIBRARY_LIST=${CURSES_LIBRARY_LIST}" "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( add_test(
NAME "cargo-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}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
) )
set_tests_properties("cargo-test" PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE}) set_tests_properties("cargo-test" PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE})

View File

@ -45,7 +45,7 @@ ENV \
RUSTFLAGS=-Zsanitizer=address \ RUSTFLAGS=-Zsanitizer=address \
CC=clang \ CC=clang \
CXX=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 \ 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 \ 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 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 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
use crate::{ use fish::{
ast::Ast, ast::Ast,
builtins::shared::{ builtins::shared::{
BUILTIN_ERR_MISSING, BUILTIN_ERR_UNKNOWN, STATUS_CMD_OK, STATUS_CMD_UNKNOWN, BUILTIN_ERR_MISSING, BUILTIN_ERR_UNKNOWN, STATUS_CMD_OK, STATUS_CMD_UNKNOWN,
@ -25,17 +25,19 @@ use crate::{
common::{ common::{
escape, exit_without_destructors, get_executable_path, escape, exit_without_destructors, get_executable_path,
restore_term_foreground_process_group_for_exit, save_term_foreground_process_group, 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::Statuses,
env::{ env::{
environment::{env_init, EnvStack, Environment}, environment::{env_init, EnvStack, Environment},
ConfigPaths, EnvMode, ConfigPaths, EnvMode,
}, },
eprintf,
event::{self, Event}, event::{self, Event},
fds::set_cloexec, fds::set_cloexec,
flog::{self, activate_flog_categories_by_pattern, set_flog_file_fd, FLOG, FLOGF}, 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, history::start_private_mode,
io::IoChain, io::IoChain,
libc::setlinebuf, libc::setlinebuf,
@ -45,6 +47,7 @@ use crate::{
parse_util::parse_util_detect_errors_in_ast, parse_util::parse_util_detect_errors_in_ast,
parser::{BlockType, Parser}, parser::{BlockType, Parser},
path::path_get_config, path::path_get_config,
printf,
proc::{ proc::{
get_login, is_interactive_session, mark_login, mark_no_exec, proc_init, get_login, is_interactive_session, mark_login, mark_no_exec, proc_init,
set_interactive_session, set_interactive_session,
@ -65,11 +68,6 @@ use std::path::{Path, PathBuf};
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::Arc; 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 // FIXME: the following should just use env!(), this is to make `cargo test` work without CMake for now
const DOC_DIR: &str = { const DOC_DIR: &str = {
match option_env!("DOCDIR") { 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 { 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 RUSAGE_ARG: char = 1 as char;
const PRINT_DEBUG_CATEGORIES_ARG: char = 2 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' => { 'v' => {
printf!( printf!(
"%s", "%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); std::process::exit(0);
} }
@ -491,8 +489,7 @@ fn cstr_from_osstr(s: &OsStr) -> CString {
.unwrap() .unwrap()
} }
#[no_mangle] fn main() {
extern "C" fn fish_main() -> i32 {
let mut args: Vec<WString> = env::args_os() let mut args: Vec<WString> = env::args_os()
.map(|osstr| str2wcstring(osstr.as_bytes())) .map(|osstr| str2wcstring(osstr.as_bytes()))
.collect(); .collect();
@ -633,7 +630,7 @@ extern "C" fn fish_main() -> i32 {
} }
features::set_from_string(opts.features.as_utfstr()); features::set_from_string(opts.features.as_utfstr());
proc_init(); proc_init();
crate::env::misc_init(); fish::env::misc_init();
reader_init(); reader_init();
let parser = Parser::principal_parser(); let parser = Parser::principal_parser();
@ -706,7 +703,7 @@ extern "C" fn fish_main() -> i32 {
"no-execute mode enabled and no script given. Exiting" "no-execute mode enabled and no script given. Exiting"
); );
// above line should always exit // above line should always exit
return libc::EXIT_FAILURE; std::process::exit(libc::EXIT_FAILURE);
} }
res = reader_read(parser, libc::STDIN_FILENO, &IoChain::new()); res = reader_read(parser, libc::STDIN_FILENO, &IoChain::new());
} else { } else {

View File

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

View File

@ -15,16 +15,19 @@ use std::{
use libc::{STDIN_FILENO, TCSANOW, VEOF, VINTR}; use libc::{STDIN_FILENO, TCSANOW, VEOF, VINTR};
#[allow(unused_imports)] #[allow(unused_imports)]
use crate::future::IsSomeAnd; use fish::future::IsSomeAnd;
use crate::{ use fish::{
builtins::shared::BUILTIN_ERR_UNKNOWN, builtins::shared::BUILTIN_ERR_UNKNOWN,
common::{scoped_push_replacer, shell_modes, str2wcstring, PROGRAM_NAME}, common::{scoped_push_replacer, shell_modes, str2wcstring, PROGRAM_NAME},
env::env_init, env::env_init,
eprintf,
fallback::fish_wcwidth, fallback::fish_wcwidth,
fprintf,
input::input_terminfo_get_name, input::input_terminfo_get_name,
input_common::{CharEvent, InputEventQueue, InputEventQueuer}, input_common::{CharEvent, InputEventQueue, InputEventQueuer},
parser::Parser, parser::Parser,
print_help::print_help, print_help::print_help,
printf,
proc::set_interactive_session, proc::set_interactive_session,
reader::{ reader::{
check_exit_loop_maybe_warning, reader_init, reader_test_and_clear_interrupted, 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!( wgettext_fmt!(
"%ls, version %s\n", "%ls, version %s\n",
PROGRAM_NAME.get().unwrap(), 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 true
} }
#[no_mangle] fn main() {
extern "C" fn fish_key_reader_main() -> i32 {
PROGRAM_NAME.set(L!("fish_key_reader")).unwrap(); PROGRAM_NAME.set(L!("fish_key_reader")).unwrap();
let mut continuous_mode = false; let mut continuous_mode = false;
let mut verbose = false; let mut verbose = false;
if !parse_flags(&mut continuous_mode, &mut verbose) { if !parse_flags(&mut continuous_mode, &mut verbose) {
return 1; std::process::exit(1);
} }
if unsafe { libc::isatty(STDIN_FILENO) } == 0 { if unsafe { libc::isatty(STDIN_FILENO) } == 0 {
eprintf!("Stdin must be attached to a tty.\n"); eprintf!("Stdin must be attached to a tty.\n");
return 1; std::process::exit(1);
} }
setup_and_process_keys(continuous_mode, verbose); 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::sync::{Arc, Mutex, MutexGuard, TryLockError};
use std::time; use std::time;
pub const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");
// Highest legal ASCII value. // Highest legal ASCII value.
pub const ASCII_MAX: char = 127 as char; pub const ASCII_MAX: char = 127 as char;
@ -1177,7 +1179,7 @@ pub fn cstr2wcstring(input: &[u8]) -> WString {
str2wcstring(&input[0..strlen]) 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 input: &[u8] = unsafe {
let strlen = libc::strlen(input); let strlen = libc::strlen(input);
slice::from_raw_parts(input.cast(), strlen) slice::from_raw_parts(input.cast(), strlen)
@ -2144,21 +2146,24 @@ macro_rules! err {
} }
} }
#[macro_export]
macro_rules! fprintf { macro_rules! fprintf {
($fd:expr, $format:expr $(, $arg:expr)* $(,)?) => { ($fd:expr, $format:expr $(, $arg:expr)* $(,)?) => {
{ {
let wide = crate::wutil::sprintf!($format, $( $arg ),*); let wide = $crate::wutil::sprintf!($format, $( $arg ),*);
crate::wutil::wwrite_to_fd(&wide, $fd); $crate::wutil::wwrite_to_fd(&wide, $fd);
} }
} }
} }
#[macro_export]
macro_rules! printf { macro_rules! printf {
($format:expr $(, $arg:expr)* $(,)?) => { ($format:expr $(, $arg:expr)* $(,)?) => {
fprintf!(libc::STDOUT_FILENO, $format $(, $arg)*) fprintf!(libc::STDOUT_FILENO, $format $(, $arg)*)
} }
} }
#[macro_export]
macro_rules! eprintf { macro_rules! eprintf {
($format:expr $(, $arg:expr)* $(,)?) => { ($format:expr $(, $arg:expr)* $(,)?) => {
fprintf!(libc::STDERR_FILENO, $format $(, $arg)*) fprintf!(libc::STDERR_FILENO, $format $(, $arg)*)

View File

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

View File

@ -172,12 +172,13 @@ pub fn flog_impl(s: &str) {
} }
/// The entry point for flogging. /// The entry point for flogging.
#[macro_export]
macro_rules! FLOG { macro_rules! FLOG {
($category:ident, $($elem:expr),+ $(,)*) => { ($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)] #[allow(unused_imports)]
use crate::flog::{FloggableDisplay, FloggableDebug}; use $crate::flog::{FloggableDisplay, FloggableDebug};
let mut vs = vec![format!("{}:", crate::flog::categories::$category.name)]; let mut vs = vec![format!("{}:", $crate::flog::categories::$category.name)];
$( $(
{ {
vs.push($elem.to_flog_str()) 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. // We don't use locking here so we have to append our own newline to avoid multiple writes.
let mut v = vs.join(" "); let mut v = vs.join(" ");
v.push('\n'); v.push('\n');
crate::flog::flog_impl(&v); $crate::flog::flog_impl(&v);
} }
}; };
} }
#[macro_export]
macro_rules! FLOGF { macro_rules! FLOGF {
($category:ident, $fmt: expr, $($elem:expr),+ $(,)*) => { ($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 { macro_rules! should_flog {
($category:ident) => { ($category:ident) => {
crate::flog::categories::$category $crate::flog::categories::$category
.enabled .enabled
.load(std::sync::atomic::Ordering::Relaxed) .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. /// 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) { 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. /// Report the error code for a failed setpgid call.
pub fn report_setpgid_error( pub(crate) fn report_setpgid_error(
err: i32, err: i32,
is_parent: bool, is_parent: bool,
pid: pid_t, pid: pid_t,
@ -243,7 +243,7 @@ pub fn execute_fork() -> pid_t {
exit_without_destructors(1) exit_without_destructors(1)
} }
pub fn safe_report_exec_error( pub(crate) fn safe_report_exec_error(
err: i32, err: i32,
actual_cmd: *const c_char, actual_cmd: *const c_char,
argvv: *const *const c_char, argvv: *const *const c_char,

View File

@ -162,7 +162,7 @@ impl PosixSpawner {
} }
// Attempt to spawn a new process. // Attempt to spawn a new process.
pub fn spawn( pub(crate) fn spawn(
&mut self, &mut self,
cmd: *const c_char, cmd: *const c_char,
argv: *const *mut 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] #[macro_use]
mod common; pub mod common;
mod abbrs; pub mod abbrs;
mod ast; pub mod ast;
mod autoload; pub mod autoload;
mod builtins; pub mod builtins;
mod color; pub mod color;
mod complete; pub mod complete;
mod curses; pub mod curses;
mod editable_line; pub mod editable_line;
mod env; pub mod env;
mod env_dispatch; pub mod env_dispatch;
mod env_universal_common; pub mod env_universal_common;
mod event; pub mod event;
mod exec; pub mod exec;
mod expand; pub mod expand;
mod fallback; pub mod fallback;
mod fd_monitor; pub mod fd_monitor;
mod fd_readable_set; pub mod fd_readable_set;
mod fds; pub mod fds;
mod fish; pub mod flog;
mod fish_indent; pub mod fork_exec;
mod fish_key_reader; pub mod function;
mod flog; pub mod future;
mod fork_exec; pub mod future_feature_flags;
mod function; pub mod global_safety;
mod future; pub mod highlight;
mod future_feature_flags; pub mod history;
mod global_safety; pub mod input;
mod highlight; pub mod input_common;
mod history; pub mod io;
mod input; pub mod job_group;
mod input_common; pub mod kill;
mod io;
mod job_group;
mod kill;
#[allow(non_snake_case)] #[allow(non_snake_case)]
mod libc; pub mod libc;
mod locale; pub mod locale;
mod nix; pub mod nix;
mod null_terminated_array; pub mod null_terminated_array;
mod operation_context; pub mod operation_context;
mod output; pub mod output;
mod pager; pub mod pager;
mod parse_constants; pub mod parse_constants;
mod parse_execution; pub mod parse_execution;
mod parse_tree; pub mod parse_tree;
mod parse_util; pub mod parse_util;
mod parser; pub mod parser;
mod parser_keywords; pub mod parser_keywords;
mod path; pub mod path;
mod pointer; pub mod pointer;
mod print_help; pub mod print_help;
mod proc; pub mod proc;
mod re; pub mod re;
mod reader; pub mod reader;
mod reader_history_search; pub mod reader_history_search;
mod redirection; pub mod redirection;
mod screen; pub mod screen;
mod signal; pub mod signal;
mod termsize; pub mod termsize;
mod threads; pub mod threads;
mod timer; pub mod timer;
mod tinyexpr; pub mod tinyexpr;
mod tokenizer; pub mod tokenizer;
mod topic_monitor; pub mod topic_monitor;
mod trace; pub mod trace;
mod universal_notifier; pub mod universal_notifier;
mod util; pub mod util;
mod wait_handle; pub mod wait_handle;
mod wchar; pub mod wchar;
mod wchar_ext; pub mod wchar_ext;
mod wcstringutil; pub mod wcstringutil;
mod wgetopt; pub mod wgetopt;
mod widecharwidth; pub mod widecharwidth;
mod wildcard; pub mod wildcard;
mod wutil; pub mod wutil;
#[cfg(test)] #[cfg(test)]
#[allow(unused_imports)] // Easy way to suppress warnings while we have two testing modes. #[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. /// 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; let mut len = 0;
// Safety: caller must ensure that arr is null-terminated. // Safety: caller must ensure that arr is null-terminated.
unsafe { unsafe {

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
// Re-export sprintf macro. // Re-export sprintf macro.
pub(crate) use printf_compat::sprintf; pub use printf_compat::sprintf;
#[cfg(test)] #[cfg(test)]
mod tests { 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(); }