Repository: helix-editor/helix
File: helix-term/src/ui/mod.rs (Rust)

Code before:
                    let path = entry.path();
                    let mut path = if is_tilde {
                        // if it's a single tilde an absolute path is displayed so that when `TAB` is pressed on
                        // one of the directories the tilde will be replaced with a valid path not with a relative
                        // home directory name.
                        // ~ -> <TAB> -> /home/user
                        // ~/ -> <TAB> -> ~/first_entry
                        path.to_path_buf()
                    } else {
                        path.strip_prefix(&dir).unwrap_or(path).to_path_buf()
                    };

                    if fmatch == FileMatch::AcceptIncomplete {
                        path.push("");
                    }

                    let path = path.into_os_string().into_string().ok()?;
                    Some(Cow::from(path))
                })
            }) // TODO: unwrap or skip
            .filter(|path| !path.is_empty());

        let directory_color = editor.theme.get("ui.text.directory");

        let style_from_file = |file: Cow<'static, str>| {
            if file.ends_with(std::path::MAIN_SEPARATOR) {
                Span::styled(file, directory_color)
            } else {
                Span::raw(file)
            }
        };

        // if empty, return a list of dirs and files in current dir
        if let Some(file_name) = file_name {
            let range = (input.len().saturating_sub(file_name.len()))..;
            fuzzy_match(&file_name, files, true)
                .into_iter()
                .map(|(name, _)| (range.clone(), style_from_file(name)))
                .collect()

            // TODO: complete to longest common match
        } else {
            let mut files: Vec<_> = files
                .map(|file| (end.clone(), style_from_file(file)))
                .collect();
            files.sort_unstable_by(|(_, path1), (_, path2)| path1.content.cmp(&path2.content));
            files
        }
    }

    pub fn register(editor: &Editor, input: &str) -> Vec<Completion> {

Review comment (refactor):
Instead of checking the end of the string we can actually determine if these files are directories or without the filesystem-access-per-file (mentioned earlier in review) by uncommenting from above:

```rust
let is_dir = entry.file_type().is_some_and(|entry| entry.is_dir());
```

(`DirEntry` already stores the file type and `file_type` just accesses that info, no extra fs access.)

This should fix the colors when using something like `:cd` that uses the directory completer.

There's a bit of overlap between this and #11285 so I would suggest adding a struct near the top of this file

```rust
struct Utf8PathBuf {
    path: String,
    is_dir: bool,
}
```

And the `filter_map` in `filename_impl` can return that type. Then to make it play well with `fuzzy_match` helper we can implement `AsRef<str>` for that struct:

```rust
impl AsRef<str> for Utf8PathBuf {
    fn as_ref(&str) -> &str {
        &self.path
    }
}
```

Then later #11285 can reuse this type instead of the `(PathBuf, bool)` it uses currently.

Code after:
            .max_depth(Some(1))
            .build()
            .filter_map(|file| {
                file.ok().and_then(|entry| {
                    let fmatch = filter_fn(&entry);

                    if fmatch == FileMatch::Reject {
                        return None;
                    }

                    let is_dir = entry.file_type().is_some_and(|entry| entry.is_dir());

                    let path = entry.path();
                    let mut path = if is_tilde {
                        // if it's a single tilde an absolute path is displayed so that when `TAB` is pressed on
                        // one of the directories the tilde will be replaced with a valid path not with a relative
                        // home directory name.
                        // ~ -> <TAB> -> /home/user
                        // ~/ -> <TAB> -> ~/first_entry
                        path.to_path_buf()
                    } else {
                        path.strip_prefix(&dir).unwrap_or(path).to_path_buf()
                    };

                    if fmatch == FileMatch::AcceptIncomplete {
                        path.push("");
                    }

                    let path = path.into_os_string().into_string().ok()?;
                    Some(Utf8PathBuf { path, is_dir })
                })
            }) // TODO: unwrap or skip
            .filter(|path| !path.path.is_empty());

        let directory_color = editor.theme.get("ui.text.directory");

        let style_from_file = |file: Utf8PathBuf| {
            if file.is_dir {
                Span::styled(file.path, directory_color)
            } else {
                Span::raw(file.path)
            }
        };

        // if empty, return a list of dirs and files in current dir
        if let Some(file_name) = file_name {
            let range = (input.len().saturating_sub(file_name.len()))..;
            fuzzy_match(&file_name, files, true)
                .into_iter()
                .map(|(name, _)| (range.clone(), style_from_file(name)))
                .collect()