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

Code before:
            hit_timeout = true;
            break;
        }
    }
    if hit_timeout {
        std::thread::spawn(move || {
            for file in files {
                if injector.push(file).is_err() {
                    break;
                }
            }
        });
    }
    picker
}

pub fn file_browser(root: PathBuf) -> Result<FilePicker, std::io::Error> {
    let root = helix_stdx::path::canonicalize(root);
    let directory_content = directory_content(&root)?;

    let columns = [PickerColumn::new(
        "path",
        |item: &PathBuf, root: &PathBuf| {
            let name = item.strip_prefix(root).unwrap_or(item).to_string_lossy();
            if item.is_dir() {
                format!("{}/", name).into()
            } else {
                name.into()
            }
        },
    )];
    let picker = Picker::new(
        columns,
        0,
        directory_content,
        root,
        move |cx, path: &PathBuf, action| {
            if path.is_dir() {
                let owned_path = path.clone();
                let callback = Box::pin(async move {
                    let call: Callback =
                        Callback::EditorCompositor(Box::new(move |_editor, compositor| {
                            if let Ok(picker) = file_browser(owned_path) {
                                compositor.push(Box::new(overlay::overlaid(picker)));
                            }
                        }));
                    Ok(call)
                });
                cx.jobs.callback(callback);
            } else if let Err(e) = cx.editor.open(path, action) {
                let err = if let Some(err) = e.source() {

Review comment (suggestion):
Building on the changes in #12205 we can style directories with `"ui.text.directory"`. So `file_browser` will need to be passed `&Editor` to read from the theme and then the Picker's data can be a tuple or a new struct that holds the root and the directory style. So this column definition would instead become something like:

```rust
let columns = [PickerColumn::new(
    "path",
    |(path, is_dir): &(PathBuf, bool), data: &FileBrowserData| {
        let name = path
            .strip_prefix(&data.root)
            .unwrap_or(path)
            .to_string_lossy();
        if *is_dir {
            Span::styled(format!("{}/", name), data.directory_style).into()
        } else {
            name.into()
        }
    },
)];
```

Code after:
            cx.editor.set_error(err);
        }
    })
    .with_preview(|_editor, path| Some((path.as_path().into(), None)));
    let injector = picker.injector();
    let timeout = std::time::Instant::now() + std::time::Duration::from_millis(30);

    let mut hit_timeout = false;
    for file in &mut files {
        if injector.push(file).is_err() {
            break;
        }
        if std::time::Instant::now() >= timeout {
            hit_timeout = true;
            break;
        }
    }
    if hit_timeout {
        std::thread::spawn(move || {
            for file in files {
                if injector.push(file).is_err() {
                    break;
                }
            }
        });
    }
    picker
}

type FileBrowser = Picker<(PathBuf, bool), (PathBuf, Style)>;

pub fn file_browser(root: PathBuf, editor: &Editor) -> Result<FileBrowser, std::io::Error> {
    let directory_style = editor.theme.get("ui.text.directory");
    let directory_content = directory_content(&root)?;

    let columns = [PickerColumn::new(
        "path",
        |(path, is_dir): &(PathBuf, bool), (root, directory_style): &(PathBuf, Style)| {
            let name = path.strip_prefix(root).unwrap_or(path).to_string_lossy();
            if *is_dir {
                Span::styled(format!("{}/", name), *directory_style).into()
            } else {
                name.into()
            }
        },
    )];
    let picker = Picker::new(
        columns,
        0,
        directory_content,
        (root, directory_style),