From 610a75e7da08c62f6ed7bd182265069795004aaa Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy <mmstickman@gmail.com> Date: Fri, 7 Apr 2017 15:13:51 -0400 Subject: [PATCH] Split by Whitespaces in Array Split Method Previously, when no pattern is supplied, a string will be split by spaces. This change will extend that so that all whitespace characters will be considered in the pattern for splitting. --- README.md | 33 +++++++++- src/parser/shell_expand/words.rs | 107 +++++++++++++++++++++++-------- 2 files changed, 112 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 82f860fd..0bd4bad1 100644 --- a/README.md +++ b/README.md @@ -69,9 +69,9 @@ echo $A:$B echo ${A}s and ${B}s ``` -### Substrings +### Substrings from Variables -Ion natively supports splitting supplied strings by graphemes using the same slicing sytax for arrays: +Ion natively supports splitting supplied strings by graphemes using the same slicing syntax for arrays: ```ion $ let string = "one two three" @@ -260,6 +260,19 @@ let row = "one,two,three,four,five" echo @split(row, ',') # Splits by commas ``` +### Substring Slicing on String Methods + +```ion +echo $join(array)[3..6] +``` + +### Array Slicing on Array Methods + +```ion +let cpu_model = $(grep "model name" /proc/cpuinfo | head -1) +echo @split(cpu_model)[3..5] +``` + ### Commands Commands may be written line by line or altogether on the same line with semicolons separating them. @@ -402,6 +415,22 @@ for i in @[echo 1 2 3] end ``` +### Slicing String-Based Command Substitutions + +You may slice the string returned to obtain its substring: + +```ion +echo $(echo one two three)[..3] +``` + +### Slicing Array-Based Command Substitutions + +You may slice the array returned to obtained a specific set of elements: + +```ion +echo @[grep "model name" /proc/cpuinfo | head -1][3..5] +``` + ### Functions Functions in the Ion shell are defined with a name along with a set of variables. The function diff --git a/src/parser/shell_expand/words.rs b/src/parser/shell_expand/words.rs index 975ee59c..1d12ad20 100644 --- a/src/parser/shell_expand/words.rs +++ b/src/parser/shell_expand/words.rs @@ -1,4 +1,5 @@ use std::io::{self, Write}; +use std::char; use std::str::FromStr; use super::{ExpanderFunctions, expand_string}; use super::ranges::parse_index_range; @@ -54,41 +55,73 @@ impl FromStr for Index { } } +#[derive(Debug, PartialEq, Clone)] +enum Pattern<'a> { + StringPattern(&'a str), + Whitespace, +} + #[derive(Debug, PartialEq, Clone)] pub struct ArrayMethod<'a> { method: &'a str, variable: &'a str, - pattern: &'a str, + pattern: Pattern<'a>, index: Index } impl<'a> ArrayMethod<'a> { pub fn handle(self, current: &mut String, expand_func: &ExpanderFunctions) { - let pattern = &expand_string(self.pattern, expand_func, false).join(" "); match self.method { "split" => if let Some(variable) = (expand_func.variable)(self.variable, false) { - match self.index { - Index::All => current.push_str ( - &variable.split(pattern) + match (self.pattern, self.index) { + (Pattern::StringPattern(pattern), Index::All) => current.push_str ( + &variable.split(&expand_string(pattern, expand_func, false).join(" ")) + .collect::<Vec<&str>>() + .join(" ") + ), + (Pattern::Whitespace, Index::All) => current.push_str ( + &variable.split(char::is_whitespace) .collect::<Vec<&str>>() .join(" ") ), - Index::None => (), - Index::ID(id) => current.push_str ( - variable.split(pattern) + (_, Index::None) => (), + (Pattern::StringPattern(pattern), Index::ID(id)) => current.push_str ( + variable.split(&expand_string(pattern, expand_func, false).join(" ")) .nth(id) .unwrap_or_default() ), - Index::Range(start, IndexPosition::ID(end)) => { - let range = variable.split(pattern).skip(start) - .take(end-start) + (Pattern::Whitespace, Index::ID(id)) => current.push_str ( + variable.split(char::is_whitespace) + .nth(id) + .unwrap_or_default() + ), + (Pattern::StringPattern(pattern), Index::Range(start, IndexPosition::ID(end))) => { + let range = variable.split(&expand_string(pattern, expand_func, false).join(" ")) + .skip(start).take(end-start) + .collect::<Vec<&str>>() + .join(" "); + + current.push_str(&range); + }, + (Pattern::Whitespace, Index::Range(start, IndexPosition::ID(end))) => { + let range = variable.split(char::is_whitespace) + .skip(start).take(end-start) .collect::<Vec<&str>>() .join(" "); current.push_str(&range); }, - Index::Range(start, IndexPosition::CatchAll) => { - let range = variable.split(pattern).skip(start) + (Pattern::StringPattern(pattern), Index::Range(start, IndexPosition::CatchAll)) => { + let range = variable.split(&expand_string(pattern, expand_func, false).join(" ")) + .skip(start) + .collect::<Vec<&str>>() + .join(" "); + + current.push_str(&range); + } + (Pattern::Whitespace, Index::Range(start, IndexPosition::CatchAll)) => { + let range = variable.split(char::is_whitespace) + .skip(start) .collect::<Vec<&str>>() .join(" "); @@ -105,24 +138,46 @@ impl<'a> ArrayMethod<'a> { } pub fn handle_as_array(self, expand_func: &ExpanderFunctions) -> Vec<String> { - let pattern = &expand_string(self.pattern, expand_func, false).join(" "); match self.method { "split" => if let Some(variable) = (expand_func.variable)(self.variable, false) { - return match self.index { - Index::All => variable.split(pattern) + return match (self.pattern, self.index) { + (_, Index::None) => vec!["".to_owned()], + (Pattern::StringPattern(pattern), Index::All) => variable + .split(&expand_string(pattern, expand_func, false).join(" ")) .map(String::from) .collect::<Vec<String>>(), - Index::None => vec!["".to_owned()], - Index::ID(id) => vec![variable.split(pattern) + (Pattern::Whitespace, Index::All) => variable + .split(char::is_whitespace) + .map(String::from) + .collect::<Vec<String>>(), + (Pattern::StringPattern(pattern), Index::ID(id)) => vec![variable + .split(&expand_string(pattern, expand_func, false).join(" ")) + .nth(id).map(String::from) + .unwrap_or_default()], + (Pattern::Whitespace, Index::ID(id)) => vec![variable + .split(char::is_whitespace) .nth(id).map(String::from) .unwrap_or_default()], - Index::Range(start, IndexPosition::CatchAll) => { - variable.split(pattern).skip(start) + (Pattern::StringPattern(pattern), Index::Range(start, IndexPosition::CatchAll)) => { + variable.split(&expand_string(pattern, expand_func, false).join(" ")) + .skip(start) + .map(String::from) + .collect::<Vec<String>>() + }, + (Pattern::Whitespace, Index::Range(start, IndexPosition::CatchAll)) => { + variable.split(char::is_whitespace) + .skip(start) + .map(String::from) + .collect::<Vec<String>>() + }, + (Pattern::StringPattern(pattern), Index::Range(start, IndexPosition::ID(end))) => { + variable.split(&expand_string(pattern, expand_func, false).join(" ")).skip(start) + .take(end-start) .map(String::from) .collect::<Vec<String>>() }, - Index::Range(start, IndexPosition::ID(end)) => { - variable.split(pattern).skip(start) + (Pattern::Whitespace, Index::Range(start, IndexPosition::ID(end))) => { + variable.split(char::is_whitespace).skip(start) .take(end-start) .map(String::from) .collect::<Vec<String>>() @@ -331,14 +386,14 @@ impl<'a> WordIterator<'a> { WordToken::ArrayMethod(ArrayMethod { method: method, variable: variable, - pattern: pattern, + pattern: Pattern::StringPattern(pattern), index: self.read_index(iterator) }) } else { WordToken::ArrayMethod(ArrayMethod { method: method, variable: variable, - pattern: pattern, + pattern: Pattern::StringPattern(pattern), index: Index::All }) } @@ -355,14 +410,14 @@ impl<'a> WordIterator<'a> { WordToken::ArrayMethod(ArrayMethod { method: method, variable: variable, - pattern: " ", + pattern: Pattern::Whitespace, index: self.read_index(iterator) }) } else { WordToken::ArrayMethod(ArrayMethod { method: method, variable: variable, - pattern: " ", + pattern: Pattern::Whitespace, index: Index::All }) } -- GitLab