fixed issues with expansion of case arm patterns
This commit is contained in:
@@ -1726,6 +1726,32 @@ pub fn perform_param_expansion(raw: &str) -> ShResult<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Expand a case pattern: performs variable/command expansion while preserving
|
||||||
|
/// glob metacharacters that were inside quotes as literals (by backslash-escaping them).
|
||||||
|
/// Unquoted glob chars (*, ?, [) pass through for glob_to_regex to interpret.
|
||||||
|
pub fn expand_case_pattern(raw: &str) -> ShResult<String> {
|
||||||
|
let unescaped = unescape_str(raw);
|
||||||
|
let expanded = expand_raw(&mut unescaped.chars().peekable())?;
|
||||||
|
|
||||||
|
let mut result = String::new();
|
||||||
|
let mut in_quote = false;
|
||||||
|
let mut chars = expanded.chars();
|
||||||
|
|
||||||
|
while let Some(ch) = chars.next() {
|
||||||
|
match ch {
|
||||||
|
markers::DUB_QUOTE | markers::SNG_QUOTE => {
|
||||||
|
in_quote = !in_quote;
|
||||||
|
}
|
||||||
|
'*' | '?' | '[' | ']' if in_quote => {
|
||||||
|
result.push('\\');
|
||||||
|
result.push(ch);
|
||||||
|
}
|
||||||
|
_ => result.push(ch),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn glob_to_regex(glob: &str, anchored: bool) -> Regex {
|
pub fn glob_to_regex(glob: &str, anchored: bool) -> Regex {
|
||||||
let mut regex = String::new();
|
let mut regex = String::new();
|
||||||
if anchored {
|
if anchored {
|
||||||
@@ -1744,7 +1770,17 @@ pub fn glob_to_regex(glob: &str, anchored: bool) -> Regex {
|
|||||||
}
|
}
|
||||||
'*' => regex.push_str(".*"),
|
'*' => regex.push_str(".*"),
|
||||||
'?' => regex.push('.'),
|
'?' => regex.push('.'),
|
||||||
'.' | '+' | '(' | ')' | '|' | '^' | '$' | '[' | ']' | '{' | '}' => {
|
'[' => {
|
||||||
|
// Pass through character class [...] as-is (glob and regex syntax match)
|
||||||
|
regex.push('[');
|
||||||
|
while let Some(bc) = chars.next() {
|
||||||
|
regex.push(bc);
|
||||||
|
if bc == ']' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'.' | '+' | '(' | ')' | '|' | '^' | '$' | '{' | '}' => {
|
||||||
regex.push('\\');
|
regex.push('\\');
|
||||||
regex.push(ch);
|
regex.push(ch);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,14 +42,17 @@ pub trait NodeVecUtils<Node> {
|
|||||||
|
|
||||||
impl AutoCmdVecUtils for Vec<AutoCmd> {
|
impl AutoCmdVecUtils for Vec<AutoCmd> {
|
||||||
fn exec(&self) {
|
fn exec(&self) {
|
||||||
|
let saved_status = crate::state::get_status();
|
||||||
for cmd in self {
|
for cmd in self {
|
||||||
let AutoCmd { pattern: _, command } = cmd;
|
let AutoCmd { pattern: _, command } = cmd;
|
||||||
if let Err(e) = exec_input(command.clone(), None, false, Some("autocmd".into())) {
|
if let Err(e) = exec_input(command.clone(), None, false, Some("autocmd".into())) {
|
||||||
e.print_error();
|
e.print_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
crate::state::set_status(saved_status);
|
||||||
}
|
}
|
||||||
fn exec_with(&self, other_pattern: &str) {
|
fn exec_with(&self, other_pattern: &str) {
|
||||||
|
let saved_status = crate::state::get_status();
|
||||||
for cmd in self {
|
for cmd in self {
|
||||||
let AutoCmd { pattern, command } = cmd;
|
let AutoCmd { pattern, command } = cmd;
|
||||||
if let Some(pat) = pattern
|
if let Some(pat) = pattern
|
||||||
@@ -62,6 +65,7 @@ impl AutoCmdVecUtils for Vec<AutoCmd> {
|
|||||||
e.print_error();
|
e.print_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
crate::state::set_status(saved_status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use crate::{
|
|||||||
builtin::{
|
builtin::{
|
||||||
alias::{alias, unalias}, arrops::{arr_fpop, arr_fpush, arr_pop, arr_push, arr_rotate}, autocmd::autocmd, cd::cd, complete::{compgen_builtin, complete_builtin}, dirstack::{dirs, popd, pushd}, echo::echo, eval, exec, flowctl::flowctl, getopts::getopts, intro, jobctl::{self, JobBehavior, continue_job, disown, jobs}, keymap, map, pwd::pwd, read::{self, read_builtin}, shift::shift, shopt::shopt, source::source, test::double_bracket_test, trap::{TrapTarget, trap}, varcmds::{export, local, readonly, unset}, zoltraak::zoltraak
|
alias::{alias, unalias}, arrops::{arr_fpop, arr_fpush, arr_pop, arr_push, arr_rotate}, autocmd::autocmd, cd::cd, complete::{compgen_builtin, complete_builtin}, dirstack::{dirs, popd, pushd}, echo::echo, eval, exec, flowctl::flowctl, getopts::getopts, intro, jobctl::{self, JobBehavior, continue_job, disown, jobs}, keymap, map, pwd::pwd, read::{self, read_builtin}, shift::shift, shopt::shopt, source::source, test::double_bracket_test, trap::{TrapTarget, trap}, varcmds::{export, local, readonly, unset}, zoltraak::zoltraak
|
||||||
},
|
},
|
||||||
expand::{Expander, expand_aliases, expand_raw, glob_to_regex},
|
expand::{Expander, expand_aliases, expand_case_pattern, expand_raw, glob_to_regex},
|
||||||
jobs::{ChildProc, JobStack, attach_tty, dispatch_job},
|
jobs::{ChildProc, JobStack, attach_tty, dispatch_job},
|
||||||
libsh::{
|
libsh::{
|
||||||
error::{ShErr, ShErrKind, ShResult, ShResultExt, next_color},
|
error::{ShErr, ShErrKind, ShResult, ShResultExt, next_color},
|
||||||
@@ -428,7 +428,7 @@ impl Dispatcher {
|
|||||||
let block_patterns = block_pattern_raw.split('|');
|
let block_patterns = block_pattern_raw.split('|');
|
||||||
|
|
||||||
for pattern in block_patterns {
|
for pattern in block_patterns {
|
||||||
let pattern_exp = Expander::from_raw(pattern)?.expand()?.join(" ");
|
let pattern_exp = expand_case_pattern(pattern)?;
|
||||||
let pattern_regex = glob_to_regex(&pattern_exp, false);
|
let pattern_regex = glob_to_regex(&pattern_exp, false);
|
||||||
if pattern_regex.is_match(&pattern_raw) {
|
if pattern_regex.is_match(&pattern_raw) {
|
||||||
for node in &body {
|
for node in &body {
|
||||||
|
|||||||
Reference in New Issue
Block a user