WIP: Working modal, without navigation and search on every keystroke

This commit is contained in:
KCaverly 2023-06-28 13:27:26 -04:00
parent 9d19dea7dd
commit 40ff7779bb
4 changed files with 146 additions and 19 deletions

2
Cargo.lock generated
View file

@ -7960,6 +7960,7 @@ dependencies = [
"log",
"matrixmultiply",
"ndarray",
"picker",
"project",
"rand 0.8.5",
"rusqlite",
@ -7968,6 +7969,7 @@ dependencies = [
"sha-1 0.10.1",
"smol",
"tempdir",
"theme",
"tree-sitter",
"tree-sitter-rust",
"unindent",

View file

@ -14,6 +14,8 @@ language = { path = "../language" }
project = { path = "../project" }
workspace = { path = "../workspace" }
util = { path = "../util" }
picker = { path = "../picker" }
theme = { path = "../theme" }
anyhow.workspace = true
futures.workspace = true
smol.workspace = true

View file

@ -0,0 +1,107 @@
use std::sync::Arc;
use gpui::{
actions, elements::*, AnyElement, AppContext, ModelHandle, MouseState, Task, ViewContext,
WeakViewHandle,
};
use picker::{Picker, PickerDelegate, PickerEvent};
use project::Project;
use util::ResultExt;
use workspace::Workspace;
use crate::{SearchResult, VectorStore};
actions!(semantic_search, [Toggle]);
pub type SemanticSearch = Picker<SemanticSearchDelegate>;
pub struct SemanticSearchDelegate {
workspace: WeakViewHandle<Workspace>,
project: ModelHandle<Project>,
vector_store: ModelHandle<VectorStore>,
selected_match_index: usize,
matches: Vec<SearchResult>,
}
impl SemanticSearchDelegate {
// This is currently searching on every keystroke,
// This is wildly overkill, and has the potential to get expensive
// We will need to update this to throttle searching
pub fn new(
workspace: WeakViewHandle<Workspace>,
project: ModelHandle<Project>,
vector_store: ModelHandle<VectorStore>,
) -> Self {
Self {
workspace,
project,
vector_store,
selected_match_index: 0,
matches: vec![],
}
}
}
impl PickerDelegate for SemanticSearchDelegate {
fn placeholder_text(&self) -> Arc<str> {
"Search repository in natural language...".into()
}
fn confirm(&mut self, cx: &mut ViewContext<SemanticSearch>) {
todo!()
}
fn dismissed(&mut self, _cx: &mut ViewContext<SemanticSearch>) {}
fn match_count(&self) -> usize {
self.matches.len()
}
fn selected_index(&self) -> usize {
self.selected_match_index
}
fn set_selected_index(&mut self, ix: usize, _cx: &mut ViewContext<SemanticSearch>) {
self.selected_match_index = ix;
}
fn update_matches(&mut self, query: String, cx: &mut ViewContext<SemanticSearch>) -> Task<()> {
let task = self
.vector_store
.update(cx, |store, cx| store.search(query.to_string(), 10, cx));
cx.spawn(|this, mut cx| async move {
let results = task.await.log_err();
this.update(&mut cx, |this, cx| {
if let Some(results) = results {
let delegate = this.delegate_mut();
delegate.matches = results;
}
});
})
}
fn render_match(
&self,
ix: usize,
mouse_state: &mut MouseState,
selected: bool,
cx: &AppContext,
) -> AnyElement<Picker<Self>> {
let theme = theme::current(cx);
let style = &theme.picker.item;
let current_style = style.style_for(mouse_state, selected);
let search_result = &self.matches[ix];
let mut path = search_result.file_path.to_string_lossy();
let name = search_result.name.clone();
Flex::column()
.with_child(Text::new(name, current_style.label.text.clone()).with_soft_wrap(false))
.with_child(Label::new(path.to_string(), style.default.label.clone()))
.contained()
.with_style(current_style.container)
.into_any()
}
}

View file

@ -1,5 +1,6 @@
mod db;
mod embedding;
mod modal;
mod search;
#[cfg(test)]
@ -10,6 +11,7 @@ use db::{FileSha1, VectorDatabase, VECTOR_DB_URL};
use embedding::{EmbeddingProvider, OpenAIEmbeddings};
use gpui::{actions, AppContext, Entity, ModelContext, ModelHandle, Task, ViewContext};
use language::{Language, LanguageRegistry};
use modal::{SemanticSearch, SemanticSearchDelegate, Toggle};
use project::{Fs, Project};
use smol::channel;
use std::{cmp::Ordering, collections::HashMap, path::PathBuf, sync::Arc};
@ -17,8 +19,6 @@ use tree_sitter::{Parser, QueryCursor};
use util::{http::HttpClient, ResultExt, TryFutureExt};
use workspace::{Workspace, WorkspaceCreated};
actions!(semantic_search, [TestSearch]);
#[derive(Debug)]
pub struct Document {
pub offset: usize,
@ -60,24 +60,40 @@ pub fn init(
.detach();
cx.add_action({
let vector_store = vector_store.clone();
move |workspace: &mut Workspace, _: &TestSearch, cx: &mut ViewContext<Workspace>| {
let t0 = std::time::Instant::now();
let task = vector_store.update(cx, |store, cx| {
store.search("compute embeddings for all of the symbols in the codebase and write them to a database".to_string(), 10, cx)
});
cx.spawn(|this, cx| async move {
let results = task.await?;
let duration = t0.elapsed();
println!("search took {:?}", duration);
println!("results {:?}", results);
anyhow::Ok(())
}).detach()
move |workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>| {
let vector_store = vector_store.clone();
workspace.toggle_modal(cx, |workspace, cx| {
let project = workspace.project().clone();
let workspace = cx.weak_handle();
cx.add_view(|cx| {
SemanticSearch::new(
SemanticSearchDelegate::new(workspace, project, vector_store),
cx,
)
})
})
}
});
SemanticSearch::init(cx);
// cx.add_action({
// let vector_store = vector_store.clone();
// move |workspace: &mut Workspace, _: &TestSearch, cx: &mut ViewContext<Workspace>| {
// let t0 = std::time::Instant::now();
// let task = vector_store.update(cx, |store, cx| {
// store.search("compute embeddings for all of the symbols in the codebase and write them to a database".to_string(), 10, cx)
// });
// cx.spawn(|this, cx| async move {
// let results = task.await?;
// let duration = t0.elapsed();
// println!("search took {:?}", duration);
// println!("results {:?}", results);
// anyhow::Ok(())
// }).detach()
// }
// });
}
#[derive(Debug)]
@ -87,7 +103,7 @@ pub struct IndexedFile {
documents: Vec<Document>,
}
struct VectorStore {
pub struct VectorStore {
fs: Arc<dyn Fs>,
database_url: Arc<str>,
embedding_provider: Arc<dyn EmbeddingProvider>,