Skip to content

Commit fdd3685

Browse files
committed
wip; i/f for completion
1 parent dd198ae commit fdd3685

4 files changed

Lines changed: 296 additions & 102 deletions

File tree

src/completion.rs

Lines changed: 19 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,25 @@
1-
use std::{collections::BTreeSet, sync::Arc};
1+
use std::sync::Arc;
22

33
use promkit_widgets::{
44
core::{crossterm::event::Event, grapheme::StyledGraphemes, Widget},
55
listbox::{self, Listbox},
66
};
77
use tokio::{
8-
sync::{mpsc, Mutex, RwLock},
9-
task::{self, JoinHandle},
8+
sync::{mpsc, RwLock},
9+
task::JoinHandle,
1010
};
1111

1212
use crate::{
1313
config::CompletionKeybinds,
1414
context::{Index, SharedContext},
1515
guide::{GuideAction, GuideMessage},
16-
json,
16+
jq_completion,
1717
query_editor::QueryEditorAction,
1818
};
1919

20-
/// Progress information for loading suggestions
21-
#[derive(Clone, Default)]
22-
pub struct SuggestionLoadProgress {
23-
pub is_complete: bool,
24-
pub loaded_path_count: usize,
25-
}
26-
27-
/// Store for suggestions with thread-safe access
28-
struct SuggestionStore {
29-
/// Set of all paths extracted from JSON input
30-
paths: BTreeSet<String>,
31-
progress: SuggestionLoadProgress,
32-
}
33-
34-
#[derive(Clone)]
35-
pub struct SharedSuggestionStore(Arc<Mutex<SuggestionStore>>);
36-
37-
impl SharedSuggestionStore {
38-
/// Collect suggestions that start with the given prefix
39-
pub async fn collect_matches(&self, prefix: &str) -> (Vec<String>, SuggestionLoadProgress) {
40-
let store = self.0.lock().await;
41-
let items = store
42-
.paths
43-
.iter()
44-
.filter(|p| p.starts_with(prefix))
45-
.cloned()
46-
.collect::<Vec<_>>();
47-
(items, store.progress.clone())
48-
}
49-
}
50-
51-
/// Spawn a background loader and return shared suggestion store with task handle.
52-
pub fn spawn_initialize(
53-
input: &'static str,
54-
max_streams: Option<usize>,
55-
chunk_size: usize,
56-
) -> (SharedSuggestionStore, JoinHandle<()>) {
57-
let shared = SharedSuggestionStore(Arc::new(Mutex::new(SuggestionStore {
58-
paths: BTreeSet::new(),
59-
progress: SuggestionLoadProgress::default(),
60-
})));
61-
62-
let shared_for_loading = shared.clone();
63-
let loader_task = task::spawn(async move {
64-
// Load paths in a streaming manner and update the shared store incrementally
65-
let iter = match json::get_all_paths(input, max_streams).await {
66-
Ok(iter) => iter,
67-
Err(_) => {
68-
let mut store = shared_for_loading.0.lock().await;
69-
store.progress.is_complete = true;
70-
return;
71-
}
72-
};
73-
74-
// Process paths in chunks to avoid holding the lock for too long
75-
let mut batch = Vec::with_capacity(chunk_size);
76-
for path in iter {
77-
batch.push(path);
78-
79-
if batch.len() >= chunk_size {
80-
let loaded = batch.len();
81-
let mut store = shared_for_loading.0.lock().await;
82-
for item in batch.drain(..) {
83-
store.paths.insert(item);
84-
}
85-
store.progress.loaded_path_count += loaded;
86-
}
87-
}
88-
89-
// Insert any remaining paths after the loop
90-
let remaining = batch.len();
91-
let mut store = shared_for_loading.0.lock().await;
92-
for item in batch {
93-
store.paths.insert(item);
94-
}
95-
96-
// Mark loading as complete and update progress
97-
store.progress.loaded_path_count += remaining;
98-
store.progress.is_complete = true;
99-
});
100-
101-
(shared, loader_task)
102-
}
103-
10420
/// Navigator for managing the state of suggestions
10521
/// and interactions in the completion view.
10622
pub struct CompletionNavigator {
107-
shared_suggestions: SharedSuggestionStore,
10823
state: listbox::State,
10924
/// Number of suggestions to load in each chunk
11025
/// when the user scrolls near the end of the list.
@@ -115,12 +30,10 @@ pub struct CompletionNavigator {
11530

11631
impl CompletionNavigator {
11732
pub fn new(
118-
shared_suggestions: SharedSuggestionStore,
11933
state: listbox::State,
12034
search_result_chunk_size: usize,
12135
) -> Self {
12236
Self {
123-
shared_suggestions,
12437
state,
12538
search_result_chunk_size,
12639
remaining_items: Default::default(),
@@ -198,8 +111,13 @@ impl CompletionNavigator {
198111
None
199112
}
200113

201-
async fn enter(&mut self, prefix: &str) -> (Option<String>, SuggestionLoadProgress) {
202-
let (items, progress) = self.shared_suggestions.collect_matches(prefix).await;
114+
async fn enter(
115+
&mut self,
116+
completion_engine: &jq_completion::CompletionEngine,
117+
query: &str,
118+
cursor_char: usize,
119+
) -> (Option<String>, jq_completion::LoadProgress) {
120+
let (items, progress) = completion_engine.suggest_strings(query, cursor_char).await;
203121
let head_item = self.initialize_session_items(items);
204122
(head_item, progress)
205123
}
@@ -230,8 +148,8 @@ impl CompletionNavigator {
230148
}
231149

232150
pub enum CompletionAction {
233-
/// Triggered when the user enters the completion view with a current query as prefix.
234-
Enter { prefix: String },
151+
/// Triggered when the user enters completion with current query and cursor position.
152+
Enter { query: String, cursor_char: usize },
235153
/// Triggered when the user leaves the completion view.
236154
Leave,
237155
/// Triggered on user input events within the completion view, such as navigation keys.
@@ -242,6 +160,7 @@ pub enum CompletionAction {
242160
pub fn start_completion_task(
243161
mut action_rx: mpsc::Receiver<CompletionAction>,
244162
shared_ctx: SharedContext,
163+
completion_engine: jq_completion::CompletionEngine,
245164
shared_completion: Arc<RwLock<CompletionNavigator>>,
246165
shared_renderer: promkit_widgets::core::render::SharedRenderer<Index>,
247166
query_editor_action_tx: mpsc::Sender<QueryEditorAction>,
@@ -256,8 +175,10 @@ pub fn start_completion_task(
256175
let completion_view = {
257176
let mut completion = shared_completion.write().await;
258177
match action {
259-
CompletionAction::Enter { prefix } => {
260-
let (head_item, load_progress) = completion.enter(&prefix).await;
178+
CompletionAction::Enter { query, cursor_char } => {
179+
let (head_item, load_progress) = completion
180+
.enter(&completion_engine, &query, cursor_char)
181+
.await;
261182
match head_item {
262183
Some(head) => {
263184
let message = if load_progress.is_complete {
@@ -272,7 +193,7 @@ pub fn start_completion_task(
272193
}
273194
None => {
274195
guide_action_tx
275-
.send(GuideAction::Show(GuideMessage::NoSuggestionFound(prefix)))
196+
.send(GuideAction::Show(GuideMessage::NoSuggestionFound(query)))
276197
.await?;
277198
shared_ctx.set_active_index(Index::QueryEditor).await;
278199
completion.clear_session_state();

0 commit comments

Comments
 (0)