1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! v0.6: incremental search with real-time filtering.
//!
//! When an application calls [`DirectoryTree::set_search_query`] with
//! a non-empty query, the widget narrows its visible rows to those
//! whose basename matches the query (case-insensitive substring)
//! **plus** every ancestor of every match — so the user sees both
//! the matching rows and the tree context that leads to them.
//!
//! # How matches are defined
//!
//! The match check is **basename, case-insensitive substring**:
//! `"rEAdMe"` matches both `README.md` and `readme.txt`. The
//! *full* path is not searched — only the file/folder name at
//! that level. This keeps search behaviour predictable (a query
//! for `"src"` doesn't light up every file that happens to live
//! under a `src/` folder).
//!
//! More sophisticated matching (regex, glob, fuzzy, case-sensitive
//! opt-in, full-path mode) is a future extension via a pluggable
//! matcher trait; for v0.6 we pick one predictable default.
//!
//! # Scope: already-loaded nodes only
//!
//! Search operates on **already-loaded nodes only** — it does not
//! trigger filesystem scans. If the user has a folder collapsed and
//! not yet loaded, matches inside it won't appear until the folder
//! is loaded (by user expansion, or by the v0.5 prefetch mechanism).
//!
//! Search *does* descend into loaded-but-collapsed folders, though:
//! if `/foo` has been loaded once (so its children exist in memory)
//! and the user then collapses it, a match deep inside still shows
//! up during search and the ancestor chain is force-rendered
//! regardless of `is_expanded` state.
//!
//! # Integration with other features
//!
//! * **Selection** is orthogonal to search. Selected rows remain
//! selected when hidden by a search query, and reappear when the
//! query clears.
//! * **Filter** (`DirectoryFilter`) operates first; search runs over
//! filter-surviving nodes only. Changing the filter while a
//! search is active re-runs the search over the new filter
//! output.
//! * **Expand state (`is_expanded`)** is ignored while search is
//! active. The widget renders the path-to-match chain even if
//! the user had the ancestors collapsed. When the search is
//! cleared, the saved `is_expanded` state takes effect.
//!
//! [`DirectoryTree::set_search_query`]: crate::DirectoryTree::set_search_query
use HashSet;
use ;
/// The crate-internal search state.
///
/// Held at `DirectoryTree::search: Option<SearchState>` — `None`
/// when search is inactive (the default). Applications don't
/// construct this directly; they drive search through
/// [`DirectoryTree::set_search_query`] /
/// [`DirectoryTree::clear_search`] and observe through
/// [`DirectoryTree::search_query`] /
/// [`DirectoryTree::is_searching`] /
/// [`DirectoryTree::search_match_count`].
///
/// [`DirectoryTree::set_search_query`]: crate::DirectoryTree::set_search_query
/// [`DirectoryTree::clear_search`]: crate::DirectoryTree::clear_search
/// [`DirectoryTree::search_query`]: crate::DirectoryTree::search_query
/// [`DirectoryTree::is_searching`]: crate::DirectoryTree::is_searching
/// [`DirectoryTree::search_match_count`]: crate::DirectoryTree::search_match_count
pub
/// Does `path` match the normalized query?
///
/// Match logic: case-insensitive substring on the basename
/// (`path.file_name()`). A path with no basename (root-only paths
/// like `/` or `C:\`) is compared against its full display form
/// as a fallback — unusual but defensive.
///
/// # Example
///
/// ```ignore
/// use std::path::Path;
/// assert!(matches_query(Path::new("/a/README.md"), "readme"));
/// assert!(matches_query(Path::new("/a/README.md"), "ME.MD"));
/// assert!(!matches_query(Path::new("/a/README.md"), "src"));
/// ```
pub