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
//! App events from background workers (GitHub API calls run on worker
//! threads; results return over this channel into the event loop).
use crate::provider::{ProviderError, SearchItem};
#[derive(Debug)]
pub enum AppEvent {
SearchResults {
gen_id: u64,
items: Vec<SearchItem>,
},
SearchFailed {
gen_id: u64,
error: ProviderError,
},
OrgReposLoaded {
org: String,
repos: Vec<crate::provider::RepoInfo>,
},
OrgReposFailed {
org: String,
error: ProviderError,
},
TreeLoaded {
owner: String,
name: String,
entries: Vec<crate::provider::TreeNode>,
truncated: bool,
branch: String,
},
TreeFailed {
owner: String,
name: String,
error: ProviderError,
},
BlobLoaded {
sha: String,
name: String,
bytes: Vec<u8>,
},
BlobFailed {
sha: String,
error: ProviderError,
},
/// Global search view results (plans/0002 §4): raw hits from the
/// worker, styled on the UI thread.
GlobalSearchResults {
gen_id: u64,
hits: Vec<crate::components::global_search::RawHit>,
clipped: bool,
/// v1.3: index freshness ("2026-08-20T14:00:00Z") for indexed
/// backends — rendered next to the result count.
index: Option<String>,
/// v1.2-grammar (plans/0012 M1): hits the client-side
/// subtraction filter removed.
client_filtered: usize,
/// Grammar tokens not expressible anywhere (title chip).
unfiltered: Vec<String>,
},
/// Streamed batch (v1.3, plans/0011): raw hits as the provider
/// emits them; styled on the UI thread, appended under `gen_id`.
GlobalSearchDelta {
gen_id: u64,
hits: Vec<crate::components::global_search::RawHit>,
},
GlobalSearchFailed {
gen_id: u64,
error: ProviderError,
},
/// Lazy per-hit context (plans/0006 §1): blob fetched + located on
/// a worker for the selected bare hit.
HitContextLoaded {
gen_id: u64,
repo: String,
path: String,
sha: String,
line: u32,
preview: Vec<(u32, String)>,
match_count: u32,
query: String,
},
/// Lazy context fetch found no match text in the blob
/// (plans/0008 §4): the hit flips to `unlocatable` instead of
/// rendering stale forever.
HitContextMissing {
gen_id: u64,
sha: String,
},
/// Cursor-rest debounce fired (plans/0008 §3): rapid selection
/// moves collapse into this one dispatch for the hit the cursor
/// finally rested on.
HitContextDebounceFired {
timer_gen: u64,
hit: crate::components::global_search::SearchHit,
query: String,
},
/// Lazy context fetch failed (plans/0008 §2): auth/throttle
/// surfaces a status line; other kinds stay quiet (bare path
/// remains, retry on revisit).
HitContextFailed {
gen_id: u64,
sha: String,
error: ProviderError,
},
/// Expanded file pane (plans/0012 M2): the hit's whole blob, raw
/// bytes — the UI thread sanitizes + highlights at the boundary.
HitFileLoaded {
gen_id: u64,
repo: String,
path: String,
sha: String,
bytes: Vec<u8>,
},
HitFileFailed {
gen_id: u64,
sha: String,
error: crate::provider::ProviderError,
},
CloneDone {
ok: Vec<String>,
failed: Vec<(String, String)>,
},
/// Org marks expanded to their repos; open the clone wizard with
/// the combined list (plans/0004). v1.4: expanded repos carry
/// their listing metadata (sort-by-pushed, grey archived).
CloneExpanded {
repos: Vec<crate::provider::RepoInfo>,
errors: Vec<String>,
},
}
pub type AppTx = std::sync::mpsc::Sender<AppEvent>;
pub type AppRx = std::sync::mpsc::Receiver<AppEvent>;
pub fn channel() -> (AppTx, AppRx) {
std::sync::mpsc::channel()
}