From 8b9d97cd64d872d5aeac82f6cd2fb44a501076d2 Mon Sep 17 00:00:00 2001 From: gwenn <gtreguier@gmail.com> Date: Wed, 24 Aug 2016 20:34:39 +0200 Subject: [PATCH] Introduce longest_common_prefix function --- src/completion.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 18 +++++++++++++++-- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/completion.rs b/src/completion.rs index 042c9873..0c9ebbd4 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -159,6 +159,33 @@ pub fn extract_word<'l>(line: &'l str, } } +pub fn longest_common_prefix(candidates: &[String]) -> Option<String> { + if candidates.is_empty() { + return None; + } else if candidates.len() == 1 { + return Some(candidates[0].clone()); + } + let mut longest_common_prefix = 0; + 'o: loop { + for i in 0..candidates.len() - 1 { + let b1 = candidates[i].as_bytes(); + let b2 = candidates[i + 1].as_bytes(); + if b1.len() <= longest_common_prefix || b2.len() <= longest_common_prefix || + b1[i] != b2[i] { + break 'o; + } + } + longest_common_prefix += 1; + } + while !candidates[0].is_char_boundary(longest_common_prefix) { + longest_common_prefix -= 1; + } + if longest_common_prefix == 0 { + return None; + } + Some(String::from(&candidates[0][0..longest_common_prefix])) +} + #[cfg(test)] mod tests { use std::collections::BTreeSet; @@ -170,4 +197,26 @@ mod tests { assert_eq!((4, "/usr/local/b"), super::extract_word(line, line.len(), &break_chars)); } + + #[test] + pub fn longest_common_prefix() { + let mut candidates = vec![]; + let lcp = super::longest_common_prefix(&candidates); + assert!(lcp.is_none()); + + let c1 = String::from("User"); + candidates.push(c1.clone()); + let lcp = super::longest_common_prefix(&candidates); + assert_eq!(Some(c1.clone()), lcp); + + let c2 = String::from("Users"); + candidates.push(c2.clone()); + let lcp = super::longest_common_prefix(&candidates); + assert_eq!(Some(c1), lcp); + + let c3 = String::from(""); + candidates.push(c3.clone()); + let lcp = super::longest_common_prefix(&candidates); + assert!(lcp.is_none()); + } } diff --git a/src/lib.rs b/src/lib.rs index efcf868a..1dca7924 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ use std::sync::atomic; #[cfg(unix)] use nix::sys::signal; -use completion::Completer; +use completion::{Completer, longest_common_prefix}; use consts::KeyPress; use history::History; use line_buffer::{LineBuffer, MAX_LINE, WordAction}; @@ -587,9 +587,23 @@ fn complete_line<R: Read>(rdr: &mut tty::RawReader<R>, } } Ok(Some(key)) - } else { + } else if CompletionMode::List == completion_mode { + // beep if ambiguous + if candidates.len() > 1 { + try!(beep()); + } + if let Some(lcp) = longest_common_prefix(&candidates) { + // if we can extend the item, extend it and return to main loop + if lcp.len() > s.line.pos() - start { + completer.update(&mut s.line, start, &lcp); + try!(s.refresh_line()); + return Ok(None); + } + } // TODO ... Ok(None) + } else { + Ok(None) } } -- GitLab