iced-swdir-tree 0.2.0

iced widget for file tree powered by swdir, supporting selection, lazy loading and filtering.
Documentation
# Architecture

```text
src/
  lib.rs                       # Re-exports and crate docs
  directory_tree.rs            # State struct and builder methods
  directory_tree/
    config.rs                  # DirectoryFilter, TreeConfig
    error.rs                   # Crate Error type
    executor.rs                # ScanExecutor trait, ThreadExecutor default
    icon.rs                    # Feature-gated icon renderer (lucide / text)
    keyboard.rs                # handle_key adapter + bindings
    message.rs                 # DirectoryTreeEvent + LoadPayload
    node.rs                    # TreeNode, LoadedEntry, TreeCache
    update.rs                  # State machine for update()
    view.rs                    # Render function for view()
    walker.rs                  # async scan wrapper + normalization
```

The public API is intentionally small. The internal layering
separates state ownership (`directory_tree.rs`), events (`message.rs`),
state transitions (`update.rs`), rendering (`view.rs`), data access
(`walker.rs`), blocking-work dispatch (`executor.rs`), and keyboard
translation (`keyboard.rs`), which makes room for the v0.4+ roadmap
items (multi-select, drag-and-drop, custom icon themes) without
touching the widget surface.

## Selection cursor

Selection is stored by path on `DirectoryTree::selected_path` — the
canonical cursor. The per-node `TreeNode::is_selected` flag is a
view-layer cache that the update layer keeps in sync. This lets
filter changes and subtree reloads preserve the user's selection
even when the selected node's in-memory representation is
reconstructed from scratch.

## Scan dispatch

`walker::scan` is runtime-agnostic: it produces an `iced::Task`
backed by a `ScanFuture`, itself obtained from
`Arc<dyn ScanExecutor>`. The default `ThreadExecutor` spawns one
`std::thread` per scan, which is correct but slightly wasteful for
apps that already run a blocking-task pool. Those apps can
implement `ScanExecutor` (one method, `spawn_blocking`) and swap
it in at construction time via `DirectoryTree::with_executor`.