message: Refactor filename completion as an iterator to set up for when liner uses iterators
diff: @@ -48,8 +48,7 @@ impl Completer for IonFileCompleter {
  if let Some(expanded) = unsafe { (*self.vars).tilde_expansion(start, &*self.dir_stack) }
  {
  // Now we obtain completions for the `expanded` form of the `start` value.
  - let completions = filename_completion(&expanded, |x| self.inner.completions(x));
  - let mut iterator = completions.iter();
  + let mut iterator = FilenameCompletion::new(&expanded, |x| self.inner.completions(x));
  // And then we will need to take those completions and remove the expanded form
  // of the tilde pattern and replace it with that pattern yet again.
  @@ -92,14 +91,16 @@ impl Completer for IonFileCompleter {
  }
  }
  - filename_completion(&start, |x| self.inner.completions(x))
  + FilenameCompletion::new(&start, |x| self.inner.completions(x)).collect()
  }
  }
  -fn filename_completion<LC>(start: &str, liner_complete: LC) -> Vec<String>
  -where
  - LC: Fn(&str) -> Vec<String>,
  -{
  +pub struct FilenameCompletion<'a> {
  + iter: Box<Iterator<Item = String> + 'a>,
  +}
  +
  +impl<'a> FilenameCompletion<'a> {
  + pub fn new<LC: Fn(&str) -> Vec<String> + 'a>(start: &'a str, liner_complete: LC) -> Self {
  let unescaped_start = unescape(start);
  let split_start = unescaped_start.split("/");
  @@ -123,31 +124,41 @@ where
  };
  start_for_glob.pop(); // pop out the last '/' character
  - let mut inner_glob: Vec<String> = match glob(&start_for_glob) {
  - Ok(completions) => completions
  + let iter_inner_glob: Box<Iterator<Item = String>> = match glob(&start_for_glob) {
  + Ok(completions) => {
  + let mut iter = completions
  .filter_map(Result::ok)
  .map(|x| x.to_string_lossy().into_owned())
  - .collect(),
  - _ => vec![],
  - };
  - if inner_glob.len() == 0 {
  - inner_glob.push(escape(&start.to_string()));
  + .peekable();
  + if iter.peek().is_some() {
  + Box::new(iter)
  + } else {
  + Box::new(Some(escape(start)).into_iter())
  }
  -
  - let mut completions = vec![];
  + }
  + _ => Box::new(Some(escape(start)).into_iter()),
  + };
  // Use Liner::Completer as well, to preserve the previous behaviour
  // around single-directory completions
  - for path in inner_glob {
  - let liner_completions: Vec<String> = liner_complete(&path)
  - .iter()
  + let iter = iter_inner_glob.flat_map(move |path| {
  + liner_complete(&path)
  + .into_iter()
  .map(|x| escape(x.as_str()))
  - .collect();
  - for c in liner_completions {
  - completions.push(c)
  + });
  +
  + FilenameCompletion {
  + iter: Box::new(iter),
  }
  }
  - completions
  +}
  +
  +impl<'a> Iterator for FilenameCompletion<'a> {
  + type Item = String;
  +
  + fn next(&mut self) -> Option<Self::Item> {
  + self.iter.next()
  + }
  }
  /// Escapes filenames from the completer so that special characters will be properly escaped.
  