Skip to content

Commit

Permalink
fix: slight compat improvements to set -x (#205)
Browse files Browse the repository at this point in the history
  • Loading branch information
reubeno authored Oct 15, 2024
1 parent 20a8090 commit 45d95c1
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 18 deletions.
18 changes: 13 additions & 5 deletions brush-core/src/escape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,10 @@ pub(crate) enum QuoteMode {
Quote,
}

pub(crate) fn quote_if_needed(s: &str, mode: QuoteMode) -> String {
pub(crate) fn quote_if_needed<S: AsRef<str>>(s: S, mode: QuoteMode) -> String {
match mode {
QuoteMode::BackslashEscape => escape_with_backslash(s),
QuoteMode::Quote => escape_with_quoting(s),
QuoteMode::BackslashEscape => escape_with_backslash(s.as_ref()),
QuoteMode::Quote => escape_with_quoting(s.as_ref()),
}
}

Expand All @@ -197,7 +197,7 @@ fn escape_with_backslash(s: &str) -> String {

fn escape_with_quoting(s: &str) -> String {
// TODO: Handle single-quote!
if s.chars().any(needs_escaping) {
if s.is_empty() || s.chars().any(needs_escaping) {
std::format!("'{s}'")
} else {
s.to_owned()
Expand Down Expand Up @@ -235,9 +235,17 @@ mod tests {
use super::*;

#[test]
fn test_escape() {
fn test_backslash_escape() {
assert_eq!(quote_if_needed("a", QuoteMode::BackslashEscape), "a");
assert_eq!(quote_if_needed("a b", QuoteMode::BackslashEscape), r"a\ b");
assert_eq!(quote_if_needed("", QuoteMode::BackslashEscape), "");
}

#[test]
fn test_quote_escape() {
assert_eq!(quote_if_needed("a", QuoteMode::Quote), "a");
assert_eq!(quote_if_needed("a b", QuoteMode::Quote), "'a b'");
assert_eq!(quote_if_needed("", QuoteMode::Quote), "''");
}

fn assert_echo_expands_to(unexpanded: &str, expected: &str) {
Expand Down
12 changes: 9 additions & 3 deletions brush-core/src/extendedtests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ use brush_parser::ast;
use std::path::Path;

use crate::{
env, error, expansion, namedoptions, patterns,
sys::{fs::MetadataExt, fs::PathExt, users},
env, error, escape, expansion, namedoptions, patterns,
sys::{
fs::{MetadataExt, PathExt},
users,
},
variables::{self, ArrayLiteral},
Shell,
};
Expand Down Expand Up @@ -47,7 +50,10 @@ async fn apply_unary_predicate(
let expanded_operand = expansion::basic_expand_word(shell, operand).await?;

if shell.options.print_commands_and_arguments {
shell.trace_command(std::format!("[[ {op} {expanded_operand} ]]"))?;
shell.trace_command(std::format!(
"[[ {op} {} ]]",
escape::quote_if_needed(&expanded_operand, escape::QuoteMode::Quote)
))?;
}

apply_unary_predicate_to_str(op, expanded_operand.as_str(), shell)
Expand Down
26 changes: 19 additions & 7 deletions brush-core/src/variables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::borrow::Cow;
use std::collections::BTreeMap;
use std::fmt::{Display, Write};

use crate::error;
use crate::{error, escape};

/// A shell variable.
#[derive(Clone, Debug)]
Expand Down Expand Up @@ -510,26 +510,38 @@ pub enum ShellValueLiteral {
Array(ArrayLiteral),
}

impl Display for ShellValueLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl ShellValueLiteral {
pub(crate) fn fmt_for_tracing(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
// TODO: Decide if it needs to be quoted.
ShellValueLiteral::Scalar(s) => write!(f, "{s}"),
ShellValueLiteral::Scalar(s) => Self::fmt_scalar_for_tracing(s.as_str(), f),
ShellValueLiteral::Array(elements) => {
write!(f, "(")?;
for (i, (key, value)) in elements.0.iter().enumerate() {
if i > 0 {
write!(f, " ")?;
}
if let Some(key) = key {
write!(f, "[{key}]=")?;
write!(f, "[")?;
Self::fmt_scalar_for_tracing(key.as_str(), f)?;
write!(f, "]=")?;
}
write!(f, "{value}")?;
Self::fmt_scalar_for_tracing(value.as_str(), f)?;
}
write!(f, ")")
}
}
}

fn fmt_scalar_for_tracing(s: &str, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let processed = escape::quote_if_needed(s, escape::QuoteMode::Quote);
write!(f, "{processed}")
}
}

impl Display for ShellValueLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_for_tracing(f)
}
}

impl From<&str> for ShellValueLiteral {
Expand Down
5 changes: 2 additions & 3 deletions brush-shell/tests/cases/options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ cases:
echo "Math checks"
fi
# TODO: Re-enable these
# var=" "
# [[ ${var} && ! ${var//[[:space:]]/} ]]
var="x"
[[ ${var} && ${var//[[:space:]]/} ]]
for ((i = 0; i < 3; i++)); do
echo $i
Expand Down

0 comments on commit 45d95c1

Please sign in to comment.