# Selection API Migration (EntryId-only)

This document describes the breaking API changes introduced by the EntryId-only selection refactor in `dear-file-browser`.

## Why this change

Selection, focus, and range anchor are now modeled by stable `EntryId` values instead of base-name strings.

Benefits:

- deterministic behavior under sorting/filtering
- robust handling for duplicate names
- cleaner state model without name-based fallback mirrors

## Breaking changes

### `CoreEvent`

Removed name-based variants:

- `CoreEvent::FocusAndSelectByName(String)`
- `CoreEvent::ReplaceSelectionByNames(Vec<String>)`

Canonical write-path variants:

- `CoreEvent::FocusAndSelectById(EntryId)`
- `CoreEvent::ReplaceSelectionByIds(Vec<EntryId>)`

### `FileDialogCore` API

Removed name-based mutating APIs:

- `focus_and_select_by_name(...)`
- `replace_selection_by_names(...)`
- `entry_id_by_name(&str) -> Option<EntryId>`
- `entry_name_by_id(EntryId) -> Option<&str>`

Canonical ID-first APIs:

- `focus_and_select_by_id(EntryId)`
- `replace_selection_by_ids<I: IntoIterator<Item = EntryId>>(...)`
- `selected_entry_ids() -> Vec<EntryId>`
- `focused_entry_id() -> Option<EntryId>`
- `entry_path_by_id(EntryId) -> Option<&Path>`

Name read helpers were also removed from public API:

- `selected_names() -> Vec<String>`

### `CustomPaneCtx` API

The custom pane context is now ID-first as well:

- removed: `selected_names: &[String]`
- added: `selected_entry_ids: &[EntryId]`
- added: `selected_paths: &[PathBuf]`
- added: `selected_files_count: usize`
- added: `selected_dirs_count: usize`

## Migration patterns

### 1) Event-driven replacement

Before:

```rust
core.handle_event(CoreEvent::ReplaceSelectionByNames(vec!["a.txt".into()]));
```

After:

```rust
let id = EntryId::from_path(&core.cwd.join("a.txt"));
core.handle_event(CoreEvent::ReplaceSelectionByIds(vec![id]));
```

### 2) Direct API replacement

Before:

```rust
core.focus_and_select_by_name("new_folder");
```

After:

```rust
let id = EntryId::from_path(&core.cwd.join("new_folder"));
core.focus_and_select_by_id(id);
```

### 3) Batch selection replacement

Before:

```rust
core.replace_selection_by_names(vec!["a.txt".into(), "b.txt".into()]);
```

After:

```rust
let ids = ["a.txt", "b.txt"]
    .iter()
    .map(|name| EntryId::from_path(&core.cwd.join(name)))
    .collect::<Vec<_>>();
core.replace_selection_by_ids(ids);
```

### 4) Resolve IDs to paths

```rust
let selected_paths = core
    .selected_entry_ids()
    .into_iter()
    .filter_map(|id| core.entry_path_by_id(id).map(std::path::Path::to_path_buf))
    .collect::<Vec<_>>();
```

## Notes

- There is no name-based compatibility layer anymore.
- For create/rename/paste flows, select by `EntryId::from_path(...)` immediately and let next rescan resolve display names.
- If callers need paths before confirm, resolve them with `selected_entry_ids()` + `entry_path_by_id()`.
