From 85311546ded580c89e4f17ef755d4b65a11e299e Mon Sep 17 00:00:00 2001 From: Daniel Rainer Date: Sat, 4 Apr 2026 02:40:52 +0200 Subject: [PATCH] refactor: extract `fish-feature-flags` crate Another step in splitting up the main library crate. Note that this change requires removing the `#[cfg(test)]` annotations around the `LOCAL_OVERRIDE_STACK` code, because otherwise the code would be removed in test builds for other packages, making the `#[cfg(test)]` functions unusable from other packages, and functions with such feature gates in their body would have the code guarded by these gates removed in test builds for tests in other packages. Closes #12494 --- Cargo.lock | 8 ++++++++ Cargo.toml | 2 ++ crates/feature-flags/Cargo.toml | 13 +++++++++++++ .../feature-flags/src/lib.rs | 10 ++++------ src/bin/fish.rs | 6 +++--- src/builtins/fish_indent.rs | 3 +-- src/builtins/fish_key_reader.rs | 3 +-- src/builtins/status.rs | 2 +- src/builtins/string/match.rs | 2 +- src/builtins/string/replace.rs | 2 +- src/builtins/test.rs | 2 +- src/common.rs | 2 +- src/expand.rs | 2 +- src/highlight/highlight.rs | 4 ++-- src/input_common.rs | 2 +- src/key.rs | 2 +- src/lib.rs | 1 - src/parse_util.rs | 2 +- src/reader/reader.rs | 4 ++-- src/terminal.rs | 10 +++++----- src/tokenizer.rs | 2 +- src/wildcard.rs | 5 ++--- 22 files changed, 53 insertions(+), 36 deletions(-) create mode 100644 crates/feature-flags/Cargo.toml rename src/future_feature_flags.rs => crates/feature-flags/src/lib.rs (98%) diff --git a/Cargo.lock b/Cargo.lock index d84df332f..b4951608a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -272,6 +272,7 @@ dependencies = [ "fish-color", "fish-common", "fish-fallback", + "fish-feature-flags", "fish-gettext", "fish-gettext-extraction", "fish-gettext-mo-file-parser", @@ -348,6 +349,13 @@ dependencies = [ "widestring", ] +[[package]] +name = "fish-feature-flags" +version = "0.0.0" +dependencies = [ + "fish-widestring", +] + [[package]] name = "fish-gettext" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index 100804797..90444640c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ fish-build-man-pages = { path = "crates/build-man-pages" } fish-color = { path = "crates/color" } fish-common = { path = "crates/common" } fish-fallback = { path = "crates/fallback" } +fish-feature-flags = { path = "crates/feature-flags" } fish-gettext = { path = "crates/gettext" } fish-gettext-extraction = { path = "crates/gettext-extraction" } fish-gettext-maps = { path = "crates/gettext-maps" } @@ -108,6 +109,7 @@ fish-build-man-pages = { workspace = true, optional = true } fish-color.workspace = true fish-common.workspace = true fish-fallback.workspace = true +fish-feature-flags.workspace = true fish-gettext = { workspace = true, optional = true } fish-gettext-extraction = { workspace = true, optional = true } fish-printf.workspace = true diff --git a/crates/feature-flags/Cargo.toml b/crates/feature-flags/Cargo.toml new file mode 100644 index 000000000..08ac463c1 --- /dev/null +++ b/crates/feature-flags/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "fish-feature-flags" +edition.workspace = true +rust-version.workspace = true +version = "0.0.0" +repository.workspace = true +license.workspace = true + +[dependencies] +fish-widestring.workspace = true + +[lints] +workspace = true diff --git a/src/future_feature_flags.rs b/crates/feature-flags/src/lib.rs similarity index 98% rename from src/future_feature_flags.rs rename to crates/feature-flags/src/lib.rs index 942211b52..b5da6c693 100644 --- a/src/future_feature_flags.rs +++ b/crates/feature-flags/src/lib.rs @@ -1,9 +1,10 @@ //! Flags to enable upcoming features use fish_widestring::{L, WExt as _, wstr}; -#[cfg(test)] -use std::cell::RefCell; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::{ + cell::RefCell, + sync::atomic::{AtomicBool, Ordering}, +}; /// The list of flags. #[repr(u8)] @@ -154,7 +155,6 @@ pub struct FeatureMetadata { ]; thread_local!( - #[cfg(test)] static LOCAL_OVERRIDE_STACK: RefCell> = const { RefCell::new(Vec::new()) }; ); @@ -164,7 +164,6 @@ pub struct FeatureMetadata { /// Perform a feature test on the global set of features. pub fn feature_test(flag: FeatureFlag) -> bool { - #[cfg(test)] if let Some(value) = LOCAL_OVERRIDE_STACK.with(|stack| { for &(overridden_feature, value) in stack.borrow().iter().rev() { if flag == overridden_feature { @@ -254,7 +253,6 @@ fn set_from_string(&self, str: &wstr) { /// Run code with a feature overridden. /// This should only be used in tests. -#[cfg(test)] pub fn with_overridden_feature(flag: FeatureFlag, value: bool, test_fn: impl FnOnce()) { LOCAL_OVERRIDE_STACK.with(|stack| { stack.borrow_mut().push((flag, value)); diff --git a/src/bin/fish.rs b/src/bin/fish.rs index 229872c90..f34e02faf 100644 --- a/src/bin/fish.rs +++ b/src/bin/fish.rs @@ -38,7 +38,7 @@ eprintf, event::{self, Event}, flog::{self, activate_flog_categories_by_pattern, flog, flogf, set_flog_file_fd}, - fprintf, function, future_feature_flags as features, + fprintf, function, history::{self, start_private_mode}, io::IoChain, locale::set_libc_locales, @@ -482,10 +482,10 @@ fn throwing_main() -> i32 { // command line takes precedence). if let Some(features_var) = EnvStack::globals().get(L!("fish_features")) { for s in features_var.as_list() { - features::set_from_string(s.as_utfstr()); + fish_feature_flags::set_from_string(s.as_utfstr()); } } - features::set_from_string(opts.features.as_utfstr()); + fish_feature_flags::set_from_string(opts.features.as_utfstr()); proc_init(); reader_init(true); diff --git a/src/builtins/fish_indent.rs b/src/builtins/fish_indent.rs index c9d8d63f0..7d8e088db 100644 --- a/src/builtins/fish_indent.rs +++ b/src/builtins/fish_indent.rs @@ -20,7 +20,6 @@ use crate::env::env_init; use crate::env::environment::Environment as _; use crate::expand::INTERNAL_SEPARATOR; -use crate::future_feature_flags; use crate::global_safety::RelaxedAtomicBool; use crate::highlight::{HighlightRole, HighlightSpec, colorize, highlight_shell}; use crate::operation_context::OperationContext; @@ -945,7 +944,7 @@ fn throwing_main() -> i32 { // Only set these here so you can't set them via the builtin. if let Some(features_var) = EnvStack::globals().get(L!("fish_features")) { for s in features_var.as_list() { - future_feature_flags::set_from_string(s.as_utfstr()); + fish_feature_flags::set_from_string(s.as_utfstr()); } } diff --git a/src/builtins/fish_key_reader.rs b/src/builtins/fish_key_reader.rs index d8c202425..a6e12232a 100644 --- a/src/builtins/fish_key_reader.rs +++ b/src/builtins/fish_key_reader.rs @@ -15,7 +15,6 @@ builtins::shared::BUILTIN_ERR_UNKNOWN_OPT, common::{PROGRAM_NAME, get_program_name, osstr2wcstring, shell_modes}, env::{EnvStack, Environment as _, env_init}, - future_feature_flags, input_common::{ CharEvent, ImplicitEvent, InputEventQueue, InputEventQueuer as _, KeyEvent, QueryResultEvent, match_key_event_to_key, @@ -295,7 +294,7 @@ fn throwing_main() -> i32 { reader_init(false); if let Some(features_var) = EnvStack::globals().get(L!("fish_features")) { for s in features_var.as_list() { - future_feature_flags::set_from_string(s.as_utfstr()); + fish_feature_flags::set_from_string(s.as_utfstr()); } } diff --git a/src/builtins/status.rs b/src/builtins/status.rs index a8f37510a..a58ad4340 100644 --- a/src/builtins/status.rs +++ b/src/builtins/status.rs @@ -1,7 +1,6 @@ use super::prelude::*; use crate::common::{bytes2wcstring, get_program_name, osstr2wcstring, str2wcstring}; use crate::env::config_paths::get_fish_path; -use crate::future_feature_flags::{self as features, feature_test}; use crate::proc::{ JobControl, get_job_control_mode, get_login, is_interactive_session, set_job_control_mode, }; @@ -9,6 +8,7 @@ use crate::tty_handoff::{TERMINAL_OS_NAME, get_scroll_content_up_capability, xtversion}; use crate::wutil::{Error, waccess, wbasename, wdirname, wrealpath}; use cfg_if::cfg_if; +use fish_feature_flags::{self as features, feature_test}; use fish_util::wcsfilecmp_glob; use fish_wcstringutil::wcs2bytes; use nix::unistd::AccessFlags; diff --git a/src/builtins/string/match.rs b/src/builtins/string/match.rs index 72dfd3a9c..8f339c9b6 100644 --- a/src/builtins/string/match.rs +++ b/src/builtins/string/match.rs @@ -414,9 +414,9 @@ fn report_matches(&mut self, arg: &wstr, streams: &mut IoStreams) { #[cfg(test)] mod tests { use crate::builtins::shared::{STATUS_CMD_ERROR, STATUS_CMD_OK, STATUS_INVALID_ARGS}; - use crate::future_feature_flags::{FeatureFlag, with_overridden_feature}; use crate::tests::prelude::*; use crate::validate; + use fish_feature_flags::{FeatureFlag, with_overridden_feature}; #[test] #[serial] diff --git a/src/builtins/string/replace.rs b/src/builtins/string/replace.rs index ed2210aaf..459d4f626 100644 --- a/src/builtins/string/replace.rs +++ b/src/builtins/string/replace.rs @@ -3,7 +3,7 @@ use pcre2::utf32::{Regex, RegexBuilder}; use super::*; -use crate::future_feature_flags::{FeatureFlag, feature_test}; +use fish_feature_flags::{FeatureFlag, feature_test}; #[derive(Default)] pub struct Replace<'args> { diff --git a/src/builtins/test.rs b/src/builtins/test.rs index 13d3f14e4..4b40b8123 100644 --- a/src/builtins/test.rs +++ b/src/builtins/test.rs @@ -1,6 +1,6 @@ use super::prelude::*; -use crate::future_feature_flags::{FeatureFlag, feature_test}; use crate::should_flog; +use fish_feature_flags::{FeatureFlag, feature_test}; mod test_expressions { use nix::unistd::{AccessFlags, Gid, Uid}; diff --git a/src/common.rs b/src/common.rs index 6bc53f0d5..8eb4bb5cd 100644 --- a/src/common.rs +++ b/src/common.rs @@ -4,7 +4,6 @@ BRACE_BEGIN, BRACE_END, BRACE_SEP, BRACE_SPACE, HOME_DIRECTORY, INTERNAL_SEPARATOR, PROCESS_EXPAND_SELF, PROCESS_EXPAND_SELF_STR, VARIABLE_EXPAND, VARIABLE_EXPAND_SINGLE, }; -use crate::future_feature_flags::{FeatureFlag, feature_test}; use crate::global_safety::AtomicRef; use crate::global_safety::RelaxedAtomicBool; use crate::key; @@ -15,6 +14,7 @@ use crate::wildcard::{ANY_CHAR, ANY_STRING, ANY_STRING_RECURSIVE}; use crate::wutil::fish_iswalnum; use fish_fallback::fish_wcwidth; +use fish_feature_flags::{FeatureFlag, feature_test}; use fish_wcstringutil::wcs2bytes; use fish_widestring::{ ENCODE_DIRECT_END, decode_byte_from_char, encode_byte_to_char, subslice_position, diff --git a/src/expand.rs b/src/expand.rs index 392f3b312..74cb5ea1c 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -14,7 +14,6 @@ use crate::complete::{CompleteFlags, Completion, CompletionList, CompletionReceiver}; use crate::env::{EnvVar, Environment}; use crate::exec::exec_subshell_for_expand; -use crate::future_feature_flags::{FeatureFlag, feature_test}; use crate::history::{History, history_session_id}; use crate::operation_context::OperationContext; use crate::parse_constants::{ParseError, ParseErrorCode, ParseErrorList, SOURCE_LOCATION_UNKNOWN}; @@ -26,6 +25,7 @@ use crate::wutil::{Options, normalize_path, wcstoi_partial}; use bitflags::bitflags; use fish_common::{EXPAND_RESERVED_BASE, EXPAND_RESERVED_END}; +use fish_feature_flags::{FeatureFlag, feature_test}; use fish_util::wcsfilecmp_glob; use fish_wcstringutil::{join_strings, trim}; use fish_widestring::char_offset; diff --git a/src/highlight/highlight.rs b/src/highlight/highlight.rs index 10c9105ad..c95593099 100644 --- a/src/highlight/highlight.rs +++ b/src/highlight/highlight.rs @@ -12,7 +12,6 @@ ExpandFlags, ExpandResultCode, PROCESS_EXPAND_SELF_STR, expand_one, expand_to_command_and_args, }; use crate::function; -use crate::future_feature_flags::{FeatureFlag, feature_test}; use crate::highlight::file_tester::FileTester; use crate::history::all_paths_are_valid; use crate::operation_context::OperationContext; @@ -31,6 +30,7 @@ use crate::tokenizer::{PipeOrRedir, variable_assignment_equals_pos}; use fish_color::Color; use fish_common::{ASCII_MAX, EXPAND_RESERVED_BASE, EXPAND_RESERVED_END}; +use fish_feature_flags::{FeatureFlag, feature_test}; use fish_wcstringutil::string_prefixes_string; use fish_widestring::{L, WExt as _, WString, wstr}; use std::collections::HashMap; @@ -1314,12 +1314,12 @@ mod tests { use super::{HighlightColorResolver, HighlightRole, HighlightSpec, highlight_shell}; use crate::common::ScopeGuard; use crate::env::{EnvMode, EnvSetMode, EnvVar, EnvVarFlags, Environment as _}; - use crate::future_feature_flags::{FeatureFlag, with_overridden_feature}; use crate::highlight::parse_text_face_for_highlight; use crate::operation_context::{EXPANSION_LIMIT_BACKGROUND, OperationContext}; use crate::prelude::*; use crate::tests::prelude::*; use crate::text_face::{ResettableStyle, UnderlineStyle}; + use fish_feature_flags::{FeatureFlag, with_overridden_feature}; use libc::PATH_MAX; // Helper to return a string whose length greatly exceeds PATH_MAX. diff --git a/src/input_common.rs b/src/input_common.rs index 82e099c2c..0ce9944b2 100644 --- a/src/input_common.rs +++ b/src/input_common.rs @@ -5,7 +5,6 @@ use crate::env::{EnvStack, Environment as _}; use crate::fd_readable_set::{FdReadableSet, Timeout}; use crate::flog::{FloggableDebug, FloggableDisplay, flog}; -use crate::future_feature_flags::{FeatureFlag, feature_test}; use crate::key::{ self, Key, Modifiers, ViewportPosition, alt, canonicalize_control_char, canonicalize_keyed_control_char, char_to_symbol, function_key, shift, @@ -18,6 +17,7 @@ }; use crate::universal_notifier::default_notifier; use crate::wutil::{fish_is_pua, fish_wcstol}; +use fish_feature_flags::{FeatureFlag, feature_test}; use fish_widestring::encode_byte_to_char; use nix::sys::{select::FdSet, signal::SigSet, time::TimeSpec}; use std::cell::{RefCell, RefMut}; diff --git a/src/key.rs b/src/key.rs index 4dc1b36f5..fe08a73f7 100644 --- a/src/key.rs +++ b/src/key.rs @@ -3,12 +3,12 @@ use crate::{ common::{EscapeFlags, EscapeStringStyle, escape_string}, flog::FloggableDebug, - future_feature_flags::{FeatureFlag, feature_test}, prelude::*, reader::safe_get_terminal_mode_on_startup, wutil::fish_wcstoul, }; use fish_fallback::fish_wcwidth; +use fish_feature_flags::{FeatureFlag, feature_test}; use fish_widestring::decode_byte_from_char; pub(crate) const Backspace: char = '\u{F500}'; // below ENCODE_DIRECT_BASE diff --git a/src/lib.rs b/src/lib.rs index 84e8c7016..7e88e3d35 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,6 @@ pub mod fork_exec; pub mod fs; pub mod function; -pub mod future_feature_flags; pub mod global_safety; pub mod highlight; pub mod history; diff --git a/src/parse_util.rs b/src/parse_util.rs index 227957049..ee8d9afd5 100644 --- a/src/parse_util.rs +++ b/src/parse_util.rs @@ -13,7 +13,6 @@ VARIABLE_EXPAND, VARIABLE_EXPAND_EMPTY, VARIABLE_EXPAND_SINGLE, expand_one, expand_to_command_and_args, }; -use crate::future_feature_flags::{FeatureFlag, feature_test}; use crate::operation_context::OperationContext; use crate::parse_constants::{ ERROR_BAD_VAR_CHAR1, ERROR_BRACKETED_VARIABLE_QUOTED1, ERROR_BRACKETED_VARIABLE1, @@ -30,6 +29,7 @@ }; use crate::wildcard::{ANY_CHAR, ANY_STRING, ANY_STRING_RECURSIVE}; use fish_common::help_section; +use fish_feature_flags::{FeatureFlag, feature_test}; use fish_wcstringutil::{count_newlines, truncate}; use std::ops::Range; use std::{iter, ops}; diff --git a/src/reader/reader.rs b/src/reader/reader.rs index b457bc048..abc47c587 100644 --- a/src/reader/reader.rs +++ b/src/reader/reader.rs @@ -46,7 +46,6 @@ use crate::fd_readable_set::poll_fd_readable; use crate::fds::{make_fd_blocking, wopen_cloexec}; use crate::flog::{flog, flogf}; -use crate::future_feature_flags::{self, FeatureFlag}; use crate::global_safety::RelaxedAtomicBool; use crate::highlight::{ HighlightRole, HighlightSpec, autosuggest_validate_from_history, highlight_shell, @@ -121,6 +120,7 @@ use fish_common::{UTF8_BOM_WCHAR, help_section}; use fish_fallback::fish_wcwidth; use fish_fallback::lowercase; +use fish_feature_flags::FeatureFlag; use fish_util::{perror, write_to_fd}; use fish_wcstringutil::{ CaseSensitivity, IsPrefix, StringFuzzyMatch, count_preceding_backslashes, is_prefix, @@ -239,7 +239,7 @@ fn redirect_tty_after_sighup() { } fn querying_allowed(vars: &dyn Environment) -> bool { - future_feature_flags::feature_test(FeatureFlag::QueryTerm) + fish_feature_flags::feature_test(FeatureFlag::QueryTerm) && !is_dumb() && { // TODO(term-workaround) diff --git a/src/terminal.rs b/src/terminal.rs index 529fe156b..d2588530a 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -1,12 +1,12 @@ // Generic output functions. use crate::common::{self, EscapeStringStyle, escape_string}; -use crate::future_feature_flags::{self, FeatureFlag}; use crate::prelude::*; use crate::screen::{is_dumb, only_grayscale}; use crate::text_face::{ResettableStyle, TextFace, TextStyling, UnderlineStyle}; use crate::threads::MainThread; use bitflags::bitflags; use fish_color::{Color, Color24}; +use fish_feature_flags::FeatureFlag; use fish_wcstringutil::{wcs2bytes, wcs2bytes_appending}; use std::cell::{RefCell, RefMut}; use std::ops::{Deref, DerefMut}; @@ -181,7 +181,7 @@ fn osc_0_or_1_terminal_title(out: &mut Outputter, is_1: bool, title: &[WString]) } fn osc_133_prompt_start(out: &mut Outputter) -> bool { - if !future_feature_flags::feature_test(FeatureFlag::MarkPrompt) { + if !fish_feature_flags::feature_test(FeatureFlag::MarkPrompt) { return false; } static TEST_BALLOON: OnceLock<()> = OnceLock::new(); @@ -194,7 +194,7 @@ fn osc_133_prompt_start(out: &mut Outputter) -> bool { } fn osc_133_prompt_end(out: &mut Outputter) -> bool { - if !future_feature_flags::feature_test(FeatureFlag::MarkPrompt) { + if !fish_feature_flags::feature_test(FeatureFlag::MarkPrompt) { return false; } write_to_output!(out, "\x1b]133;B\x07"); @@ -202,7 +202,7 @@ fn osc_133_prompt_end(out: &mut Outputter) -> bool { } fn osc_133_command_start(out: &mut Outputter, command: &wstr) -> bool { - if !future_feature_flags::feature_test(FeatureFlag::MarkPrompt) { + if !fish_feature_flags::feature_test(FeatureFlag::MarkPrompt) { return false; } write_to_output!( @@ -214,7 +214,7 @@ fn osc_133_command_start(out: &mut Outputter, command: &wstr) -> bool { } fn osc_133_command_finished(out: &mut Outputter, exit_status: libc::c_int) -> bool { - if !future_feature_flags::feature_test(FeatureFlag::MarkPrompt) { + if !fish_feature_flags::feature_test(FeatureFlag::MarkPrompt) { return false; } write_to_output!(out, "\x1b]133;D;{}\x07", exit_status); diff --git a/src/tokenizer.rs b/src/tokenizer.rs index e3f9e62e3..16a028564 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -3,11 +3,11 @@ use crate::ast::unescape_keyword; use crate::common::valid_var_name_char; -use crate::future_feature_flags::{FeatureFlag, feature_test}; use crate::parse_constants::SOURCE_OFFSET_INVALID; use crate::parser_keywords::parser_keywords_is_subcommand; use crate::prelude::*; use crate::redirection::RedirectionMode; +use fish_feature_flags::{FeatureFlag, feature_test}; use libc::{STDIN_FILENO, STDOUT_FILENO}; use nix::fcntl::OFlag; use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not, Range}; diff --git a/src/wildcard.rs b/src/wildcard.rs index 33466ed59..d511acfbb 100644 --- a/src/wildcard.rs +++ b/src/wildcard.rs @@ -13,12 +13,11 @@ }; use crate::complete::{CompleteFlags, Completion, CompletionReceiver, PROG_COMPLETE_SEP}; use crate::expand::ExpandFlags; -use crate::future_feature_flags::FeatureFlag; -use crate::future_feature_flags::feature_test; use crate::prelude::*; use crate::wutil::dir_iter::DirEntryType; use crate::wutil::{dir_iter::DirEntry, lwstat, waccess}; use fish_fallback::wcscasecmp; +use fish_feature_flags::{FeatureFlag, feature_test}; use fish_wcstringutil::{ CaseSensitivity, string_fuzzy_match_string, string_suffixes_string_case_insensitive, strip_executable_suffix, @@ -1231,7 +1230,7 @@ pub fn wildcard_has(s: impl AsRef) -> bool { #[cfg(test)] mod tests { use super::*; - use crate::future_feature_flags::with_overridden_feature; + use fish_feature_flags::with_overridden_feature; #[test] fn test_wildcards() {