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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
//! 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>,
},
// Revision awareness (v1.5, plans/0016 M1). All scoped by
// repo/path so late landings are dropped by the UI.
/// Refs for the switcher popup.
RefsLoaded {
repo: String,
refs: crate::provider::RepoRefs,
},
RefsFailed {
repo: String,
error: ProviderError,
},
/// Commit log for the history lens.
LogLoaded {
path: String,
entries: Vec<crate::provider::LogEntry>,
truncated: bool,
},
LogFailed {
path: String,
error: ProviderError,
},
/// Blame ranges for the blame lens.
BlameLoaded {
path: String,
ranges: Vec<crate::provider::BlameRange>,
},
BlameFailed {
path: String,
error: ProviderError,
},
/// File bytes at a commit (open-at-commit from the history lens);
/// the commit's subject/author/date dress the header band.
BlobAtLoaded {
path: String,
ref_: String,
sha: String,
bytes: Vec<u8>,
subject: String,
author: String,
date: String,
},
BlobAtFailed {
path: String,
error: ProviderError,
},
/// Startup update check (0017 M3): a newer release tag exists.
/// `toast` (0018 M2): the once-a-day status nag was still due
/// when the worker consumed it — the chip shows either way.
UpdateAvailable {
tag: String,
toast: bool,
},
}
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()
}