diff --git a/examples/methods.ion b/examples/methods.ion index 6ff9c69e4ab7102ebfe7bef9e4d282bd492cc3f3..768dfa97fcbe73484f0130cbae34d0fe93cad1c8 100644 --- a/examples/methods.ion +++ b/examples/methods.ion @@ -31,4 +31,8 @@ echo $repeat("one ", 5) echo $join([one two three], "\n") echo $join([one two three], "\t") echo $join([one two three], "\\n") -echo $replace($join([one two three], "\n"), "\n" "\t") \ No newline at end of file +echo $replace($join([one two three], "\n"), "\n" "\t") +let a = "applesauce" +let pos = $find(a, "s") +let array = [@split_at(a, $pos)] +echo $join(array, "\n") \ No newline at end of file diff --git a/examples/methods.out b/examples/methods.out index 629625ca3c3b2239c1db5c2770be4ed7720e4ec5..b64222956262039121094a0eed07bfe3988e893d 100644 --- a/examples/methods.out +++ b/examples/methods.out @@ -63,3 +63,5 @@ three one two three one\ntwo\nthree one two three +apple +sauce diff --git a/src/parser/shell_expand/mod.rs b/src/parser/shell_expand/mod.rs index 46c9e0fd3328129efee58439ec66c504b2b641a1..6f9fa498bc526e208f367f8d14d589302abc5191 100644 --- a/src/parser/shell_expand/mod.rs +++ b/src/parser/shell_expand/mod.rs @@ -350,13 +350,7 @@ pub(crate) fn expand_tokens<E: Expander>( Select::Key(_) => (), }, WordToken::ArrayMethod(ref array_method) => { - return if array_method.returns_array() { - array_method.handle_as_array(expand_func) - } else { - let mut output = String::new(); - array_method.handle(&mut output, expand_func); - array!(output) - } + return array_method.handle_as_array(expand_func) } _ => (), } diff --git a/src/parser/shell_expand/words/methods/arrays.rs b/src/parser/shell_expand/words/methods/arrays.rs index 133c38b6af842e1471b7aa5671fae4cfe226849d..f699ae28f47e43058c2af9ba6470ee7750960274 100644 --- a/src/parser/shell_expand/words/methods/arrays.rs +++ b/src/parser/shell_expand/words/methods/arrays.rs @@ -1,7 +1,9 @@ use super::{Pattern, Select, SelectWithSize}; +use super::pattern::unescape; use super::super::Index; use super::super::super::{expand_string, Expander}; use super::super::super::is_expression; +use smallstring::SmallString; use std::char; use std::io::{self, Write}; use types::Array; @@ -16,13 +18,6 @@ pub(crate) struct ArrayMethod<'a> { } impl<'a> ArrayMethod<'a> { - pub(crate) fn returns_array(&self) -> bool { - match self.method { - "split" | "chars" | "bytes" | "graphemes" => true, - _ => false, - } - } - pub(crate) fn handle<E: Expander>(&self, current: &mut String, expand_func: &E) { match self.method { "split" => { @@ -35,7 +30,7 @@ impl<'a> ArrayMethod<'a> { }; match (&self.pattern, self.selection.clone()) { (&Pattern::StringPattern(pattern), Select::All) => current.push_str(&variable - .split(&expand_string(pattern, expand_func, false).join(" ")) + .split(&unescape(expand_string(pattern, expand_func, false).join(" "))) .collect::<Vec<&str>>() .join(" ")), (&Pattern::Whitespace, Select::All) => current.push_str(&variable @@ -47,7 +42,9 @@ impl<'a> ArrayMethod<'a> { (&Pattern::StringPattern(pattern), Select::Index(Index::Forward(id))) => { current.push_str( variable - .split(&expand_string(pattern, expand_func, false).join(" ")) + .split( + &unescape(expand_string(pattern, expand_func, false).join(" ")), + ) .nth(id) .unwrap_or_default(), ) @@ -62,7 +59,9 @@ impl<'a> ArrayMethod<'a> { (&Pattern::StringPattern(pattern), Select::Index(Index::Backward(id))) => { current.push_str( variable - .rsplit(&expand_string(pattern, expand_func, false).join(" ")) + .rsplit( + &unescape(expand_string(pattern, expand_func, false).join(" ")), + ) .nth(id) .unwrap_or_default(), ) @@ -76,7 +75,9 @@ impl<'a> ArrayMethod<'a> { .unwrap_or_default(), ), (&Pattern::StringPattern(pattern), Select::Range(range)) => { - let expansion = expand_string(pattern, expand_func, false).join(" "); + let expansion = unescape( + unescape(expand_string(pattern, expand_func, false).join(" ")), + ); let iter = variable.split(&expansion); if let Some((start, length)) = range.bounds(iter.clone().count()) { let range = iter.skip(start).take(length).collect::<Vec<_>>().join(" "); @@ -127,7 +128,7 @@ impl<'a> ArrayMethod<'a> { return match (&self.pattern, self.selection.clone()) { (_, Select::None) => Some("".into()).into_iter().collect(), (&Pattern::StringPattern(pattern), Select::All) => variable - .split(&expand_string(pattern, expand_func, false).join(" ")) + .split(&unescape(expand_string(pattern, expand_func, false).join(" "))) .map(From::from) .collect(), (&Pattern::Whitespace, Select::All) => variable @@ -137,7 +138,7 @@ impl<'a> ArrayMethod<'a> { .collect(), (&Pattern::StringPattern(pattern), Select::Index(Index::Forward(id))) => { variable - .split(&expand_string(pattern, expand_func, false).join(" ")) + .split(&unescape(expand_string(pattern, expand_func, false).join(" "))) .nth(id) .map(From::from) .into_iter() @@ -152,7 +153,7 @@ impl<'a> ArrayMethod<'a> { .collect(), (&Pattern::StringPattern(pattern), Select::Index(Index::Backward(id))) => { variable - .rsplit(&expand_string(pattern, expand_func, false).join(" ")) + .rsplit(&unescape(expand_string(pattern, expand_func, false).join(" "))) .nth(id) .map(From::from) .into_iter() @@ -166,7 +167,8 @@ impl<'a> ArrayMethod<'a> { .into_iter() .collect(), (&Pattern::StringPattern(pattern), Select::Range(range)) => { - let expansion = expand_string(pattern, expand_func, false).join(" "); + let expansion = + unescape(expand_string(pattern, expand_func, false).join(" ")); let iter = variable.split(&expansion); if let Some((start, length)) = range.bounds(iter.clone().count()) { iter.skip(start).take(length).map(From::from).collect() @@ -192,6 +194,25 @@ impl<'a> ArrayMethod<'a> { (_, Select::Key(_)) => Some("".into()).into_iter().collect(), }; } + "split_at" => { + let variable = resolve_var!(); + match self.pattern { + Pattern::StringPattern(string) => if let Ok(value) = + expand_string(string, expand_func, false).join(" ").parse::<usize>() + { + if value < variable.len() { + let (l, r) = variable.split_at(value); + return array![SmallString::from(l), SmallString::from(r)]; + } + eprintln!("ion: split_at: value is out of bounds"); + } else { + eprintln!("ion: split_at: requires a valid number as an argument"); + }, + Pattern::Whitespace => { + eprintln!("ion: split_at: requires an argument"); + } + } + } "graphemes" => { let variable = resolve_var!(); let graphemes = UnicodeSegmentation::graphemes(variable.as_str(), true); diff --git a/src/parser/shell_expand/words/methods/mod.rs b/src/parser/shell_expand/words/methods/mod.rs index 6b24d0c156edd42e2e6492f97f08d08344c60073..191b5db7ad53a55750249391bad179451cad9ba5 100644 --- a/src/parser/shell_expand/words/methods/mod.rs +++ b/src/parser/shell_expand/words/methods/mod.rs @@ -3,8 +3,8 @@ mod pattern; mod strings; pub(crate) use self::arrays::ArrayMethod; -pub(crate) use self::strings::StringMethod; pub(crate) use self::pattern::Pattern; +pub(crate) use self::strings::StringMethod; use super::{Index, Range}; use super::super::ranges::parse_index_range; diff --git a/src/parser/shell_expand/words/methods/pattern.rs b/src/parser/shell_expand/words/methods/pattern.rs index 929c0432da71915ad0cb8ac93da6fcb237f819fa..edd6849f767493ecf70c34b3e2088c994479d9ff 100644 --- a/src/parser/shell_expand/words/methods/pattern.rs +++ b/src/parser/shell_expand/words/methods/pattern.rs @@ -13,10 +13,19 @@ pub(crate) fn unescape(input: String) -> String { output += &input[start..id]; if let Some((_, character)) = characters.next() { start = match character { - 'n' => {output.push('\n'); id + 2}, - '\\' => {output.push('\\'); id + 2}, - 't' => {output.push('\t'); id + 2}, - _ => id + 1 + 'n' => { + output.push('\n'); + id + 2 + } + '\\' => { + output.push('\\'); + id + 2 + } + 't' => { + output.push('\t'); + id + 2 + } + _ => id + 1, }; } } @@ -26,4 +35,4 @@ pub(crate) fn unescape(input: String) -> String { output += &input[start..]; } output -} \ No newline at end of file +} diff --git a/src/parser/shell_expand/words/methods/strings.rs b/src/parser/shell_expand/words/methods/strings.rs index 34bee02bf03b6f9ca981e14a25f59fa4bcb597e7..7135d44ccb128bc9f76f50b779c136e2244f51e9 100644 --- a/src/parser/shell_expand/words/methods/strings.rs +++ b/src/parser/shell_expand/words/methods/strings.rs @@ -3,6 +3,7 @@ use super::pattern::unescape; use super::super::super::{expand_string, Expander}; use super::super::super::{is_expression, slice}; use super::super::super::super::ArgumentSplitter; +use parser::assignments::is_array; use shell::plugins::methods::{self, MethodArguments, StringMethodPlugins}; use std::path::Path; use sys; @@ -172,6 +173,17 @@ impl<'a> StringMethod<'a> { let rev_graphs = UnicodeSegmentation::graphemes(word.as_str(), true).rev(); output.push_str(rev_graphs.collect::<String>().as_str()); }, + "find" => { + let pattern = unescape(expand_string(pattern, expand, false).join(" ")); + let out = if let Some(value) = expand.variable(variable, false) { + value.find(&pattern) + } else if is_expression(variable) { + expand_string(variable, expand, false).join(" ").find(&pattern) + } else { + None + }; + output.push_str(&out.unwrap_or(0).to_string()); + } method @ _ => { if sys::is_root() { eprintln!("ion: root is not allowed to execute plugins");