Enable exact match behavior for any path with slashes (#15458)

# Description

Closes #14794. This PR enables the strict exact match behavior requested
in #13204 and #14794 for any path containing a slash (#13302 implemented
this for paths ending in slashes).

If any of the components along the way *don't* exactly match a
directory, then the next components will use the old Fish-like
completion behavior rather than the strict behavior.

This change only affects those using prefix matching. Fuzzy matching
remains unaffected.

# User-Facing Changes

Suppose you have the following directory structure:
```
- foo
  - bar
    - xyzzy
  - barbaz
    - xyzzy
- foobar
  - bar
    - xyzzy
  - barbaz
    - xyzzy
```

- If you type `cd foo<TAB>`, you will be suggested `[foo, foobar]`
- This is because `foo` is the last component of the path, so the strict
behavior isn't activated
  - Similarly, `foo/bar` will show you `[foo/bar, foo/barbaz]`
- If you type `foo/bar/x`, you will be suggested `[foo/bar/xyzzy]`
  - This is because `foo` and `bar` both exactly matched a directory
- If you type `foo/b/x`, you will be suggested `[foo/bar/xyzzy,
foo/barbaz/xyzzy]`
- This is because `foo` matches a directory exactly, so `foobar/*` won't
be suggested, but `b` doesn't exactly match a directory, so both `bar`
and `barbaz` are suggested
- If you type `f/b/x`, you will be suggested all four of the `xyzzy`
files above
- If you type `f/bar/x`, you will be suggested all four of the `xyzzy`
files above
- Since `f` doesn't exactly match a directory, every component after it
won't use the strict matching behavior (even though `bar` exactly
matches a directory)

# Tests + Formatting

# After Submitting

This is a pretty minor change but should be mentioned somewhere in the
release notes in case it surprises someone.

---------

Co-authored-by: 132ikl <132@ikl.sh>
This commit is contained in:
Yash Thakur
2025-03-31 14:19:09 -04:00
committed by GitHub
parent 9aba96604b
commit 5c2bcd068b
4 changed files with 62 additions and 21 deletions

View File

@ -951,10 +951,11 @@ fn partial_completions() {
// Create the expected values
let expected_paths = [
file(dir.join("partial").join("hello.txt")),
folder(dir.join("partial").join("hol")),
file(dir.join("partial-a").join("have_ext.exe")),
file(dir.join("partial-a").join("have_ext.txt")),
file(dir.join("partial-a").join("hello")),
file(dir.join("partial-a").join("hola")),
folder(dir.join("partial-a").join("hola")),
file(dir.join("partial-b").join("hello_b")),
file(dir.join("partial-b").join("hi_b")),
file(dir.join("partial-c").join("hello_c")),
@ -971,11 +972,12 @@ fn partial_completions() {
// Create the expected values
let expected_paths = [
file(dir.join("partial").join("hello.txt")),
folder(dir.join("partial").join("hol")),
file(dir.join("partial-a").join("anotherfile")),
file(dir.join("partial-a").join("have_ext.exe")),
file(dir.join("partial-a").join("have_ext.txt")),
file(dir.join("partial-a").join("hello")),
file(dir.join("partial-a").join("hola")),
folder(dir.join("partial-a").join("hola")),
file(dir.join("partial-b").join("hello_b")),
file(dir.join("partial-b").join("hi_b")),
file(dir.join("partial-c").join("hello_c")),
@ -2215,15 +2217,43 @@ fn exact_match() {
let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack));
// Troll case to test if exact match logic works case insensitively
let target_dir = format!("open {}", folder(dir.join("pArTiAL")));
let suggestions = completer.complete(&target_dir, target_dir.len());
// Since it's an exact match, only 'partial' should be suggested, not
// 'partial-a' and stuff. Implemented in #13302
match_suggestions(
&vec![file(dir.join("partial").join("hello.txt")).as_str()],
&vec![
file(dir.join("partial").join("hello.txt")).as_str(),
folder(dir.join("partial").join("hol")).as_str(),
],
&suggestions,
);
let target_dir = format!("open {}", file(dir.join("partial").join("h")));
let suggestions = completer.complete(&target_dir, target_dir.len());
match_suggestions(
&vec![
file(dir.join("partial").join("hello.txt")).as_str(),
folder(dir.join("partial").join("hol")).as_str(),
],
&suggestions,
);
// Even though "hol" is an exact match, the first component ("part") wasn't an
// exact match, so we include partial-a/hola
let target_dir = format!("open {}", file(dir.join("part").join("hol")));
let suggestions = completer.complete(&target_dir, target_dir.len());
match_suggestions(
&vec![
folder(dir.join("partial").join("hol")).as_str(),
folder(dir.join("partial-a").join("hola")).as_str(),
],
&suggestions,
);
// Exact match behavior shouldn't be enabled if the path has no slashes
let target_dir = format!("open {}", file(dir.join("partial")));
let suggestions = completer.complete(&target_dir, target_dir.len());
assert!(suggestions.len() > 1);
}
#[ignore = "was reverted, still needs fixing"]