@@ -152,8 +152,46 @@ pub mod completers {
152152 names
153153 }
154154
155− // TODO: we could return an iter/lazy thing so it can fetch as many as it needs.
156155 pub fn filename(input: &str) -> Vec<Completion> {
156+ filename_impl(input, |entry| {
157+ let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());
158+
159+ if is_dir {
160+ FileMatch::AcceptIncomplete
161+ } else {
162+ FileMatch::Accept
163+ }
164+ })
165+ }
166+
167+ pub fn directory(input: &str) -> Vec<Completion> {
168+ filename_impl(input, |entry| {
169+ let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());
170+
171+ if is_dir {
172+ FileMatch::Accept
173+ } else {
174+ FileMatch::Reject
175+ }
176+ })
177+ }
178+
179+ #[derive(Copy, Clone, PartialEq, Eq)]
180+ enum FileMatch {
181+ /// Entry should be ignored
182+ Reject,
183+ /// Entry is usable but can't be the end (for instance if the entry is a directory and we
184+ /// try to match a file)
185+ AcceptIncomplete,
186+ /// Entry is usable and can be the end of the match
187+ Accept,
188+ }
189+
190+ // TODO: we could return an iter/lazy thing so it can fetch as many as it needs.
191+ fn filename_impl<F>(input: &str, filter_fn: F) -> Vec<Completion>
192+ where
193+ F: Fn(&ignore::DirEntry) -> FileMatch,
194+ {
157195 // Rust's filename handling is really annoying.
158196
159197 use ignore::WalkBuilder;
@@ -184,7 +222,13 @@ pub mod completers {
184222 .max_depth(Some(1))
185223 .build()
186224 .filter_map(|file| {
187− file.ok().map(|entry| {
225+ file.ok().and_then(|entry| {
226+ let fmatch = filter_fn(&entry);
227+
228+ if fmatch == FileMatch::Reject {
229+ return None;
230+ }
231+
188232 let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());
189233
190234 let path = entry.path();
@@ -199,11 +243,12 @@ pub mod completers {
199243 path.strip_prefix(&dir).unwrap_or(path).to_path_buf()
200244 };
201245
202− if is_dir {
246+ if fmatch == FileMatch::AcceptIncomplete {
203247 path.push("");
204248 }
249+
205250 let path = path.to_str().unwrap().to_owned();
206− (end.clone(), Cow::from(path))
251+ Some((end.clone(), Cow::from(path)))
207252 })
208253 }) // TODO: unwrap or skip
209254 .filter(|(_, path)| !path.is_empty()) // TODO