mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-01 04:41:14 -03:00
Compare commits
9 Commits
f3f675b4cc
...
d2653b7cac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2653b7cac | ||
|
|
cf16949ce7 | ||
|
|
85311546de | ||
|
|
c44aa32a15 | ||
|
|
65bc9b9e3e | ||
|
|
8125f78a84 | ||
|
|
f0f48b4859 | ||
|
|
a009f87630 | ||
|
|
edb66d4d4e |
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Script to generate the dput.cf for a set of Ubuntu series, prints the filename
|
||||
# Arguments are the PPA followed by the series names
|
||||
|
||||
set -e
|
||||
|
||||
outfile=$(mktemp --tmpdir dput.XXXXX.cf)
|
||||
|
||||
[ $# -lt 2 ] &&
|
||||
echo "$0: at least two arguments (a PPA and at least one series) are required" >&2 &&
|
||||
exit 1
|
||||
|
||||
ppa=$1
|
||||
shift
|
||||
|
||||
for series in "$@"; do
|
||||
cat >> "$outfile" <<EOF
|
||||
[fish-$ppa-$series]
|
||||
fqdn = ppa.launchpad.net
|
||||
method = ftp
|
||||
login = anonymous
|
||||
incoming = ~fish-shell/$ppa/ubuntu/$series
|
||||
|
||||
EOF
|
||||
done
|
||||
|
||||
echo "$outfile"
|
||||
83
build_tools/make_linux_packages.sh
Executable file
83
build_tools/make_linux_packages.sh
Executable file
@@ -0,0 +1,83 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script takes a source tarball (from build_tools/make_tarball.sh) and a vendor tarball (from
|
||||
# build_tools/make_vendor_tarball.sh, generated if not present), and produces:
|
||||
# * Appropriately-named symlinks to look like a Debian package
|
||||
# * Debian .changes and .dsc files with plain names ($version-1) and supported Ubuntu prefixes
|
||||
# ($version-1~somedistro)
|
||||
# * An RPM spec file
|
||||
# By default, input and output files go in ~/fish_built, but this can be controlled with the
|
||||
# FISH_ARTEFACT_PATH environment variable.
|
||||
|
||||
{
|
||||
|
||||
set -e
|
||||
|
||||
version=$1
|
||||
[ -n "$version" ] || { echo "Version number required as argument" >&2; exit 1; }
|
||||
|
||||
|
||||
[ -n "$DEB_SIGN_KEYID$DEB_SIGN_KEYFILE" ] ||
|
||||
echo "Warning: neither DEB_SIGN_KEYID or DEB_SIGN_KEYFILE environment variables are set; you
|
||||
will need a signing key for the author of the most recent debian/changelog entry." >&2
|
||||
|
||||
workpath=${FISH_ARTEFACT_PATH:-~/fish_built}
|
||||
source_tarball="$workpath"/fish-"$version".tar.xz
|
||||
vendor_tarball="$workpath"/fish-"$version"-vendor.tar.xz
|
||||
|
||||
[ -e "$source_tarball" ] || { echo "Missing source tarball, expected at $source_tarball" >&2; exit 1; }
|
||||
cd "$workpath"
|
||||
|
||||
# Unpack the sources
|
||||
tar xf "$source_tarball"
|
||||
sourcepath="$workpath"/fish-"$version"
|
||||
|
||||
# Generate the vendor tarball if it is not already present
|
||||
[ -e "$vendor_tarball" ] || (cd "$sourcepath"; build_tools/make_vendor_tarball.sh;)
|
||||
|
||||
# This step requires network access, so do it early in case it fails
|
||||
# sh has no real array support
|
||||
ubuntu_versions=$(uv run --script "$sourcepath"/build_tools/supported_ubuntu_versions.py)
|
||||
|
||||
# Write the specfile
|
||||
[ -e "$workpath"/fish.spec ] && { echo "Cowardly refusing to overwite an existing fish.spec" >&2;
|
||||
exit 1; }
|
||||
rpmversion=$(echo "$version" |sed -e 's/-/+/' -e 's/-/./g')
|
||||
sed -e "s/@version@/$version/g" -e "s/@rpmversion@/$rpmversion/g" \
|
||||
< "$sourcepath"/fish.spec.in > "$workpath"/fish.spec
|
||||
|
||||
# Make the symlinks for Debian
|
||||
ln -s "$source_tarball" "$workpath"/fish_"$version".orig.tar.xz
|
||||
ln -s "$vendor_tarball" "$workpath"/fish_"$version".orig-cargo-vendor.tar.xz
|
||||
|
||||
# Set up the Debian source tree
|
||||
cd "$sourcepath"
|
||||
mkdir cargo-vendor
|
||||
tar -C cargo-vendor -x -f "$vendor_tarball"
|
||||
cp -r contrib/debian debian
|
||||
|
||||
# The vendor tarball contains a new .cargo/config.toml, which has the
|
||||
# vendoring overrides appended to it. dpkg-source will add this as a
|
||||
# patch using the flags in debian/
|
||||
cp cargo-vendor/.cargo/config.toml .cargo/config.toml
|
||||
|
||||
# Update the Debian changelog
|
||||
# The release scripts do this for release builds - skip if it has already been done
|
||||
if head -n1 debian/changelog | grep --invert-match --quiet --fixed-strings "$version"; then
|
||||
debchange --newversion "$version-1" --distribution unstable "Snapshot build"
|
||||
fi
|
||||
|
||||
# Builds the "plain" Debian package
|
||||
# debuild runs lintian, which takes ten minutes to run over the vendor directories
|
||||
# just use dpkg-buildpackage directly
|
||||
dpkg-buildpackage --build=source -d
|
||||
|
||||
# Build the Ubuntu packages
|
||||
# deb-reversion does not work on source packages, so do the whole thing ourselves
|
||||
for series in $ubuntu_versions; do
|
||||
sed -i -e "1 s/$version-1)/$version-1~$series)/" -e "1 s/unstable/$series/" debian/changelog
|
||||
dpkg-buildpackage --build=source -d
|
||||
sed -i -e "1 s/$version-1~$series)/$version-1)/" -e "1 s/$series/unstable/" debian/changelog
|
||||
done
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@ Build-Depends: debhelper-compat (= 13),
|
||||
python3-sphinx,
|
||||
# Test dependencies
|
||||
locales-all,
|
||||
man-db | mandoc | man,
|
||||
man-db | man,
|
||||
python3
|
||||
# 4.6.2 is Debian 12/Ubuntu Noble 24.04; Ubuntu Jammy is 4.6.0.1
|
||||
Standards-Version: 4.6.2
|
||||
@@ -27,7 +27,7 @@ Architecture: any
|
||||
Depends: bsdextrautils,
|
||||
file,
|
||||
# for showing built-in help pages
|
||||
man-db | mandoc | man,
|
||||
man-db | man,
|
||||
# for kill
|
||||
procps,
|
||||
python3 (>=3.5),
|
||||
|
||||
13
crates/feature-flags/Cargo.toml
Normal file
13
crates/feature-flags/Cargo.toml
Normal file
@@ -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
|
||||
@@ -1,15 +1,14 @@
|
||||
//! Flags to enable upcoming features
|
||||
|
||||
use crate::prelude::*;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
#[cfg(test)]
|
||||
use std::cell::RefCell;
|
||||
use fish_widestring::{L, WExt as _, wstr};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
|
||||
/// The list of flags.
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum FeatureFlag {
|
||||
/// Whether ^ is supported for stderr redirection.
|
||||
StderrNoCaret,
|
||||
@@ -63,10 +62,10 @@ pub struct FeatureMetadata {
|
||||
pub description: &'static wstr,
|
||||
|
||||
/// Default flag value.
|
||||
pub default_value: bool,
|
||||
default_value: bool,
|
||||
|
||||
/// Whether the value can still be changed or not.
|
||||
pub read_only: bool,
|
||||
read_only: bool,
|
||||
}
|
||||
|
||||
/// The metadata, indexed by flag.
|
||||
@@ -156,31 +155,26 @@ pub struct FeatureMetadata {
|
||||
];
|
||||
|
||||
thread_local!(
|
||||
#[cfg(test)]
|
||||
static LOCAL_FEATURES: RefCell<Option<Features>> = const { RefCell::new(None) };
|
||||
static LOCAL_OVERRIDE_STACK: RefCell<Vec<(FeatureFlag, bool)>> =
|
||||
const { RefCell::new(Vec::new()) };
|
||||
);
|
||||
|
||||
/// The singleton shared feature set.
|
||||
static FEATURES: Features = Features::new();
|
||||
|
||||
/// Perform a feature test on the global set of features.
|
||||
pub fn test(flag: FeatureFlag) -> bool {
|
||||
#[cfg(test)]
|
||||
{
|
||||
LOCAL_FEATURES.with(|fc| fc.borrow().as_ref().unwrap_or(&FEATURES).test(flag))
|
||||
pub fn feature_test(flag: FeatureFlag) -> bool {
|
||||
if let Some(value) = LOCAL_OVERRIDE_STACK.with(|stack| {
|
||||
for &(overridden_feature, value) in stack.borrow().iter().rev() {
|
||||
if flag == overridden_feature {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
None
|
||||
}) {
|
||||
return value;
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
FEATURES.test(flag)
|
||||
}
|
||||
}
|
||||
|
||||
pub use test as feature_test;
|
||||
|
||||
/// Set a flag.
|
||||
#[cfg(test)]
|
||||
pub fn set(flag: FeatureFlag, value: bool) {
|
||||
LOCAL_FEATURES.with(|fc| fc.borrow().as_ref().unwrap_or(&FEATURES).set(flag, value));
|
||||
FEATURES.test(flag)
|
||||
}
|
||||
|
||||
/// Parses a comma-separated feature-flag string, updating ourselves with the values.
|
||||
@@ -188,20 +182,7 @@ pub fn set(flag: FeatureFlag, value: bool) {
|
||||
/// The special group name "all" may be used for those who like to live on the edge.
|
||||
/// Unknown features are silently ignored.
|
||||
pub fn set_from_string<'a>(str: impl Into<&'a wstr>) {
|
||||
let wstr: &wstr = str.into();
|
||||
#[cfg(test)]
|
||||
{
|
||||
LOCAL_FEATURES.with(|fc| {
|
||||
fc.borrow()
|
||||
.as_ref()
|
||||
.unwrap_or(&FEATURES)
|
||||
.set_from_string(wstr);
|
||||
});
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
FEATURES.set_from_string(wstr);
|
||||
}
|
||||
FEATURES.set_from_string(str.into());
|
||||
}
|
||||
|
||||
impl Features {
|
||||
@@ -270,28 +251,20 @@ fn set_from_string(&self, str: &wstr) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn scoped_test(flag: FeatureFlag, value: bool, test_fn: impl FnOnce()) {
|
||||
LOCAL_FEATURES.with(|fc| {
|
||||
assert!(
|
||||
fc.borrow().is_none(),
|
||||
"scoped_test() does not support nesting"
|
||||
);
|
||||
|
||||
let f = Features::new();
|
||||
f.set(flag, value);
|
||||
*fc.borrow_mut() = Some(f);
|
||||
|
||||
/// Run code with a feature overridden.
|
||||
/// This should only be used in tests.
|
||||
pub fn with_overridden_feature(flag: FeatureFlag, value: bool, test_fn: impl FnOnce()) {
|
||||
LOCAL_OVERRIDE_STACK.with(|stack| {
|
||||
stack.borrow_mut().push((flag, value));
|
||||
test_fn();
|
||||
|
||||
*fc.borrow_mut() = None;
|
||||
stack.borrow_mut().pop();
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{FeatureFlag, Features, METADATA, scoped_test, set, test};
|
||||
use crate::prelude::*;
|
||||
use super::{FeatureFlag, Features, METADATA, feature_test, with_overridden_feature};
|
||||
use fish_widestring::L;
|
||||
|
||||
#[test]
|
||||
fn test_feature_flags() {
|
||||
@@ -317,25 +290,19 @@ fn test_feature_flags() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scoped() {
|
||||
scoped_test(FeatureFlag::QuestionMarkNoGlob, true, || {
|
||||
assert!(test(FeatureFlag::QuestionMarkNoGlob));
|
||||
fn test_overridden_feature() {
|
||||
with_overridden_feature(FeatureFlag::QuestionMarkNoGlob, true, || {
|
||||
assert!(feature_test(FeatureFlag::QuestionMarkNoGlob));
|
||||
});
|
||||
|
||||
set(FeatureFlag::QuestionMarkNoGlob, true);
|
||||
|
||||
scoped_test(FeatureFlag::QuestionMarkNoGlob, false, || {
|
||||
assert!(!test(FeatureFlag::QuestionMarkNoGlob));
|
||||
with_overridden_feature(FeatureFlag::QuestionMarkNoGlob, false, || {
|
||||
assert!(!feature_test(FeatureFlag::QuestionMarkNoGlob));
|
||||
});
|
||||
|
||||
set(FeatureFlag::QuestionMarkNoGlob, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_nested_scopes_not_supported() {
|
||||
scoped_test(FeatureFlag::QuestionMarkNoGlob, true, || {
|
||||
scoped_test(FeatureFlag::QuestionMarkNoGlob, false, || {});
|
||||
with_overridden_feature(FeatureFlag::QuestionMarkNoGlob, false, || {
|
||||
with_overridden_feature(FeatureFlag::QuestionMarkNoGlob, true, || {
|
||||
assert!(feature_test(FeatureFlag::QuestionMarkNoGlob));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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, scoped_test};
|
||||
use crate::tests::prelude::*;
|
||||
use crate::validate;
|
||||
use fish_feature_flags::{FeatureFlag, with_overridden_feature};
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
@@ -487,7 +487,7 @@ fn plain() {
|
||||
#[serial]
|
||||
#[rustfmt::skip]
|
||||
fn test_qmark_noglob_true() {
|
||||
scoped_test(FeatureFlag::QuestionMarkNoGlob, true, || {
|
||||
with_overridden_feature(FeatureFlag::QuestionMarkNoGlob, true, || {
|
||||
validate!(["string", "match", "a*b?c", "axxb?c"], STATUS_CMD_OK, "axxb?c\n");
|
||||
validate!(["string", "match", "*?", "a"], STATUS_CMD_ERROR, "");
|
||||
validate!(["string", "match", "*?", "ab"], STATUS_CMD_ERROR, "");
|
||||
@@ -515,7 +515,7 @@ fn test_qmark_noglob_true() {
|
||||
#[serial]
|
||||
#[rustfmt::skip]
|
||||
fn test_qmark_glob() {
|
||||
scoped_test(FeatureFlag::QuestionMarkNoGlob, false, || {
|
||||
with_overridden_feature(FeatureFlag::QuestionMarkNoGlob, false, || {
|
||||
validate!(["string", "match", "a*b?c", "axxbyc"], STATUS_CMD_OK, "axxbyc\n");
|
||||
validate!(["string", "match", "*?", "a"], STATUS_CMD_OK, "a\n");
|
||||
validate!(["string", "match", "*?", "ab"], STATUS_CMD_OK, "ab\n");
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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::{self, FeatureFlag};
|
||||
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.
|
||||
@@ -1418,404 +1418,400 @@ macro_rules! validate {
|
||||
let mut redirection_valid_path = HighlightSpec::with_fg(HighlightRole::redirection);
|
||||
redirection_valid_path.valid_path = true;
|
||||
|
||||
let saved_flag = future_feature_flags::test(FeatureFlag::AmpersandNoBgInToken);
|
||||
future_feature_flags::set(FeatureFlag::AmpersandNoBgInToken, true);
|
||||
let _restore_saved_flag = ScopeGuard::new((), |_| {
|
||||
future_feature_flags::set(FeatureFlag::AmpersandNoBgInToken, saved_flag);
|
||||
with_overridden_feature(FeatureFlag::AmpersandNoBgInToken, true, || {
|
||||
let fg = HighlightSpec::with_fg;
|
||||
|
||||
// Verify variables and wildcards in commands using /bin/cat.
|
||||
let vars = parser.vars();
|
||||
let local_mode = EnvSetMode::new_at_early_startup(EnvMode::LOCAL);
|
||||
vars.set_one(L!("CDPATH"), local_mode, L!("./cdpath-entry").to_owned());
|
||||
|
||||
// NOTE n, nv are suffix of /usr/bin/env
|
||||
vars.set_one(L!("VARIABLE_IN_COMMAND"), local_mode, L!("n").to_owned());
|
||||
vars.set_one(L!("VARIABLE_IN_COMMAND2"), local_mode, L!("nv").to_owned());
|
||||
|
||||
let _cleanup = ScopeGuard::new((), |_| {
|
||||
vars.remove(L!("VARIABLE_IN_COMMAND"), EnvSetMode::default());
|
||||
vars.remove(L!("VARIABLE_IN_COMMAND2"), EnvSetMode::default());
|
||||
});
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("./foo", param_valid_path),
|
||||
("&", fg(HighlightRole::statement_terminator)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("command", fg(HighlightRole::keyword)),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("abc", fg(HighlightRole::param)),
|
||||
("foo", param_valid_path),
|
||||
("&", fg(HighlightRole::statement_terminator)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("foo&bar", fg(HighlightRole::param)),
|
||||
("foo", fg(HighlightRole::param), ns),
|
||||
("&", fg(HighlightRole::statement_terminator)),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("&>", fg(HighlightRole::redirection)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("if command", fg(HighlightRole::keyword)),
|
||||
("ls", fg(HighlightRole::command)),
|
||||
("; ", fg(HighlightRole::statement_terminator)),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("abc", fg(HighlightRole::param)),
|
||||
("; ", fg(HighlightRole::statement_terminator)),
|
||||
("/bin/definitely_not_a_command", fg(HighlightRole::error)),
|
||||
("; ", fg(HighlightRole::statement_terminator)),
|
||||
("end", fg(HighlightRole::keyword)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("if", fg(HighlightRole::keyword)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("else", fg(HighlightRole::keyword)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("end", fg(HighlightRole::keyword)),
|
||||
);
|
||||
|
||||
// Verify that cd shows errors for non-directories.
|
||||
validate!(
|
||||
("cd", fg(HighlightRole::command)),
|
||||
("dir", param_valid_path),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("cd", fg(HighlightRole::command)),
|
||||
("foo", fg(HighlightRole::error)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("cd", fg(HighlightRole::command)),
|
||||
("--help", fg(HighlightRole::option)),
|
||||
("-h", fg(HighlightRole::option)),
|
||||
("definitely_not_a_directory", fg(HighlightRole::error)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("cd", fg(HighlightRole::command)),
|
||||
("dir-in-cdpath", param_valid_path),
|
||||
);
|
||||
|
||||
// Command substitutions.
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("param1", fg(HighlightRole::param)),
|
||||
("-l", fg(HighlightRole::option)),
|
||||
("--", fg(HighlightRole::option)),
|
||||
("-l", fg(HighlightRole::param)),
|
||||
("(", fg(HighlightRole::operat)),
|
||||
("ls", fg(HighlightRole::command)),
|
||||
("-l", fg(HighlightRole::option)),
|
||||
("--", fg(HighlightRole::option)),
|
||||
("-l", fg(HighlightRole::param)),
|
||||
("param2", fg(HighlightRole::param)),
|
||||
(")", fg(HighlightRole::operat)),
|
||||
("|", fg(HighlightRole::statement_terminator)),
|
||||
("cat", fg(HighlightRole::command)),
|
||||
);
|
||||
validate!(
|
||||
("true", fg(HighlightRole::command)),
|
||||
("$(", fg(HighlightRole::operat)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
(")", fg(HighlightRole::operat)),
|
||||
);
|
||||
validate!(
|
||||
("true", fg(HighlightRole::command)),
|
||||
("\"before", fg(HighlightRole::quote)),
|
||||
("$(", fg(HighlightRole::operat)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
("param1", fg(HighlightRole::param)),
|
||||
(")", fg(HighlightRole::operat)),
|
||||
("after\"", fg(HighlightRole::quote)),
|
||||
("param2", fg(HighlightRole::param)),
|
||||
);
|
||||
validate!(
|
||||
("true", fg(HighlightRole::command)),
|
||||
("\"", fg(HighlightRole::error)),
|
||||
("unclosed quote", fg(HighlightRole::quote)),
|
||||
("$(", fg(HighlightRole::operat)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
(")", fg(HighlightRole::operat)),
|
||||
);
|
||||
|
||||
// Redirections substitutions.
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("param1", fg(HighlightRole::param)),
|
||||
// Input redirection.
|
||||
("<", fg(HighlightRole::redirection)),
|
||||
("/dev/null", redirection_valid_path),
|
||||
// Output redirection to a valid fd.
|
||||
("1>&2", fg(HighlightRole::redirection)),
|
||||
// Output redirection to an invalid fd.
|
||||
("2>&", fg(HighlightRole::redirection)),
|
||||
("LO", fg(HighlightRole::error)),
|
||||
// Just a param, not a redirection.
|
||||
("test/blah", fg(HighlightRole::param)),
|
||||
// Input redirection from directory.
|
||||
("<", fg(HighlightRole::redirection)),
|
||||
("test/", fg(HighlightRole::error)),
|
||||
// Output redirection to an invalid path.
|
||||
("3>", fg(HighlightRole::redirection)),
|
||||
("/not/a/valid/path/nope", fg(HighlightRole::error)),
|
||||
// Output redirection to directory.
|
||||
("3>", fg(HighlightRole::redirection)),
|
||||
("test/nope/", fg(HighlightRole::error)),
|
||||
// Redirections to overflow fd.
|
||||
("99999999999999999999>&2", fg(HighlightRole::error)),
|
||||
("2>&", fg(HighlightRole::redirection)),
|
||||
("99999999999999999999", fg(HighlightRole::error)),
|
||||
// Output redirection containing a command substitution.
|
||||
("4>", fg(HighlightRole::redirection)),
|
||||
("(", fg(HighlightRole::operat)),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("test/somewhere", fg(HighlightRole::param)),
|
||||
(")", fg(HighlightRole::operat)),
|
||||
// Just another param.
|
||||
("param2", fg(HighlightRole::param)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("for", fg(HighlightRole::keyword)),
|
||||
("x", fg(HighlightRole::param)),
|
||||
("in", fg(HighlightRole::keyword)),
|
||||
("set-by-for-1", fg(HighlightRole::param)),
|
||||
("set-by-for-2", fg(HighlightRole::param)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
(">", fg(HighlightRole::redirection)),
|
||||
("$x", fg(HighlightRole::redirection)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("end", fg(HighlightRole::keyword)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("set", fg(HighlightRole::command)),
|
||||
("x", fg(HighlightRole::param)),
|
||||
("set-by-set", fg(HighlightRole::param)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
(">", fg(HighlightRole::redirection)),
|
||||
("$x", fg(HighlightRole::redirection)),
|
||||
("2>", fg(HighlightRole::redirection)),
|
||||
("$totally_not_x", fg(HighlightRole::error)),
|
||||
("<", fg(HighlightRole::redirection)),
|
||||
("$x_but_its_an_impostor", fg(HighlightRole::error)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("x", fg(HighlightRole::param), ns),
|
||||
("=", fg(HighlightRole::operat), ns),
|
||||
("set-by-variable-override", fg(HighlightRole::param), ns),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
(">", fg(HighlightRole::redirection)),
|
||||
("$x", fg(HighlightRole::redirection)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("end", fg(HighlightRole::error)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("if", fg(HighlightRole::keyword)),
|
||||
("end", fg(HighlightRole::error)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("'", fg(HighlightRole::error)),
|
||||
("single_quote", fg(HighlightRole::quote)),
|
||||
("$stuff", fg(HighlightRole::quote)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("\"", fg(HighlightRole::error)),
|
||||
("double_quote", fg(HighlightRole::quote)),
|
||||
("$stuff", fg(HighlightRole::operat)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("$foo", fg(HighlightRole::operat)),
|
||||
("\"", fg(HighlightRole::quote)),
|
||||
("$bar", fg(HighlightRole::operat)),
|
||||
("\"", fg(HighlightRole::quote)),
|
||||
("$baz[", fg(HighlightRole::operat)),
|
||||
("1 2..3", fg(HighlightRole::param)),
|
||||
("]", fg(HighlightRole::operat)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("for", fg(HighlightRole::keyword)),
|
||||
("i", fg(HighlightRole::param)),
|
||||
("in", fg(HighlightRole::keyword)),
|
||||
("1 2 3", fg(HighlightRole::param)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("end", fg(HighlightRole::keyword)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("$$foo[", fg(HighlightRole::operat)),
|
||||
("1", fg(HighlightRole::param)),
|
||||
("][", fg(HighlightRole::operat)),
|
||||
("2", fg(HighlightRole::param)),
|
||||
("]", fg(HighlightRole::operat)),
|
||||
("[3]", fg(HighlightRole::param)), // two dollar signs, so last one is not an expansion
|
||||
);
|
||||
|
||||
validate!(
|
||||
("cat", fg(HighlightRole::command)),
|
||||
("/dev/null", param_valid_path),
|
||||
("|", fg(HighlightRole::statement_terminator)),
|
||||
// This is bogus, but we used to use "less" here and that doesn't have to be installed.
|
||||
("cat", fg(HighlightRole::command)),
|
||||
("2>", fg(HighlightRole::redirection)),
|
||||
);
|
||||
|
||||
// Highlight path-prefixes only at the cursor.
|
||||
validate!(
|
||||
("cat", fg(HighlightRole::command)),
|
||||
("/dev/nu", fg(HighlightRole::param)),
|
||||
("/dev/nu", param_valid_path),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("if", fg(HighlightRole::keyword)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
("&&", fg(HighlightRole::operat)),
|
||||
("false", fg(HighlightRole::command)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("or", fg(HighlightRole::operat)),
|
||||
("false", fg(HighlightRole::command)),
|
||||
("||", fg(HighlightRole::operat)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("and", fg(HighlightRole::operat)),
|
||||
("not", fg(HighlightRole::operat)),
|
||||
("!", fg(HighlightRole::operat)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("end", fg(HighlightRole::keyword)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("%self", fg(HighlightRole::operat)),
|
||||
("not%self", fg(HighlightRole::param)),
|
||||
("self%not", fg(HighlightRole::param)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("false", fg(HighlightRole::command)),
|
||||
("&|", fg(HighlightRole::statement_terminator)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("HOME", fg(HighlightRole::param)),
|
||||
("=", fg(HighlightRole::operat), ns),
|
||||
(".", fg(HighlightRole::param), ns),
|
||||
("VAR1", fg(HighlightRole::param)),
|
||||
("=", fg(HighlightRole::operat), ns),
|
||||
("VAL1", fg(HighlightRole::param), ns),
|
||||
("VAR", fg(HighlightRole::param)),
|
||||
("=", fg(HighlightRole::operat), ns),
|
||||
("false", fg(HighlightRole::command)),
|
||||
("|&", fg(HighlightRole::statement_terminator)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
("stuff", fg(HighlightRole::param)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)), // (
|
||||
(")", fg(HighlightRole::error)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("stuff", fg(HighlightRole::param)),
|
||||
("# comment", fg(HighlightRole::comment)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("--", fg(HighlightRole::option)),
|
||||
("-s", fg(HighlightRole::param)),
|
||||
);
|
||||
|
||||
// Overlong paths don't crash (#7837).
|
||||
let overlong = get_overlong_path();
|
||||
validate!(
|
||||
("touch", fg(HighlightRole::command)),
|
||||
(&overlong, fg(HighlightRole::param)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("a", fg(HighlightRole::param)),
|
||||
("=", fg(HighlightRole::operat), ns),
|
||||
);
|
||||
|
||||
// Highlighting works across escaped line breaks (#8444).
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("$FISH_\\\n", fg(HighlightRole::operat)),
|
||||
("VERSION", fg(HighlightRole::operat), ns),
|
||||
);
|
||||
|
||||
// NOTE: we assume /usr/bin/env exists on the system here
|
||||
validate!(
|
||||
("/usr/bin/en", fg(HighlightRole::command), ns),
|
||||
("*", fg(HighlightRole::operat), ns)
|
||||
);
|
||||
|
||||
validate!(
|
||||
("/usr/bin/e", fg(HighlightRole::command), ns),
|
||||
("*", fg(HighlightRole::operat), ns)
|
||||
);
|
||||
|
||||
validate!(
|
||||
("/usr/bin/e", fg(HighlightRole::command), ns),
|
||||
("{$VARIABLE_IN_COMMAND}", fg(HighlightRole::operat), ns),
|
||||
("*", fg(HighlightRole::operat), ns)
|
||||
);
|
||||
|
||||
validate!(
|
||||
("/usr/bin/e", fg(HighlightRole::command), ns),
|
||||
("$VARIABLE_IN_COMMAND2", fg(HighlightRole::operat), ns)
|
||||
);
|
||||
|
||||
validate!(("$EMPTY_VARIABLE", fg(HighlightRole::error)));
|
||||
validate!(("\"$EMPTY_VARIABLE\"", fg(HighlightRole::error)));
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("\\UFDFD", fg(HighlightRole::escape)),
|
||||
);
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("\\U10FFFF", fg(HighlightRole::escape)),
|
||||
);
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("\\U110000", fg(HighlightRole::error)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
(">", fg(HighlightRole::error)),
|
||||
("echo", fg(HighlightRole::error)),
|
||||
);
|
||||
});
|
||||
|
||||
let fg = HighlightSpec::with_fg;
|
||||
|
||||
// Verify variables and wildcards in commands using /bin/cat.
|
||||
let vars = parser.vars();
|
||||
let local_mode = EnvSetMode::new_at_early_startup(EnvMode::LOCAL);
|
||||
vars.set_one(L!("CDPATH"), local_mode, L!("./cdpath-entry").to_owned());
|
||||
|
||||
// NOTE n, nv are suffix of /usr/bin/env
|
||||
vars.set_one(L!("VARIABLE_IN_COMMAND"), local_mode, L!("n").to_owned());
|
||||
vars.set_one(L!("VARIABLE_IN_COMMAND2"), local_mode, L!("nv").to_owned());
|
||||
|
||||
let _cleanup = ScopeGuard::new((), |_| {
|
||||
vars.remove(L!("VARIABLE_IN_COMMAND"), EnvSetMode::default());
|
||||
vars.remove(L!("VARIABLE_IN_COMMAND2"), EnvSetMode::default());
|
||||
});
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("./foo", param_valid_path),
|
||||
("&", fg(HighlightRole::statement_terminator)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("command", fg(HighlightRole::keyword)),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("abc", fg(HighlightRole::param)),
|
||||
("foo", param_valid_path),
|
||||
("&", fg(HighlightRole::statement_terminator)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("foo&bar", fg(HighlightRole::param)),
|
||||
("foo", fg(HighlightRole::param), ns),
|
||||
("&", fg(HighlightRole::statement_terminator)),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("&>", fg(HighlightRole::redirection)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("if command", fg(HighlightRole::keyword)),
|
||||
("ls", fg(HighlightRole::command)),
|
||||
("; ", fg(HighlightRole::statement_terminator)),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("abc", fg(HighlightRole::param)),
|
||||
("; ", fg(HighlightRole::statement_terminator)),
|
||||
("/bin/definitely_not_a_command", fg(HighlightRole::error)),
|
||||
("; ", fg(HighlightRole::statement_terminator)),
|
||||
("end", fg(HighlightRole::keyword)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("if", fg(HighlightRole::keyword)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("else", fg(HighlightRole::keyword)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("end", fg(HighlightRole::keyword)),
|
||||
);
|
||||
|
||||
// Verify that cd shows errors for non-directories.
|
||||
validate!(
|
||||
("cd", fg(HighlightRole::command)),
|
||||
("dir", param_valid_path),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("cd", fg(HighlightRole::command)),
|
||||
("foo", fg(HighlightRole::error)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("cd", fg(HighlightRole::command)),
|
||||
("--help", fg(HighlightRole::option)),
|
||||
("-h", fg(HighlightRole::option)),
|
||||
("definitely_not_a_directory", fg(HighlightRole::error)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("cd", fg(HighlightRole::command)),
|
||||
("dir-in-cdpath", param_valid_path),
|
||||
);
|
||||
|
||||
// Command substitutions.
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("param1", fg(HighlightRole::param)),
|
||||
("-l", fg(HighlightRole::option)),
|
||||
("--", fg(HighlightRole::option)),
|
||||
("-l", fg(HighlightRole::param)),
|
||||
("(", fg(HighlightRole::operat)),
|
||||
("ls", fg(HighlightRole::command)),
|
||||
("-l", fg(HighlightRole::option)),
|
||||
("--", fg(HighlightRole::option)),
|
||||
("-l", fg(HighlightRole::param)),
|
||||
("param2", fg(HighlightRole::param)),
|
||||
(")", fg(HighlightRole::operat)),
|
||||
("|", fg(HighlightRole::statement_terminator)),
|
||||
("cat", fg(HighlightRole::command)),
|
||||
);
|
||||
validate!(
|
||||
("true", fg(HighlightRole::command)),
|
||||
("$(", fg(HighlightRole::operat)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
(")", fg(HighlightRole::operat)),
|
||||
);
|
||||
validate!(
|
||||
("true", fg(HighlightRole::command)),
|
||||
("\"before", fg(HighlightRole::quote)),
|
||||
("$(", fg(HighlightRole::operat)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
("param1", fg(HighlightRole::param)),
|
||||
(")", fg(HighlightRole::operat)),
|
||||
("after\"", fg(HighlightRole::quote)),
|
||||
("param2", fg(HighlightRole::param)),
|
||||
);
|
||||
validate!(
|
||||
("true", fg(HighlightRole::command)),
|
||||
("\"", fg(HighlightRole::error)),
|
||||
("unclosed quote", fg(HighlightRole::quote)),
|
||||
("$(", fg(HighlightRole::operat)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
(")", fg(HighlightRole::operat)),
|
||||
);
|
||||
|
||||
// Redirections substitutions.
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("param1", fg(HighlightRole::param)),
|
||||
// Input redirection.
|
||||
("<", fg(HighlightRole::redirection)),
|
||||
("/dev/null", redirection_valid_path),
|
||||
// Output redirection to a valid fd.
|
||||
("1>&2", fg(HighlightRole::redirection)),
|
||||
// Output redirection to an invalid fd.
|
||||
("2>&", fg(HighlightRole::redirection)),
|
||||
("LO", fg(HighlightRole::error)),
|
||||
// Just a param, not a redirection.
|
||||
("test/blah", fg(HighlightRole::param)),
|
||||
// Input redirection from directory.
|
||||
("<", fg(HighlightRole::redirection)),
|
||||
("test/", fg(HighlightRole::error)),
|
||||
// Output redirection to an invalid path.
|
||||
("3>", fg(HighlightRole::redirection)),
|
||||
("/not/a/valid/path/nope", fg(HighlightRole::error)),
|
||||
// Output redirection to directory.
|
||||
("3>", fg(HighlightRole::redirection)),
|
||||
("test/nope/", fg(HighlightRole::error)),
|
||||
// Redirections to overflow fd.
|
||||
("99999999999999999999>&2", fg(HighlightRole::error)),
|
||||
("2>&", fg(HighlightRole::redirection)),
|
||||
("99999999999999999999", fg(HighlightRole::error)),
|
||||
// Output redirection containing a command substitution.
|
||||
("4>", fg(HighlightRole::redirection)),
|
||||
("(", fg(HighlightRole::operat)),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("test/somewhere", fg(HighlightRole::param)),
|
||||
(")", fg(HighlightRole::operat)),
|
||||
// Just another param.
|
||||
("param2", fg(HighlightRole::param)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("for", fg(HighlightRole::keyword)),
|
||||
("x", fg(HighlightRole::param)),
|
||||
("in", fg(HighlightRole::keyword)),
|
||||
("set-by-for-1", fg(HighlightRole::param)),
|
||||
("set-by-for-2", fg(HighlightRole::param)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
(">", fg(HighlightRole::redirection)),
|
||||
("$x", fg(HighlightRole::redirection)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("end", fg(HighlightRole::keyword)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("set", fg(HighlightRole::command)),
|
||||
("x", fg(HighlightRole::param)),
|
||||
("set-by-set", fg(HighlightRole::param)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
(">", fg(HighlightRole::redirection)),
|
||||
("$x", fg(HighlightRole::redirection)),
|
||||
("2>", fg(HighlightRole::redirection)),
|
||||
("$totally_not_x", fg(HighlightRole::error)),
|
||||
("<", fg(HighlightRole::redirection)),
|
||||
("$x_but_its_an_impostor", fg(HighlightRole::error)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("x", fg(HighlightRole::param), ns),
|
||||
("=", fg(HighlightRole::operat), ns),
|
||||
("set-by-variable-override", fg(HighlightRole::param), ns),
|
||||
("echo", fg(HighlightRole::command)),
|
||||
(">", fg(HighlightRole::redirection)),
|
||||
("$x", fg(HighlightRole::redirection)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("end", fg(HighlightRole::error)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("if", fg(HighlightRole::keyword)),
|
||||
("end", fg(HighlightRole::error)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("'", fg(HighlightRole::error)),
|
||||
("single_quote", fg(HighlightRole::quote)),
|
||||
("$stuff", fg(HighlightRole::quote)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("\"", fg(HighlightRole::error)),
|
||||
("double_quote", fg(HighlightRole::quote)),
|
||||
("$stuff", fg(HighlightRole::operat)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("$foo", fg(HighlightRole::operat)),
|
||||
("\"", fg(HighlightRole::quote)),
|
||||
("$bar", fg(HighlightRole::operat)),
|
||||
("\"", fg(HighlightRole::quote)),
|
||||
("$baz[", fg(HighlightRole::operat)),
|
||||
("1 2..3", fg(HighlightRole::param)),
|
||||
("]", fg(HighlightRole::operat)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("for", fg(HighlightRole::keyword)),
|
||||
("i", fg(HighlightRole::param)),
|
||||
("in", fg(HighlightRole::keyword)),
|
||||
("1 2 3", fg(HighlightRole::param)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("end", fg(HighlightRole::keyword)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("$$foo[", fg(HighlightRole::operat)),
|
||||
("1", fg(HighlightRole::param)),
|
||||
("][", fg(HighlightRole::operat)),
|
||||
("2", fg(HighlightRole::param)),
|
||||
("]", fg(HighlightRole::operat)),
|
||||
("[3]", fg(HighlightRole::param)), // two dollar signs, so last one is not an expansion
|
||||
);
|
||||
|
||||
validate!(
|
||||
("cat", fg(HighlightRole::command)),
|
||||
("/dev/null", param_valid_path),
|
||||
("|", fg(HighlightRole::statement_terminator)),
|
||||
// This is bogus, but we used to use "less" here and that doesn't have to be installed.
|
||||
("cat", fg(HighlightRole::command)),
|
||||
("2>", fg(HighlightRole::redirection)),
|
||||
);
|
||||
|
||||
// Highlight path-prefixes only at the cursor.
|
||||
validate!(
|
||||
("cat", fg(HighlightRole::command)),
|
||||
("/dev/nu", fg(HighlightRole::param)),
|
||||
("/dev/nu", param_valid_path),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("if", fg(HighlightRole::keyword)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
("&&", fg(HighlightRole::operat)),
|
||||
("false", fg(HighlightRole::command)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("or", fg(HighlightRole::operat)),
|
||||
("false", fg(HighlightRole::command)),
|
||||
("||", fg(HighlightRole::operat)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("and", fg(HighlightRole::operat)),
|
||||
("not", fg(HighlightRole::operat)),
|
||||
("!", fg(HighlightRole::operat)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
(";", fg(HighlightRole::statement_terminator)),
|
||||
("end", fg(HighlightRole::keyword)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("%self", fg(HighlightRole::operat)),
|
||||
("not%self", fg(HighlightRole::param)),
|
||||
("self%not", fg(HighlightRole::param)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("false", fg(HighlightRole::command)),
|
||||
("&|", fg(HighlightRole::statement_terminator)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("HOME", fg(HighlightRole::param)),
|
||||
("=", fg(HighlightRole::operat), ns),
|
||||
(".", fg(HighlightRole::param), ns),
|
||||
("VAR1", fg(HighlightRole::param)),
|
||||
("=", fg(HighlightRole::operat), ns),
|
||||
("VAL1", fg(HighlightRole::param), ns),
|
||||
("VAR", fg(HighlightRole::param)),
|
||||
("=", fg(HighlightRole::operat), ns),
|
||||
("false", fg(HighlightRole::command)),
|
||||
("|&", fg(HighlightRole::statement_terminator)),
|
||||
("true", fg(HighlightRole::command)),
|
||||
("stuff", fg(HighlightRole::param)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)), // (
|
||||
(")", fg(HighlightRole::error)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("stuff", fg(HighlightRole::param)),
|
||||
("# comment", fg(HighlightRole::comment)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("--", fg(HighlightRole::option)),
|
||||
("-s", fg(HighlightRole::param)),
|
||||
);
|
||||
|
||||
// Overlong paths don't crash (#7837).
|
||||
let overlong = get_overlong_path();
|
||||
validate!(
|
||||
("touch", fg(HighlightRole::command)),
|
||||
(&overlong, fg(HighlightRole::param)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
("a", fg(HighlightRole::param)),
|
||||
("=", fg(HighlightRole::operat), ns),
|
||||
);
|
||||
|
||||
// Highlighting works across escaped line breaks (#8444).
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("$FISH_\\\n", fg(HighlightRole::operat)),
|
||||
("VERSION", fg(HighlightRole::operat), ns),
|
||||
);
|
||||
|
||||
// NOTE: we assume /usr/bin/env exists on the system here
|
||||
validate!(
|
||||
("/usr/bin/en", fg(HighlightRole::command), ns),
|
||||
("*", fg(HighlightRole::operat), ns)
|
||||
);
|
||||
|
||||
validate!(
|
||||
("/usr/bin/e", fg(HighlightRole::command), ns),
|
||||
("*", fg(HighlightRole::operat), ns)
|
||||
);
|
||||
|
||||
validate!(
|
||||
("/usr/bin/e", fg(HighlightRole::command), ns),
|
||||
("{$VARIABLE_IN_COMMAND}", fg(HighlightRole::operat), ns),
|
||||
("*", fg(HighlightRole::operat), ns)
|
||||
);
|
||||
|
||||
validate!(
|
||||
("/usr/bin/e", fg(HighlightRole::command), ns),
|
||||
("$VARIABLE_IN_COMMAND2", fg(HighlightRole::operat), ns)
|
||||
);
|
||||
|
||||
validate!(("$EMPTY_VARIABLE", fg(HighlightRole::error)));
|
||||
validate!(("\"$EMPTY_VARIABLE\"", fg(HighlightRole::error)));
|
||||
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("\\UFDFD", fg(HighlightRole::escape)),
|
||||
);
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("\\U10FFFF", fg(HighlightRole::escape)),
|
||||
);
|
||||
validate!(
|
||||
("echo", fg(HighlightRole::command)),
|
||||
("\\U110000", fg(HighlightRole::error)),
|
||||
);
|
||||
|
||||
validate!(
|
||||
(">", fg(HighlightRole::error)),
|
||||
("echo", fg(HighlightRole::error)),
|
||||
);
|
||||
}
|
||||
|
||||
/// Tests that trailing spaces after a command don't inherit the underline formatting of the
|
||||
|
||||
@@ -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, test as 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};
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
use crate::{
|
||||
common::{EscapeFlags, EscapeStringStyle, escape_string},
|
||||
flog::FloggableDebug,
|
||||
future_feature_flags::{FeatureFlag, test as 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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::test(FeatureFlag::QueryTerm)
|
||||
fish_feature_flags::feature_test(FeatureFlag::QueryTerm)
|
||||
&& !is_dumb()
|
||||
&& {
|
||||
// TODO(term-workaround)
|
||||
|
||||
@@ -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::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::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::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::test(FeatureFlag::MarkPrompt) {
|
||||
if !fish_feature_flags::feature_test(FeatureFlag::MarkPrompt) {
|
||||
return false;
|
||||
}
|
||||
write_to_output!(out, "\x1b]133;D;{}\x07", exit_status);
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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<wstr>) -> bool {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::future_feature_flags::scoped_test;
|
||||
use fish_feature_flags::with_overridden_feature;
|
||||
|
||||
#[test]
|
||||
fn test_wildcards() {
|
||||
@@ -1244,12 +1243,12 @@ fn test_wildcards() {
|
||||
let wc = unescape_string(wc, UnescapeStringStyle::Script(UnescapeFlags::SPECIAL)).unwrap();
|
||||
assert!(!wildcard_has(&wc) && wildcard_has_internal(&wc));
|
||||
|
||||
scoped_test(FeatureFlag::QuestionMarkNoGlob, false, || {
|
||||
with_overridden_feature(FeatureFlag::QuestionMarkNoGlob, false, || {
|
||||
assert!(wildcard_has(L!("?")));
|
||||
assert!(!wildcard_has(L!("\\?")));
|
||||
});
|
||||
|
||||
scoped_test(FeatureFlag::QuestionMarkNoGlob, true, || {
|
||||
with_overridden_feature(FeatureFlag::QuestionMarkNoGlob, true, || {
|
||||
assert!(!wildcard_has(L!("?")));
|
||||
assert!(!wildcard_has(L!("\\?")));
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
isolated-tmux-start
|
||||
isolated-tmux send-keys 'set -g g_u_var foobar' Enter
|
||||
tmux-sleep
|
||||
isolated-tmux send-keys 'set -U g_u_var barfoo' Enter
|
||||
|
||||
tmux-sleep
|
||||
|
||||
Reference in New Issue
Block a user