Merge nucleic/nimble-umber-toad-20h7 into dev

This commit is contained in:
2026-08-11 20:11:26 -07:00
parent 959a80f5ec
commit 8e934d8996
16 changed files with 196 additions and 196 deletions
+14 -14
View File
@@ -37,7 +37,7 @@ pub(crate) struct ExpanderOptions {
/// Whether to perform pathname expansion (globbing). If disabled, glob patterns
/// are returned as literal strings.
pub pathname_expand: bool,
// nash: whether literal (unquoted, non-expansion) text is also subject to
// hydrashell: whether literal (unquoted, non-expansion) text is also subject to
// field splitting. Off by default per POSIX/bash (only expansion results
// split); enabled by callers whose input string is *data*, e.g. the
// `compgen -W` word list.
@@ -275,7 +275,7 @@ impl From<String> for WordField {
enum ExpansionPiece {
Unsplittable(String),
Splittable(String),
// nash: literal unquoted word text. Bash field-splits only the *results of
// hydrashell: literal unquoted word text. Bash field-splits only the *results of
// expansions*, never literal text — but glob characters in literal text stay
// active. This third state fixes `IFS=,; echo a,b,c` printing `a b c`
// (corpus divergence D1) without breaking `echo *.txt`.
@@ -297,7 +297,7 @@ impl From<ExpansionPiece> for patterns::PatternPiece {
match piece {
ExpansionPiece::Unsplittable(s) => Self::Literal(s),
ExpansionPiece::Splittable(s) => Self::Pattern(s),
// nash: unquoted literal text keeps glob chars active.
// hydrashell: unquoted literal text keeps glob chars active.
ExpansionPiece::LiteralText(s) => Self::Pattern(s),
}
}
@@ -308,7 +308,7 @@ impl From<ExpansionPiece> for crate::regex::RegexPiece {
match piece {
ExpansionPiece::Unsplittable(s) => Self::Literal(s),
ExpansionPiece::Splittable(s) => Self::Pattern(s),
// nash: unquoted literal text keeps pattern chars active.
// hydrashell: unquoted literal text keeps pattern chars active.
ExpansionPiece::LiteralText(s) => Self::Pattern(s),
}
}
@@ -335,12 +335,12 @@ impl ExpansionPiece {
match self {
Self::Unsplittable(_) => self,
Self::Splittable(s) => Self::Unsplittable(s),
// nash: quoting literal text also deactivates its glob chars.
// hydrashell: quoting literal text also deactivates its glob chars.
Self::LiteralText(s) => Self::Unsplittable(s),
}
}
// nash: opt literal text into field splitting (see
// hydrashell: opt literal text into field splitting (see
// `ExpanderOptions::field_split_literal_text`). Quoted pieces stay intact.
fn make_literal_splittable(self) -> Self {
match self {
@@ -547,7 +547,7 @@ struct WordExpander<'a, SE: extensions::ShellExtensions> {
in_double_quotes: bool,
/// Whether to use heredoc expansion semantics (literal quotes, no brace expansion).
heredoc_mode: bool,
// nash: see `ExpanderOptions::field_split_literal_text`.
// hydrashell: see `ExpanderOptions::field_split_literal_text`.
field_split_literal_text: bool,
}
@@ -684,7 +684,7 @@ impl<'a, SE: extensions::ShellExtensions> WordExpander<'a, SE> {
&['$', '`', '\\', '\'', '\"', '~', '{']
};
if !word.contains(expansion_chars) {
// nash: a word with no expansion characters is pure literal text —
// hydrashell: a word with no expansion characters is pure literal text —
// glob-active but not subject to field splitting.
return Ok(Expansion::from(ExpansionPiece::LiteralText(
word.to_owned(),
@@ -821,7 +821,7 @@ impl<'a, SE: extensions::ShellExtensions> WordExpander<'a, SE> {
// Go through the fields we have so far.
for existing_field in expansion.fields {
for piece in existing_field.0 {
// nash: callers whose input is data (e.g. compgen -W) opt
// hydrashell: callers whose input is data (e.g. compgen -W) opt
// literal text into splitting.
let piece = if self.field_split_literal_text {
piece.make_literal_splittable()
@@ -829,7 +829,7 @@ impl<'a, SE: extensions::ShellExtensions> WordExpander<'a, SE> {
piece
};
match piece {
// nash: literal text is never field-split (only expansion
// hydrashell: literal text is never field-split (only expansion
// results are), but stays a distinct piece so its glob
// characters remain active downstream.
ExpansionPiece::Unsplittable(_) | ExpansionPiece::LiteralText(_) => {
@@ -913,7 +913,7 @@ impl<'a, SE: extensions::ShellExtensions> WordExpander<'a, SE> {
) -> Result<Expansion, error::Error> {
let expansion: Expansion = match word_piece {
brush_parser::word::WordPiece::Text(s) => {
// nash: literal word text — not field-split, glob-active.
// hydrashell: literal word text — not field-split, glob-active.
Expansion::from(ExpansionPiece::LiteralText(s))
}
brush_parser::word::WordPiece::SingleQuotedText(s) => {
@@ -963,7 +963,7 @@ impl<'a, SE: extensions::ShellExtensions> WordExpander<'a, SE> {
ExpansionPiece::Unsplittable(self.expand_tilde_expression(&tilde_expr)?),
),
brush_parser::word::WordPiece::ParameterExpansion(p) => {
// nash: whatever a parameter expansion substitutes (including
// hydrashell: whatever a parameter expansion substitutes (including
// literal text from ${v:-default} / ${v:+alt} words) is an
// expansion *result*, so it is subject to field splitting.
// Quoted pieces inside remain Unsplittable.
@@ -999,7 +999,7 @@ impl<'a, SE: extensions::ShellExtensions> WordExpander<'a, SE> {
let trimmed_len = cmd_output.trim_end_matches('\n').len();
cmd_output.truncate(trimmed_len);
// nash: capture command-substitution output (docs/NASH.md §5.3) —
// hydrashell: capture command-substitution output (docs/HYDRASHELL.md §5.3) —
// invisible to the transcript, often carries decisions/secrets.
if !self.disable_command_substitutions {
crate::gate::gate().on_cmdsub(cmd_output.as_str());
@@ -1012,7 +1012,7 @@ impl<'a, SE: extensions::ShellExtensions> WordExpander<'a, SE> {
// If we are *not* in a double-quoted context and we were requested to skip
// unquoted backslash removal, then we need to skip removing backslashes here.
if !self.in_double_quotes && self.disable_unquoted_backslash_removal {
// nash: retained-backslash text is literal, not an
// hydrashell: retained-backslash text is literal, not an
// expansion result — no field splitting.
return Ok(Expansion::from(ExpansionPiece::LiteralText(s)));
}