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

View file

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