From 1fba1b76ec005fefa76b8585c95a075bd7cfc5c2 Mon Sep 17 00:00:00 2001
From: Agustin Chiappe Berrini <jnieve@gmail.com>
Date: Sat, 18 Nov 2017 09:41:40 -0500
Subject: [PATCH] Reduce number of heap allocations

---
 src/parser/shell_expand/mod.rs | 43 +++++++++++++++++++++++++++-------
 1 file changed, 34 insertions(+), 9 deletions(-)

diff --git a/src/parser/shell_expand/mod.rs b/src/parser/shell_expand/mod.rs
index f16a4dfb..aa9171c5 100644
--- a/src/parser/shell_expand/mod.rs
+++ b/src/parser/shell_expand/mod.rs
@@ -50,15 +50,24 @@ fn expand_process<E: Expander>(
             };
             slice(current, output, selection)
         } else {
-            // TODO: Complete this so that we don't need any heap allocations.
-            //       All that we need is to shift bytes to the left when extra spaces are found.
-            //
-            // unsafe {
-            //     let bytes: &mut [u8] = output.as_bytes_mut();
-            //     bytes.iter_mut().filter(|b| **b == b'\n').for_each(|b| *b = b' ');
-            //     slice(current, str::from_utf8_unchecked(&bytes).trim(), selection)
-            // }
-            slice(current, &output.split_whitespace().collect::<Vec<&str>>().join(" "), selection)
+            let mut result = String::with_capacity(output.len());
+            let mut previous_char_was_whitespace = true;
+            output
+                .chars()
+                .for_each(|c| {
+                    match c {
+                        c if !char::is_whitespace(c) => {
+                            result.push(c);
+                            previous_char_was_whitespace = false;
+                        },
+                        c if char::is_whitespace(c) && !previous_char_was_whitespace => {
+                            result.push(' ');
+                            previous_char_was_whitespace = true;
+                        },
+                        _ => (),
+                    }
+                });
+            slice(current, result.trim_right(), selection)
         }
     }
 }
@@ -559,6 +568,22 @@ mod test {
         }
     }
 
+    struct CommandExpander;
+
+    impl Expander for CommandExpander {
+        fn command(&self, cmd: &str) -> Option<Value> {
+            Some(cmd.to_owned())
+        }
+    }
+
+    #[test]
+    fn expand_process_unquoted() {
+        let mut output = String::new();
+        let line = " Mary   had\ta\u{2009}little  \n\t lamb\t";
+        expand_process(&mut output, line, Select::All, &CommandExpander, false);
+        assert_eq!(output, "Mary had a little lamb");
+    }
+
     #[test]
     fn expand_variable_normal_variable() {
         let input = "$FOO:NOT:$BAR";
-- 
GitLab