Compare commits
2 Commits
fix-git-ht
...
simpler-vi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a55e496a23 | ||
|
|
f89996ac21 |
@@ -36,7 +36,7 @@ use futures::future::Shared;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use gpui::{
|
||||
canvas, div, point, relative, rems, uniform_list, Action, AnyElement, AnyView, AppContext,
|
||||
AsyncAppContext, AsyncWindowContext, AvailableSpace, ClipboardItem, Context, Empty,
|
||||
AsyncAppContext, AsyncWindowContext, AvailableSpace, ClipboardItem, StaticContext, Empty,
|
||||
EventEmitter, FocusHandle, FocusableView, FontStyle, FontWeight, HighlightStyle,
|
||||
InteractiveElement, IntoElement, Model, ModelContext, ParentElement, Pixels, Render,
|
||||
SharedString, StatefulInteractiveElement, Styled, Subscription, Task, TextStyle,
|
||||
|
||||
@@ -391,7 +391,7 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use futures::stream::{self};
|
||||
use gpui::{Context, TestAppContext};
|
||||
use gpui::{StaticContext, TestAppContext};
|
||||
use indoc::indoc;
|
||||
use language::{
|
||||
language_settings, tree_sitter_rust, Buffer, Language, LanguageConfig, LanguageMatcher,
|
||||
|
||||
810
crates/assistant/src/prompt_library.rs
Normal file
810
crates/assistant/src/prompt_library.rs
Normal file
@@ -0,0 +1,810 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use chrono::{DateTime, Utc};
|
||||
use collections::HashMap;
|
||||
use editor::Editor;
|
||||
use futures::{
|
||||
future::{self, BoxFuture, Shared},
|
||||
FutureExt,
|
||||
};
|
||||
use fuzzy::StringMatchCandidate;
|
||||
use gpui::{
|
||||
actions, point, size, AppContext, BackgroundExecutor, Bounds, DevicePixels, Empty,
|
||||
EventEmitter, Global, PromptLevel, ReadGlobal, Subscription, Task, TitlebarOptions, View,
|
||||
WindowBounds, WindowHandle, WindowOptions,
|
||||
};
|
||||
use heed::{types::SerdeBincode, Database, RoTxn};
|
||||
use language::{language_settings::SoftWrap, Buffer, LanguageRegistry};
|
||||
use parking_lot::Mutex;
|
||||
use picker::{Picker, PickerDelegate};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
cmp::Reverse,
|
||||
future::Future,
|
||||
path::PathBuf,
|
||||
sync::{atomic::AtomicBool, Arc},
|
||||
};
|
||||
use ui::{
|
||||
div, prelude::*, IconButtonShape, ListItem, ListItemSpacing, ParentElement, Render,
|
||||
SharedString, Styled, TitleBar, Tooltip, ViewContext, VisualContext,
|
||||
};
|
||||
use util::{paths::PROMPTS_DIR, ResultExt};
|
||||
use uuid::Uuid;
|
||||
|
||||
actions!(
|
||||
prompt_library,
|
||||
[NewPrompt, SavePrompt, DeletePrompt, ToggleDefaultPrompt]
|
||||
);
|
||||
|
||||
/// Init starts loading the PromptStore in the background and assigns
|
||||
/// a shared future to a global.
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
let db_path = PROMPTS_DIR.join("prompts-library-db.0.mdb");
|
||||
let prompt_store_future = PromptStore::new(db_path, cx.background_executor().clone())
|
||||
.then(|result| future::ready(result.map(Arc::new).map_err(Arc::new)))
|
||||
.boxed()
|
||||
.shared();
|
||||
cx.set_global(GlobalPromptStore(prompt_store_future))
|
||||
}
|
||||
|
||||
/// This function opens a new prompt library window if one doesn't exist already.
|
||||
/// If one exists, it brings it to the foreground.
|
||||
///
|
||||
/// Note that, when opening a new window, this waits for the PromptStore to be
|
||||
/// initialized. If it was initialized successfully, it returns a window handle
|
||||
/// to a prompt library.
|
||||
pub fn open_prompt_library(
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
cx: &mut AppContext,
|
||||
) -> Task<Result<WindowHandle<PromptLibrary>>> {
|
||||
let existing_window = cx
|
||||
.windows()
|
||||
.into_iter()
|
||||
.find_map(|window| window.downcast::<PromptLibrary>());
|
||||
if let Some(existing_window) = existing_window {
|
||||
existing_window
|
||||
.update(cx, |_, cx| cx.activate_window())
|
||||
.ok();
|
||||
Task::ready(Ok(existing_window))
|
||||
} else {
|
||||
let store = PromptStore::global(cx);
|
||||
cx.spawn(|cx| async move {
|
||||
let store = store.await?;
|
||||
cx.update(|cx| {
|
||||
let bounds = Bounds::centered(
|
||||
None,
|
||||
size(DevicePixels::from(1024), DevicePixels::from(768)),
|
||||
cx,
|
||||
);
|
||||
cx.open_window(
|
||||
WindowOptions {
|
||||
titlebar: Some(TitlebarOptions {
|
||||
title: None,
|
||||
appears_transparent: true,
|
||||
traffic_light_position: Some(point(px(9.0), px(9.0))),
|
||||
}),
|
||||
window_bounds: Some(WindowBounds::Windowed(bounds)),
|
||||
..Default::default()
|
||||
},
|
||||
|cx| cx.new_view(|cx| PromptLibrary::new(store, language_registry, cx)),
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PromptLibrary {
|
||||
store: Arc<PromptStore>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
prompt_editors: HashMap<PromptId, View<Editor>>,
|
||||
active_prompt_id: Option<PromptId>,
|
||||
picker: View<Picker<PromptPickerDelegate>>,
|
||||
pending_load: Task<()>,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
}
|
||||
|
||||
struct PromptPickerDelegate {
|
||||
store: Arc<PromptStore>,
|
||||
selected_index: usize,
|
||||
matches: Vec<PromptMetadata>,
|
||||
}
|
||||
|
||||
enum PromptPickerEvent {
|
||||
Confirmed { prompt_id: PromptId },
|
||||
Deleted { prompt_id: PromptId },
|
||||
ToggledDefault { prompt_id: PromptId },
|
||||
}
|
||||
|
||||
impl EventEmitter<PromptPickerEvent> for Picker<PromptPickerDelegate> {}
|
||||
|
||||
impl PickerDelegate for PromptPickerDelegate {
|
||||
type ListItem = ListItem;
|
||||
|
||||
fn match_count(&self) -> usize {
|
||||
self.matches.len()
|
||||
}
|
||||
|
||||
fn selected_index(&self) -> usize {
|
||||
self.selected_index
|
||||
}
|
||||
|
||||
fn set_selected_index(&mut self, ix: usize, _cx: &mut ViewContext<Picker<Self>>) {
|
||||
self.selected_index = ix;
|
||||
}
|
||||
|
||||
fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc<str> {
|
||||
"Search...".into()
|
||||
}
|
||||
|
||||
fn update_matches(&mut self, query: String, cx: &mut ViewContext<Picker<Self>>) -> Task<()> {
|
||||
let search = self.store.search(query);
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let matches = search.await;
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.delegate.selected_index = 0;
|
||||
this.delegate.matches = matches;
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
}
|
||||
|
||||
fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext<Picker<Self>>) {
|
||||
if let Some(prompt) = self.matches.get(self.selected_index) {
|
||||
cx.emit(PromptPickerEvent::Confirmed {
|
||||
prompt_id: prompt.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn dismissed(&mut self, _cx: &mut ViewContext<Picker<Self>>) {}
|
||||
|
||||
fn render_match(
|
||||
&self,
|
||||
ix: usize,
|
||||
selected: bool,
|
||||
cx: &mut ViewContext<Picker<Self>>,
|
||||
) -> Option<Self::ListItem> {
|
||||
let prompt = self.matches.get(ix)?;
|
||||
let default = prompt.default;
|
||||
let prompt_id = prompt.id;
|
||||
Some(
|
||||
ListItem::new(ix)
|
||||
.inset(true)
|
||||
.spacing(ListItemSpacing::Sparse)
|
||||
.selected(selected)
|
||||
.child(Label::new(
|
||||
prompt.title.clone().unwrap_or("Untitled".into()),
|
||||
))
|
||||
.end_slot(if default {
|
||||
IconButton::new("toggle-default-prompt", IconName::StarFilled)
|
||||
.shape(IconButtonShape::Square)
|
||||
.into_any_element()
|
||||
} else {
|
||||
Empty.into_any()
|
||||
})
|
||||
.end_hover_slot(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(
|
||||
IconButton::new("delete-prompt", IconName::Trash)
|
||||
.shape(IconButtonShape::Square)
|
||||
.tooltip(move |cx| Tooltip::text("Delete Prompt", cx))
|
||||
.on_click(cx.listener(move |_, _, cx| {
|
||||
cx.emit(PromptPickerEvent::Deleted { prompt_id })
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
IconButton::new(
|
||||
"toggle-default-prompt",
|
||||
if default {
|
||||
IconName::StarFilled
|
||||
} else {
|
||||
IconName::Star
|
||||
},
|
||||
)
|
||||
.shape(IconButtonShape::Square)
|
||||
.tooltip(move |cx| {
|
||||
Tooltip::text(
|
||||
if default {
|
||||
"Remove from Default Prompt"
|
||||
} else {
|
||||
"Add to Default Prompt"
|
||||
},
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.on_click(cx.listener(move |_, _, cx| {
|
||||
cx.emit(PromptPickerEvent::ToggledDefault { prompt_id })
|
||||
})),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl PromptLibrary {
|
||||
fn new(
|
||||
store: Arc<PromptStore>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
let delegate = PromptPickerDelegate {
|
||||
store: store.clone(),
|
||||
selected_index: 0,
|
||||
matches: Vec::new(),
|
||||
};
|
||||
|
||||
let picker = cx.new_view(|cx| {
|
||||
let picker = Picker::uniform_list(delegate, cx)
|
||||
.modal(false)
|
||||
.max_height(None);
|
||||
picker.focus(cx);
|
||||
picker
|
||||
});
|
||||
let mut this = Self {
|
||||
store: store.clone(),
|
||||
language_registry,
|
||||
prompt_editors: HashMap::default(),
|
||||
active_prompt_id: None,
|
||||
pending_load: Task::ready(()),
|
||||
_subscriptions: vec![cx.subscribe(&picker, Self::handle_picker_event)],
|
||||
picker,
|
||||
};
|
||||
if let Some(prompt_id) = store.most_recently_saved() {
|
||||
this.load_prompt(prompt_id, false, cx);
|
||||
}
|
||||
this
|
||||
}
|
||||
|
||||
fn handle_picker_event(
|
||||
&mut self,
|
||||
_: View<Picker<PromptPickerDelegate>>,
|
||||
event: &PromptPickerEvent,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
match event {
|
||||
PromptPickerEvent::Confirmed { prompt_id } => {
|
||||
self.load_prompt(*prompt_id, true, cx);
|
||||
}
|
||||
PromptPickerEvent::ToggledDefault { prompt_id } => {
|
||||
self.toggle_default_for_prompt(*prompt_id, cx);
|
||||
}
|
||||
PromptPickerEvent::Deleted { prompt_id } => {
|
||||
self.delete_prompt(*prompt_id, cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_prompt(&mut self, cx: &mut ViewContext<Self>) {
|
||||
let prompt_id = PromptId::new();
|
||||
let save = self.store.save(prompt_id, None, false, "".into());
|
||||
self.picker.update(cx, |picker, cx| picker.refresh(cx));
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
save.await?;
|
||||
this.update(&mut cx, |this, cx| this.load_prompt(prompt_id, true, cx))
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
|
||||
pub fn save_active_prompt(&mut self, cx: &mut ViewContext<Self>) {
|
||||
if let Some(active_prompt_id) = self.active_prompt_id {
|
||||
let prompt_metadata = self.store.metadata(active_prompt_id).unwrap();
|
||||
let body = self
|
||||
.prompt_editors
|
||||
.get_mut(&active_prompt_id)
|
||||
.unwrap()
|
||||
.update(cx, |editor, cx| editor.snapshot(cx));
|
||||
|
||||
let title = title_from_body(body.buffer_chars_at(0).map(|(c, _)| c));
|
||||
self.store
|
||||
.save(
|
||||
active_prompt_id,
|
||||
title,
|
||||
prompt_metadata.default,
|
||||
body.text(),
|
||||
)
|
||||
.detach_and_log_err(cx);
|
||||
self.picker.update(cx, |picker, cx| picker.refresh(cx));
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_active_prompt(&mut self, cx: &mut ViewContext<Self>) {
|
||||
if let Some(active_prompt_id) = self.active_prompt_id {
|
||||
self.delete_prompt(active_prompt_id, cx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_default_for_active_prompt(&mut self, cx: &mut ViewContext<Self>) {
|
||||
if let Some(active_prompt_id) = self.active_prompt_id {
|
||||
self.toggle_default_for_prompt(active_prompt_id, cx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_default_for_prompt(&mut self, prompt_id: PromptId, cx: &mut ViewContext<Self>) {
|
||||
if let Some(prompt_metadata) = self.store.metadata(prompt_id) {
|
||||
self.store
|
||||
.save_metadata(prompt_id, prompt_metadata.title, !prompt_metadata.default)
|
||||
.detach_and_log_err(cx);
|
||||
self.picker.update(cx, |picker, cx| picker.refresh(cx));
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_prompt(&mut self, prompt_id: PromptId, focus: bool, cx: &mut ViewContext<Self>) {
|
||||
if let Some(prompt_editor) = self.prompt_editors.get(&prompt_id) {
|
||||
if focus {
|
||||
prompt_editor.update(cx, |editor, cx| editor.focus(cx));
|
||||
}
|
||||
self.active_prompt_id = Some(prompt_id);
|
||||
} else {
|
||||
let language_registry = self.language_registry.clone();
|
||||
let prompt = self.store.load(prompt_id);
|
||||
self.pending_load = cx.spawn(|this, mut cx| async move {
|
||||
let prompt = prompt.await;
|
||||
let markdown = language_registry.language_for_name("Markdown").await;
|
||||
this.update(&mut cx, |this, cx| match prompt {
|
||||
Ok(prompt) => {
|
||||
let buffer = cx.new_model(|cx| {
|
||||
let mut buffer = Buffer::local(prompt, cx);
|
||||
buffer.set_language(markdown.log_err(), cx);
|
||||
buffer.set_language_registry(language_registry);
|
||||
buffer
|
||||
});
|
||||
let editor = cx.new_view(|cx| {
|
||||
let mut editor = Editor::for_buffer(buffer, None, cx);
|
||||
editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx);
|
||||
editor.set_show_gutter(false, cx);
|
||||
editor.set_show_wrap_guides(false, cx);
|
||||
editor.set_show_indent_guides(false, cx);
|
||||
if focus {
|
||||
editor.focus(cx);
|
||||
}
|
||||
editor
|
||||
});
|
||||
this.prompt_editors.insert(prompt_id, editor);
|
||||
this.active_prompt_id = Some(prompt_id);
|
||||
cx.notify();
|
||||
}
|
||||
Err(error) => {
|
||||
// TODO: we should show the error in the UI.
|
||||
log::error!("error while loading prompt: {:?}", error);
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_prompt(&mut self, prompt_id: PromptId, cx: &mut ViewContext<Self>) {
|
||||
if let Some(metadata) = self.store.metadata(prompt_id) {
|
||||
let confirmation = cx.prompt(
|
||||
PromptLevel::Warning,
|
||||
&format!(
|
||||
"Are you sure you want to delete {}",
|
||||
metadata.title.unwrap_or("Untitled".into())
|
||||
),
|
||||
None,
|
||||
&["Delete", "Cancel"],
|
||||
);
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
if confirmation.await.ok() == Some(0) {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
if this.active_prompt_id == Some(prompt_id) {
|
||||
this.active_prompt_id = None;
|
||||
}
|
||||
this.prompt_editors.remove(&prompt_id);
|
||||
this.store.delete(prompt_id).detach_and_log_err(cx);
|
||||
this.picker.update(cx, |picker, cx| picker.refresh(cx));
|
||||
cx.notify();
|
||||
})?;
|
||||
}
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_prompt_list(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
v_flex()
|
||||
.id("prompt-list")
|
||||
.bg(cx.theme().colors().surface_background)
|
||||
.h_full()
|
||||
.w_1_3()
|
||||
.overflow_x_hidden()
|
||||
.child(
|
||||
h_flex()
|
||||
.bg(cx.theme().colors().background)
|
||||
.p(Spacing::Small.rems(cx))
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.h(TitleBar::height(cx))
|
||||
.w_full()
|
||||
.flex_none()
|
||||
.justify_end()
|
||||
.child(
|
||||
IconButton::new("new-prompt", IconName::Plus)
|
||||
.shape(IconButtonShape::Square)
|
||||
.tooltip(move |cx| Tooltip::for_action("New Prompt", &NewPrompt, cx))
|
||||
.on_click(|_, cx| {
|
||||
cx.dispatch_action(Box::new(NewPrompt));
|
||||
}),
|
||||
),
|
||||
)
|
||||
.child(div().flex_grow().child(self.picker.clone()))
|
||||
}
|
||||
|
||||
fn render_active_prompt(&mut self, cx: &mut ViewContext<PromptLibrary>) -> gpui::Stateful<Div> {
|
||||
div()
|
||||
.w_2_3()
|
||||
.h_full()
|
||||
.id("prompt-editor")
|
||||
.border_l_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.flex_none()
|
||||
.min_w_64()
|
||||
.children(self.active_prompt_id.and_then(|prompt_id| {
|
||||
let prompt_metadata = self.store.metadata(prompt_id)?;
|
||||
let editor = self.prompt_editors[&prompt_id].clone();
|
||||
Some(
|
||||
v_flex()
|
||||
.size_full()
|
||||
.child(
|
||||
h_flex()
|
||||
.h(TitleBar::height(cx))
|
||||
.px(Spacing::Large.rems(cx))
|
||||
.justify_between()
|
||||
.child(
|
||||
Label::new(prompt_metadata.title.unwrap_or("Untitled".into()))
|
||||
.size(LabelSize::Large),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_4()
|
||||
.child(
|
||||
IconButton::new("save-prompt", IconName::Save)
|
||||
.shape(IconButtonShape::Square)
|
||||
.tooltip(move |cx| {
|
||||
Tooltip::for_action(
|
||||
"Save Prompt",
|
||||
&SavePrompt,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.on_click(|_, cx| {
|
||||
cx.dispatch_action(Box::new(SavePrompt));
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
IconButton::new(
|
||||
"toggle-default-prompt",
|
||||
if prompt_metadata.default {
|
||||
IconName::StarFilled
|
||||
} else {
|
||||
IconName::Star
|
||||
},
|
||||
)
|
||||
.shape(IconButtonShape::Square)
|
||||
.tooltip(move |cx| {
|
||||
Tooltip::for_action(
|
||||
if prompt_metadata.default {
|
||||
"Remove from Default Prompt"
|
||||
} else {
|
||||
"Add to Default Prompt"
|
||||
},
|
||||
&ToggleDefaultPrompt,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.on_click(
|
||||
|_, cx| {
|
||||
cx.dispatch_action(Box::new(
|
||||
ToggleDefaultPrompt,
|
||||
));
|
||||
},
|
||||
),
|
||||
)
|
||||
.child(
|
||||
IconButton::new("delete-prompt", IconName::Trash)
|
||||
.shape(IconButtonShape::Square)
|
||||
.tooltip(move |cx| {
|
||||
Tooltip::for_action(
|
||||
"Delete Prompt",
|
||||
&DeletePrompt,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.on_click(|_, cx| {
|
||||
cx.dispatch_action(Box::new(DeletePrompt));
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(div().flex_grow().p(Spacing::Large.rems(cx)).child(editor)),
|
||||
)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for PromptLibrary {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
h_flex()
|
||||
.id("prompt-manager")
|
||||
.key_context("PromptLibrary")
|
||||
.on_action(cx.listener(|this, &NewPrompt, cx| this.new_prompt(cx)))
|
||||
.on_action(cx.listener(|this, &SavePrompt, cx| this.save_active_prompt(cx)))
|
||||
.on_action(cx.listener(|this, &DeletePrompt, cx| this.delete_active_prompt(cx)))
|
||||
.on_action(cx.listener(|this, &ToggleDefaultPrompt, cx| {
|
||||
this.toggle_default_for_active_prompt(cx)
|
||||
}))
|
||||
.size_full()
|
||||
.overflow_hidden()
|
||||
.child(self.render_prompt_list(cx))
|
||||
.child(self.render_active_prompt(cx))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct PromptMetadata {
|
||||
pub id: PromptId,
|
||||
pub title: Option<SharedString>,
|
||||
pub default: bool,
|
||||
pub saved_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct PromptId(Uuid);
|
||||
|
||||
impl PromptId {
|
||||
pub fn new() -> PromptId {
|
||||
PromptId(Uuid::new_v4())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PromptStore {
|
||||
executor: BackgroundExecutor,
|
||||
env: heed::Env,
|
||||
bodies: Database<SerdeBincode<PromptId>, SerdeBincode<String>>,
|
||||
metadata: Database<SerdeBincode<PromptId>, SerdeBincode<PromptMetadata>>,
|
||||
metadata_cache: Mutex<MetadataCache>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct MetadataCache {
|
||||
metadata: Vec<PromptMetadata>,
|
||||
metadata_by_id: HashMap<PromptId, PromptMetadata>,
|
||||
}
|
||||
|
||||
impl MetadataCache {
|
||||
fn from_db(
|
||||
db: Database<SerdeBincode<PromptId>, SerdeBincode<PromptMetadata>>,
|
||||
txn: &RoTxn,
|
||||
) -> Result<Self> {
|
||||
let mut cache = MetadataCache::default();
|
||||
for result in db.iter(txn)? {
|
||||
let (prompt_id, metadata) = result?;
|
||||
cache.metadata.push(metadata.clone());
|
||||
cache.metadata_by_id.insert(prompt_id, metadata);
|
||||
}
|
||||
cache
|
||||
.metadata
|
||||
.sort_unstable_by_key(|metadata| Reverse(metadata.saved_at));
|
||||
Ok(cache)
|
||||
}
|
||||
|
||||
fn insert(&mut self, metadata: PromptMetadata) {
|
||||
self.metadata_by_id.insert(metadata.id, metadata.clone());
|
||||
if let Some(old_metadata) = self.metadata.iter_mut().find(|m| m.id == metadata.id) {
|
||||
*old_metadata = metadata;
|
||||
} else {
|
||||
self.metadata.push(metadata);
|
||||
}
|
||||
self.metadata.sort_by_key(|m| Reverse(m.saved_at));
|
||||
}
|
||||
|
||||
fn remove(&mut self, id: PromptId) {
|
||||
self.metadata.retain(|metadata| metadata.id != id);
|
||||
self.metadata_by_id.remove(&id);
|
||||
}
|
||||
}
|
||||
|
||||
impl PromptStore {
|
||||
pub fn global(cx: &AppContext) -> impl Future<Output = Result<Arc<Self>>> {
|
||||
let store = GlobalPromptStore::global(cx).0.clone();
|
||||
async move { store.await.map_err(|err| anyhow!(err)) }
|
||||
}
|
||||
|
||||
pub fn new(db_path: PathBuf, executor: BackgroundExecutor) -> Task<Result<Self>> {
|
||||
executor.spawn({
|
||||
let executor = executor.clone();
|
||||
async move {
|
||||
std::fs::create_dir_all(&db_path)?;
|
||||
|
||||
let db_env = unsafe {
|
||||
heed::EnvOpenOptions::new()
|
||||
.map_size(1024 * 1024 * 1024) // 1GB
|
||||
.max_dbs(2) // bodies and metadata
|
||||
.open(db_path)?
|
||||
};
|
||||
|
||||
let mut txn = db_env.write_txn()?;
|
||||
let bodies = db_env.create_database(&mut txn, Some("bodies"))?;
|
||||
let metadata = db_env.create_database(&mut txn, Some("metadata"))?;
|
||||
let metadata_cache = MetadataCache::from_db(metadata, &txn)?;
|
||||
txn.commit()?;
|
||||
|
||||
Ok(PromptStore {
|
||||
executor,
|
||||
env: db_env,
|
||||
bodies,
|
||||
metadata,
|
||||
metadata_cache: Mutex::new(metadata_cache),
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn load(&self, id: PromptId) -> Task<Result<String>> {
|
||||
let env = self.env.clone();
|
||||
let bodies = self.bodies;
|
||||
self.executor.spawn(async move {
|
||||
let txn = env.read_txn()?;
|
||||
Ok(bodies
|
||||
.get(&txn, &id)?
|
||||
.ok_or_else(|| anyhow!("prompt not found"))?)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn delete(&self, id: PromptId) -> Task<Result<()>> {
|
||||
self.metadata_cache.lock().remove(id);
|
||||
|
||||
let db_connection = self.env.clone();
|
||||
let bodies = self.bodies;
|
||||
let metadata = self.metadata;
|
||||
|
||||
self.executor.spawn(async move {
|
||||
let mut txn = db_connection.write_txn()?;
|
||||
|
||||
metadata.delete(&mut txn, &id)?;
|
||||
bodies.delete(&mut txn, &id)?;
|
||||
|
||||
txn.commit()?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn metadata(&self, id: PromptId) -> Option<PromptMetadata> {
|
||||
self.metadata_cache.lock().metadata_by_id.get(&id).cloned()
|
||||
}
|
||||
|
||||
pub fn id_for_title(&self, title: &str) -> Option<PromptId> {
|
||||
let metadata_cache = self.metadata_cache.lock();
|
||||
let metadata = metadata_cache
|
||||
.metadata
|
||||
.iter()
|
||||
.find(|metadata| metadata.title.as_ref().map(|title| &***title) == Some(title))?;
|
||||
Some(metadata.id)
|
||||
}
|
||||
|
||||
pub fn search(&self, query: String) -> Task<Vec<PromptMetadata>> {
|
||||
let cached_metadata = self.metadata_cache.lock().metadata.clone();
|
||||
let executor = self.executor.clone();
|
||||
self.executor.spawn(async move {
|
||||
if query.is_empty() {
|
||||
cached_metadata
|
||||
} else {
|
||||
let candidates = cached_metadata
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(ix, metadata)| {
|
||||
Some(StringMatchCandidate::new(
|
||||
ix,
|
||||
metadata.title.as_ref()?.to_string(),
|
||||
))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let matches = fuzzy::match_strings(
|
||||
&candidates,
|
||||
&query,
|
||||
false,
|
||||
100,
|
||||
&AtomicBool::default(),
|
||||
executor,
|
||||
)
|
||||
.await;
|
||||
matches
|
||||
.into_iter()
|
||||
.map(|mat| cached_metadata[mat.candidate_id].clone())
|
||||
.collect()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn save(
|
||||
&self,
|
||||
id: PromptId,
|
||||
title: Option<SharedString>,
|
||||
default: bool,
|
||||
body: String,
|
||||
) -> Task<Result<()>> {
|
||||
let prompt_metadata = PromptMetadata {
|
||||
id,
|
||||
title,
|
||||
default,
|
||||
saved_at: Utc::now(),
|
||||
};
|
||||
self.metadata_cache.lock().insert(prompt_metadata.clone());
|
||||
|
||||
let db_connection = self.env.clone();
|
||||
let bodies = self.bodies;
|
||||
let metadata = self.metadata;
|
||||
|
||||
self.executor.spawn(async move {
|
||||
let mut txn = db_connection.write_txn()?;
|
||||
|
||||
metadata.put(&mut txn, &id, &prompt_metadata)?;
|
||||
bodies.put(&mut txn, &id, &body)?;
|
||||
|
||||
txn.commit()?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn save_metadata(
|
||||
&self,
|
||||
id: PromptId,
|
||||
title: Option<SharedString>,
|
||||
default: bool,
|
||||
) -> Task<Result<()>> {
|
||||
let prompt_metadata = PromptMetadata {
|
||||
id,
|
||||
title,
|
||||
default,
|
||||
saved_at: Utc::now(),
|
||||
};
|
||||
self.metadata_cache.lock().insert(prompt_metadata.clone());
|
||||
|
||||
let db_connection = self.env.clone();
|
||||
let metadata = self.metadata;
|
||||
|
||||
self.executor.spawn(async move {
|
||||
let mut txn = db_connection.write_txn()?;
|
||||
metadata.put(&mut txn, &id, &prompt_metadata)?;
|
||||
txn.commit()?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn most_recently_saved(&self) -> Option<PromptId> {
|
||||
self.metadata_cache
|
||||
.lock()
|
||||
.metadata
|
||||
.first()
|
||||
.map(|metadata| metadata.id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps a shared future to a prompt store so it can be assigned as a context global.
|
||||
pub struct GlobalPromptStore(
|
||||
Shared<BoxFuture<'static, Result<Arc<PromptStore>, Arc<anyhow::Error>>>>,
|
||||
);
|
||||
|
||||
impl Global for GlobalPromptStore {}
|
||||
|
||||
fn title_from_body<'a>(body: impl IntoIterator<Item = char>) -> Option<SharedString> {
|
||||
let mut chars = body.into_iter().take_while(|c| *c != '\n').peekable();
|
||||
|
||||
let mut level = 0;
|
||||
while let Some('#') = chars.peek() {
|
||||
level += 1;
|
||||
chars.next();
|
||||
}
|
||||
|
||||
if level > 0 {
|
||||
Some(chars.collect::<String>().trim().to_string().into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ fn line_similarity(line1: &str, line2: &str) -> f64 {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use gpui::{AppContext, Context as _};
|
||||
use gpui::{AppContext, StaticContext as _};
|
||||
use language::Buffer;
|
||||
use unindent::Unindent as _;
|
||||
use util::test::marked_text_ranges;
|
||||
|
||||
@@ -6,8 +6,8 @@ use db::kvp::KEY_VALUE_STORE;
|
||||
use db::RELEASE_CHANNEL;
|
||||
use editor::{Editor, MultiBuffer};
|
||||
use gpui::{
|
||||
actions, AppContext, AsyncAppContext, Context as _, Global, Model, ModelContext,
|
||||
SemanticVersion, SharedString, Task, View, ViewContext, VisualContext, WindowContext,
|
||||
actions, AppContext, AsyncAppContext, Global, Model, ModelContext, SemanticVersion,
|
||||
SharedString, StaticContext as _, Task, View, ViewContext, VisualContext, WindowContext,
|
||||
};
|
||||
use isahc::AsyncBody;
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ use client::{proto, ChannelId, Client, TypedEnvelope, User, UserStore, ZED_ALWAY
|
||||
use collections::HashSet;
|
||||
use futures::{channel::oneshot, future::Shared, Future, FutureExt};
|
||||
use gpui::{
|
||||
AppContext, AsyncAppContext, Context, EventEmitter, Global, Model, ModelContext, Subscription,
|
||||
Task, WeakModel,
|
||||
AppContext, AsyncAppContext, EventEmitter, Global, Model, ModelContext, StaticContext,
|
||||
Subscription, Task, WeakModel,
|
||||
};
|
||||
use postage::watch;
|
||||
use project::Project;
|
||||
|
||||
@@ -12,7 +12,7 @@ use collections::{BTreeMap, HashMap, HashSet};
|
||||
use fs::Fs;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use gpui::{
|
||||
AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Task, WeakModel,
|
||||
AppContext, AsyncAppContext, StaticContext, EventEmitter, Model, ModelContext, Task, WeakModel,
|
||||
};
|
||||
use language::LanguageRegistry;
|
||||
use live_kit_client::{LocalAudioTrack, LocalTrackPublication, LocalVideoTrack, RoomUpdate};
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::{Channel, ChannelStore};
|
||||
use anyhow::Result;
|
||||
use client::{ChannelId, Client, Collaborator, UserStore, ZED_ALWAYS_ACTIVE};
|
||||
use collections::HashMap;
|
||||
use gpui::{AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Task};
|
||||
use gpui::{AppContext, AsyncAppContext, EventEmitter, Model, ModelContext, StaticContext, Task};
|
||||
use language::proto::serialize_version;
|
||||
use rpc::{
|
||||
proto::{self, PeerId},
|
||||
|
||||
@@ -8,7 +8,7 @@ use client::{
|
||||
use collections::HashSet;
|
||||
use futures::lock::Mutex;
|
||||
use gpui::{
|
||||
AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Task, WeakModel,
|
||||
AppContext, AsyncAppContext, EventEmitter, Model, ModelContext, StaticContext, Task, WeakModel,
|
||||
};
|
||||
use rand::prelude::*;
|
||||
use std::{
|
||||
|
||||
@@ -7,8 +7,8 @@ use client::{ChannelId, Client, ClientSettings, ProjectId, Subscription, User, U
|
||||
use collections::{hash_map, HashMap, HashSet};
|
||||
use futures::{channel::mpsc, future::Shared, Future, FutureExt, StreamExt};
|
||||
use gpui::{
|
||||
AppContext, AsyncAppContext, Context, EventEmitter, Global, Model, ModelContext, SharedString,
|
||||
Task, WeakModel,
|
||||
AppContext, AsyncAppContext, EventEmitter, Global, Model, ModelContext, SharedString,
|
||||
StaticContext, Task, WeakModel,
|
||||
};
|
||||
use language::Capability;
|
||||
use rpc::{
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::channel_chat::ChannelChatEvent;
|
||||
use super::*;
|
||||
use client::{test::FakeServer, Client, UserStore};
|
||||
use clock::FakeSystemClock;
|
||||
use gpui::{AppContext, Context, Model, TestAppContext};
|
||||
use gpui::{AppContext, Model, StaticContext, TestAppContext};
|
||||
use http::FakeHttpClient;
|
||||
use rpc::proto::{self};
|
||||
use settings::SettingsStore;
|
||||
|
||||
@@ -1701,7 +1701,7 @@ mod tests {
|
||||
use crate::test::FakeServer;
|
||||
|
||||
use clock::FakeSystemClock;
|
||||
use gpui::{BackgroundExecutor, Context, TestAppContext};
|
||||
use gpui::{BackgroundExecutor, StaticContext, TestAppContext};
|
||||
use http::FakeHttpClient;
|
||||
use parking_lot::Mutex;
|
||||
use settings::SettingsStore;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{Client, Connection, Credentials, EstablishConnectionError, UserStore};
|
||||
use anyhow::{anyhow, Result};
|
||||
use futures::{stream::BoxStream, StreamExt};
|
||||
use gpui::{BackgroundExecutor, Context, Model, TestAppContext};
|
||||
use gpui::{BackgroundExecutor, StaticContext, Model, TestAppContext};
|
||||
use parking_lot::Mutex;
|
||||
use rpc::{
|
||||
proto::{self, GetPrivateUserInfo, GetPrivateUserInfoResponse},
|
||||
|
||||
@@ -7,7 +7,7 @@ use collab_ui::{
|
||||
};
|
||||
use editor::{Editor, ExcerptRange, MultiBuffer};
|
||||
use gpui::{
|
||||
point, BackgroundExecutor, BorrowAppContext, Context, Entity, SharedString, TestAppContext,
|
||||
point, BackgroundExecutor, BorrowAppContext, StaticContext, Entity, SharedString, TestAppContext,
|
||||
View, VisualContext, VisualTestContext,
|
||||
};
|
||||
use language::Capability;
|
||||
|
||||
@@ -18,7 +18,7 @@ use collections::{HashMap, HashSet};
|
||||
use fs::FakeFs;
|
||||
use futures::{channel::oneshot, StreamExt as _};
|
||||
use git::GitHostingProviderRegistry;
|
||||
use gpui::{BackgroundExecutor, Context, Model, Task, TestAppContext, View, VisualTestContext};
|
||||
use gpui::{BackgroundExecutor, StaticContext, Model, Task, TestAppContext, View, VisualTestContext};
|
||||
use http::FakeHttpClient;
|
||||
use language::LanguageRegistry;
|
||||
use node_runtime::FakeNodeRuntime;
|
||||
|
||||
@@ -9,7 +9,7 @@ use collections::{HashMap, HashSet};
|
||||
use command_palette_hooks::CommandPaletteFilter;
|
||||
use futures::{channel::oneshot, future::Shared, Future, FutureExt, TryFutureExt};
|
||||
use gpui::{
|
||||
actions, AppContext, AsyncAppContext, Context, Entity, EntityId, EventEmitter, Global, Model,
|
||||
actions, AppContext, AsyncAppContext, StaticContext, Entity, EntityId, EventEmitter, Global, Model,
|
||||
ModelContext, Task, WeakModel,
|
||||
};
|
||||
use http::github::latest_github_release;
|
||||
|
||||
@@ -292,7 +292,7 @@ mod tests {
|
||||
};
|
||||
use fs::FakeFs;
|
||||
use futures::StreamExt;
|
||||
use gpui::{BackgroundExecutor, Context, TestAppContext, UpdateGlobal};
|
||||
use gpui::{BackgroundExecutor, StaticContext, TestAppContext, UpdateGlobal};
|
||||
use indoc::indoc;
|
||||
use language::{
|
||||
language_settings::{AllLanguageSettings, AllLanguageSettingsContent},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use anyhow::Result;
|
||||
use gpui::{AppContext, AsyncAppContext, Context, Global, Model, ModelContext, SharedString, Task};
|
||||
use gpui::{AppContext, AsyncAppContext, StaticContext, Global, Model, ModelContext, SharedString, Task};
|
||||
use rpc::{
|
||||
proto::{self, DevServerStatus},
|
||||
TypedEnvelope,
|
||||
|
||||
@@ -19,9 +19,9 @@ use futures::{
|
||||
StreamExt as _,
|
||||
};
|
||||
use gpui::{
|
||||
actions, div, svg, AnyElement, AnyView, AppContext, Context, EventEmitter, FocusHandle,
|
||||
FocusableView, HighlightStyle, InteractiveElement, IntoElement, Model, ParentElement, Render,
|
||||
SharedString, Styled, StyledText, Subscription, Task, View, ViewContext, VisualContext,
|
||||
actions, div, svg, AnyElement, AnyView, AppContext, EventEmitter, FocusHandle, FocusableView,
|
||||
HighlightStyle, InteractiveElement, IntoElement, Model, ParentElement, Render, SharedString,
|
||||
StaticContext, Styled, StyledText, Subscription, Task, View, ViewContext, VisualContext,
|
||||
WeakView, WindowContext,
|
||||
};
|
||||
use language::{
|
||||
|
||||
@@ -1054,7 +1054,7 @@ pub mod tests {
|
||||
movement,
|
||||
test::{editor_test_context::EditorTestContext, marked_display_snapshot},
|
||||
};
|
||||
use gpui::{div, font, observe, px, AppContext, BorrowAppContext, Context, Element, Hsla};
|
||||
use gpui::{div, font, observe, px, AppContext, BorrowAppContext, StaticContext, Element, Hsla};
|
||||
use language::{
|
||||
language_settings::{AllLanguageSettings, AllLanguageSettingsContent},
|
||||
Buffer, Language, LanguageConfig, LanguageMatcher, SelectionGoal,
|
||||
|
||||
@@ -3,7 +3,7 @@ use super::{
|
||||
tab_map::{self, TabEdit, TabPoint, TabSnapshot},
|
||||
Highlights,
|
||||
};
|
||||
use gpui::{AppContext, Context, Font, LineWrapper, Model, ModelContext, Pixels, Task};
|
||||
use gpui::{AppContext, Font, LineWrapper, Model, ModelContext, Pixels, StaticContext, Task};
|
||||
use language::{Chunk, Point};
|
||||
use lazy_static::lazy_static;
|
||||
use multi_buffer::MultiBufferSnapshot;
|
||||
|
||||
@@ -39,6 +39,7 @@ pub mod tasks;
|
||||
|
||||
#[cfg(test)]
|
||||
mod editor_tests;
|
||||
pub mod sketch;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub mod test;
|
||||
use ::git::diff::{DiffHunk, DiffHunkStatus};
|
||||
@@ -67,11 +68,11 @@ use git::diff_hunk_to_display;
|
||||
use gpui::{
|
||||
div, impl_actions, point, prelude::*, px, relative, size, uniform_list, Action, AnyElement,
|
||||
AppContext, AsyncWindowContext, AvailableSpace, BackgroundExecutor, Bounds, ClipboardItem,
|
||||
Context, DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusableView, FontId, FontStyle,
|
||||
DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusableView, FontId, FontStyle,
|
||||
FontWeight, HighlightStyle, Hsla, InteractiveText, KeyContext, Model, MouseButton, PaintQuad,
|
||||
ParentElement, Pixels, Render, SharedString, Size, StrikethroughStyle, Styled, StyledText,
|
||||
Subscription, Task, TextStyle, UnderlineStyle, UniformListScrollHandle, View, ViewContext,
|
||||
ViewInputHandler, VisualContext, WeakView, WhiteSpace, WindowContext,
|
||||
ParentElement, Pixels, Render, SharedString, Size, StaticContext, StrikethroughStyle, Styled,
|
||||
StyledText, Subscription, Task, TextStyle, UnderlineStyle, UniformListScrollHandle, View,
|
||||
ViewContext, ViewInputHandler, VisualContext, WeakView, WhiteSpace, WindowContext,
|
||||
};
|
||||
use highlight_matching_bracket::refresh_matching_bracket_highlights;
|
||||
use hover_popover::{hide_hover, HoverState};
|
||||
|
||||
@@ -5569,7 +5569,7 @@ mod tests {
|
||||
use language::language_settings;
|
||||
use log::info;
|
||||
use std::num::NonZeroU32;
|
||||
use ui::Context;
|
||||
use ui::StaticContext;
|
||||
use util::test::sample_text;
|
||||
|
||||
#[gpui::test]
|
||||
|
||||
@@ -107,7 +107,7 @@ pub fn diff_hunk_to_display(
|
||||
mod tests {
|
||||
use crate::Point;
|
||||
use crate::{editor_tests::init_test, hunk_status};
|
||||
use gpui::{Context, TestAppContext};
|
||||
use gpui::{StaticContext, TestAppContext};
|
||||
use language::Capability::ReadWrite;
|
||||
use multi_buffer::{ExcerptRange, MultiBuffer, MultiBufferRow};
|
||||
use project::{FakeFs, Project};
|
||||
|
||||
@@ -519,7 +519,7 @@ async fn parse_markdown(text: &str, language_registry: &Arc<LanguageRegistry>) -
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use gpui::Context;
|
||||
use gpui::StaticContext;
|
||||
use language::{Point, Rope};
|
||||
use project::FakeFs;
|
||||
use rand::prelude::*;
|
||||
|
||||
@@ -13,7 +13,8 @@ use multi_buffer::{
|
||||
use settings::{Settings, SettingsStore};
|
||||
use text::{BufferId, Point};
|
||||
use ui::{
|
||||
div, ActiveTheme, Context as _, IntoElement, ParentElement, Styled, ViewContext, VisualContext,
|
||||
div, ActiveTheme, IntoElement, ParentElement, StaticContext as _, Styled, ViewContext,
|
||||
VisualContext,
|
||||
};
|
||||
use util::{debug_panic, RangeExt};
|
||||
|
||||
|
||||
@@ -1268,7 +1268,7 @@ pub mod tests {
|
||||
ExcerptRange,
|
||||
};
|
||||
use futures::StreamExt;
|
||||
use gpui::{Context, TestAppContext, WindowHandle};
|
||||
use gpui::{StaticContext, TestAppContext, WindowHandle};
|
||||
use itertools::Itertools;
|
||||
use language::{
|
||||
language_settings::AllLanguageSettingsContent, Capability, FakeLspAdapter, Language,
|
||||
|
||||
@@ -8,7 +8,7 @@ use collections::HashSet;
|
||||
use futures::future::try_join_all;
|
||||
use git::repository::GitFileStatus;
|
||||
use gpui::{
|
||||
point, AnyElement, AppContext, AsyncWindowContext, Context, Entity, EntityId, EventEmitter,
|
||||
point, AnyElement, AppContext, AsyncWindowContext, StaticContext, Entity, EntityId, EventEmitter,
|
||||
IntoElement, Model, ParentElement, Pixels, SharedString, Styled, Task, View, ViewContext,
|
||||
VisualContext, WeakView, WindowContext,
|
||||
};
|
||||
|
||||
@@ -579,7 +579,7 @@ mod tests {
|
||||
test::{editor_test_context::EditorTestContext, marked_display_snapshot},
|
||||
Buffer, DisplayMap, DisplayRow, ExcerptRange, FoldPlaceholder, InlayId, MultiBuffer,
|
||||
};
|
||||
use gpui::{font, Context as _};
|
||||
use gpui::{font, StaticContext as _};
|
||||
use language::Capability;
|
||||
use project::Project;
|
||||
use settings::SettingsStore;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Context as _;
|
||||
use gpui::{Context, View, ViewContext, VisualContext, WindowContext};
|
||||
use gpui::{StaticContext, View, ViewContext, VisualContext, WindowContext};
|
||||
use language::Language;
|
||||
use multi_buffer::MultiBuffer;
|
||||
use project::lsp_ext_command::ExpandMacro;
|
||||
|
||||
27
crates/editor/src/sketch.rs
Normal file
27
crates/editor/src/sketch.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use crate::{Editor, EditorElement, EditorStyle};
|
||||
use gpui::{sketch::View, Model};
|
||||
use ui::ViewContext;
|
||||
|
||||
pub struct PaneItemProps {}
|
||||
struct TabProps {}
|
||||
|
||||
pub trait RenderEditor {
|
||||
fn tab_view(&self, props: EditorStyle) -> View<Editor, TabProps>;
|
||||
fn render(&self, props: EditorStyle) -> EditorElement;
|
||||
}
|
||||
|
||||
impl RenderEditor for Model<Editor> {
|
||||
fn tab_view(&self, style: EditorStyle) -> View<Editor, TabProps> {
|
||||
View::new(
|
||||
self.clone(),
|
||||
move |_, _: TabProps, cx: &mut ViewContext<Editor>| {
|
||||
cx.view().model.render(style.clone())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn render(&self, style: EditorStyle) -> EditorElement {
|
||||
todo!()
|
||||
// EditorElement::new(self, style)
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ use crate::{
|
||||
display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
|
||||
DisplayPoint, Editor, EditorMode, FoldPlaceholder, MultiBuffer,
|
||||
};
|
||||
use gpui::{Context, Font, FontFeatures, FontStyle, FontWeight, Model, Pixels, ViewContext};
|
||||
use gpui::{Font, FontFeatures, FontStyle, FontWeight, Model, Pixels, StaticContext, ViewContext};
|
||||
use project::Project;
|
||||
use util::test::{marked_text_offsets, marked_text_ranges};
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ use std::{
|
||||
},
|
||||
};
|
||||
|
||||
use ui::Context;
|
||||
use ui::StaticContext;
|
||||
use util::{
|
||||
assert_set_eq,
|
||||
test::{generate_marked_text, marked_text_ranges},
|
||||
|
||||
@@ -28,7 +28,7 @@ use futures::{
|
||||
select_biased, AsyncReadExt as _, Future, FutureExt as _, StreamExt as _,
|
||||
};
|
||||
use gpui::{
|
||||
actions, AppContext, AsyncAppContext, Context, EventEmitter, Global, Model, ModelContext, Task,
|
||||
actions, AppContext, AsyncAppContext, StaticContext, EventEmitter, Global, Model, ModelContext, Task,
|
||||
WeakModel,
|
||||
};
|
||||
use http::{AsyncBody, HttpClient, HttpClientWithUrl};
|
||||
|
||||
@@ -10,7 +10,7 @@ use async_compression::futures::bufread::GzipEncoder;
|
||||
use collections::BTreeMap;
|
||||
use fs::{FakeFs, Fs, RealFs};
|
||||
use futures::{io::BufReader, AsyncReadExt, StreamExt};
|
||||
use gpui::{Context, TestAppContext};
|
||||
use gpui::{StaticContext, TestAppContext};
|
||||
use http::{FakeHttpClient, Response};
|
||||
use language::{LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus, LanguageServerName};
|
||||
use node_runtime::FakeNodeRuntime;
|
||||
|
||||
@@ -27,7 +27,7 @@ use util::ResultExt;
|
||||
|
||||
use crate::{
|
||||
current_platform, init_app_menus, Action, ActionRegistry, Any, AnyView, AnyWindowHandle,
|
||||
AppMetadata, AssetCache, AssetSource, BackgroundExecutor, ClipboardItem, Context,
|
||||
AppMetadata, AssetCache, AssetSource, BackgroundExecutor, ClipboardItem, StaticContext,
|
||||
DispatchPhase, DisplayId, Entity, EventEmitter, ForegroundExecutor, Global, KeyBinding, Keymap,
|
||||
Keystroke, LayoutId, Menu, MenuItem, PathPromptOptions, Pixels, Platform, PlatformDisplay,
|
||||
Point, PromptBuilder, PromptHandle, PromptLevel, Render, RenderablePromptHandle, Reservation,
|
||||
@@ -1263,7 +1263,7 @@ impl AppContext {
|
||||
}
|
||||
}
|
||||
|
||||
impl Context for AppContext {
|
||||
impl StaticContext for AppContext {
|
||||
type Result<T> = T;
|
||||
|
||||
/// Build an entity that is owned by the application. The given function will be invoked with
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
AnyView, AnyWindowHandle, AppCell, AppContext, BackgroundExecutor, BorrowAppContext, Context,
|
||||
AnyView, AnyWindowHandle, AppCell, AppContext, BackgroundExecutor, BorrowAppContext,
|
||||
DismissEvent, FocusableView, ForegroundExecutor, Global, Model, ModelContext, PromptLevel,
|
||||
Render, Reservation, Result, Task, View, ViewContext, VisualContext, WindowContext,
|
||||
WindowHandle,
|
||||
Render, Reservation, Result, StaticContext, Task, View, ViewContext, VisualContext,
|
||||
WindowContext, WindowHandle,
|
||||
};
|
||||
use anyhow::{anyhow, Context as _};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
@@ -19,7 +19,7 @@ pub struct AsyncAppContext {
|
||||
pub(crate) foreground_executor: ForegroundExecutor,
|
||||
}
|
||||
|
||||
impl Context for AsyncAppContext {
|
||||
impl StaticContext for AsyncAppContext {
|
||||
type Result<T> = Result<T>;
|
||||
|
||||
fn new_model<T: 'static>(
|
||||
@@ -301,7 +301,7 @@ impl AsyncWindowContext {
|
||||
}
|
||||
}
|
||||
|
||||
impl Context for AsyncWindowContext {
|
||||
impl StaticContext for AsyncWindowContext {
|
||||
type Result<T> = Result<T>;
|
||||
|
||||
fn new_model<T>(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{seal::Sealed, AppContext, Context, Entity, ModelContext};
|
||||
use crate::{seal::Sealed, AppContext, StaticContext, Entity, ModelContext};
|
||||
use anyhow::{anyhow, Result};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
||||
@@ -398,7 +398,7 @@ impl<T: 'static> Model<T> {
|
||||
}
|
||||
|
||||
/// Read the entity referenced by this model with the given function.
|
||||
pub fn read_with<R, C: Context>(
|
||||
pub fn read_with<R, C: StaticContext>(
|
||||
&self,
|
||||
cx: &C,
|
||||
f: impl FnOnce(&T, &AppContext) -> R,
|
||||
@@ -417,7 +417,7 @@ impl<T: 'static> Model<T> {
|
||||
update: impl FnOnce(&mut T, &mut ModelContext<'_, T>) -> R,
|
||||
) -> C::Result<R>
|
||||
where
|
||||
C: Context,
|
||||
C: StaticContext,
|
||||
{
|
||||
cx.update_model(self, update)
|
||||
}
|
||||
@@ -595,7 +595,7 @@ impl<T: 'static> WeakModel<T> {
|
||||
update: impl FnOnce(&mut T, &mut ModelContext<'_, T>) -> R,
|
||||
) -> Result<R>
|
||||
where
|
||||
C: Context,
|
||||
C: StaticContext,
|
||||
Result<C::Result<R>>: crate::Flatten<R>,
|
||||
{
|
||||
crate::Flatten::flatten(
|
||||
@@ -610,7 +610,7 @@ impl<T: 'static> WeakModel<T> {
|
||||
/// been released.
|
||||
pub fn read_with<C, R>(&self, cx: &C, read: impl FnOnce(&T, &AppContext) -> R) -> Result<R>
|
||||
where
|
||||
C: Context,
|
||||
C: StaticContext,
|
||||
Result<C::Result<R>>: crate::Flatten<R>,
|
||||
{
|
||||
crate::Flatten::flatten(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
AnyView, AnyWindowHandle, AppContext, AsyncAppContext, Context, Effect, Entity, EntityId,
|
||||
EventEmitter, Model, Reservation, Subscription, Task, View, WeakModel, WindowContext,
|
||||
AnyView, AnyWindowHandle, AppContext, AsyncAppContext, Effect, Entity, EntityId, EventEmitter,
|
||||
Model, Reservation, StaticContext, Subscription, Task, View, WeakModel, WindowContext,
|
||||
WindowHandle,
|
||||
};
|
||||
use anyhow::Result;
|
||||
@@ -220,7 +220,7 @@ impl<'a, T> ModelContext<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Context for ModelContext<'a, T> {
|
||||
impl<'a, T> StaticContext for ModelContext<'a, T> {
|
||||
type Result<U> = U;
|
||||
|
||||
fn new_model<U: 'static>(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
Action, AnyView, AnyWindowHandle, AppCell, AppContext, AsyncAppContext, AvailableSpace,
|
||||
BackgroundExecutor, BorrowAppContext, Bounds, ClipboardItem, Context, DrawPhase, Drawable,
|
||||
BackgroundExecutor, BorrowAppContext, Bounds, ClipboardItem, StaticContext, DrawPhase, Drawable,
|
||||
Element, Empty, Entity, EventEmitter, ForegroundExecutor, Global, InputEvent, Keystroke, Model,
|
||||
ModelContext, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent,
|
||||
MouseUpEvent, Pixels, Platform, Point, Render, Result, Size, Task, TestDispatcher,
|
||||
@@ -29,7 +29,7 @@ pub struct TestAppContext {
|
||||
on_quit: Rc<RefCell<Vec<Box<dyn FnOnce() + 'static>>>>,
|
||||
}
|
||||
|
||||
impl Context for TestAppContext {
|
||||
impl StaticContext for TestAppContext {
|
||||
type Result<T> = T;
|
||||
|
||||
fn new_model<T: 'static>(
|
||||
@@ -844,8 +844,8 @@ impl VisualTestContext {
|
||||
}
|
||||
}
|
||||
|
||||
impl Context for VisualTestContext {
|
||||
type Result<T> = <TestAppContext as Context>::Result<T>;
|
||||
impl StaticContext for VisualTestContext {
|
||||
type Result<T> = <TestAppContext as StaticContext>::Result<T>;
|
||||
|
||||
fn new_model<T: 'static>(
|
||||
&mut self,
|
||||
|
||||
@@ -87,6 +87,8 @@ pub mod prelude;
|
||||
mod scene;
|
||||
mod shared_string;
|
||||
mod shared_uri;
|
||||
/// todo!
|
||||
pub mod sketch;
|
||||
mod style;
|
||||
mod styled;
|
||||
mod subscription;
|
||||
@@ -156,7 +158,7 @@ use taffy::TaffyLayoutEngine;
|
||||
|
||||
/// The context trait, allows the different contexts in GPUI to be used
|
||||
/// interchangeably for certain operations.
|
||||
pub trait Context {
|
||||
pub trait StaticContext {
|
||||
/// The result type for this context, used for async contexts that
|
||||
/// can't hold a direct reference to the application context.
|
||||
type Result<T>;
|
||||
@@ -226,7 +228,7 @@ impl<T: 'static> Reservation<T> {
|
||||
|
||||
/// This trait is used for the different visual contexts in GPUI that
|
||||
/// require a window to be present.
|
||||
pub trait VisualContext: Context {
|
||||
pub trait VisualContext: StaticContext {
|
||||
/// Construct a new view in the window referenced by this context.
|
||||
fn new_view<V>(
|
||||
&mut self,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//! application to avoid having to import each trait individually.
|
||||
|
||||
pub use crate::{
|
||||
util::FluentBuilder, BorrowAppContext, BorrowWindow, Context, Element, FocusableElement,
|
||||
util::FluentBuilder, BorrowAppContext, BorrowWindow, Element, FocusableElement,
|
||||
InteractiveElement, IntoElement, ParentElement, Refineable, Render, RenderOnce,
|
||||
StatefulInteractiveElement, Styled, VisualContext,
|
||||
StatefulInteractiveElement, StaticContext, Styled, VisualContext,
|
||||
};
|
||||
|
||||
107
crates/gpui/src/sketch.rs
Normal file
107
crates/gpui/src/sketch.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
use crate::{AnyElement, AnyModel, IntoElement, ViewContext, WindowContext};
|
||||
use std::{any::Any, marker::PhantomData, sync::Arc};
|
||||
|
||||
pub struct Model<M> {
|
||||
state_type: PhantomData<M>,
|
||||
}
|
||||
|
||||
pub trait Context {
|
||||
type ModelContext<'a, M>;
|
||||
|
||||
fn update<M, F, R>(&mut self, model: &Model<M>, update: F) -> R
|
||||
where
|
||||
M: 'static,
|
||||
F: for<'a> FnOnce(&mut M, &mut Self::ModelContext<'a, M>) -> R;
|
||||
}
|
||||
|
||||
impl Context for WindowContext<'_> {
|
||||
type ModelContext<'a, M> = ViewContext<'a, M>;
|
||||
|
||||
fn update<M, F, R>(&mut self, model: &Model<M>, update: F) -> R
|
||||
where
|
||||
M: 'static,
|
||||
F: for<'a> FnOnce(&mut M, &mut Self::ModelContext<'a, M>) -> R,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> Model<M> {
|
||||
pub fn update<C, F, R>(&self, cx: &mut C, update: F) -> R
|
||||
where
|
||||
C: Context,
|
||||
F: for<'a> FnOnce(&mut M, &mut C::ModelContext<'a, M>) -> R,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// A view is the combination of a model with a compatible render function for that model.
|
||||
pub struct View<M, P> {
|
||||
/// A handle to the state we will render
|
||||
pub model: Model<M>,
|
||||
/// A recipe for displaying the state based on properties
|
||||
pub component: Arc<dyn StatefulComponent<M, P>>,
|
||||
}
|
||||
|
||||
impl<M: 'static, P: 'static> View<M, P> {
|
||||
/// Creates a new `View` with the specified model and render function.
|
||||
pub fn new<F, E>(model: Model<M>, render: F) -> Self
|
||||
where
|
||||
F: 'static + Fn(&mut M, P, &mut ViewContext<M>) -> E,
|
||||
E: IntoElement,
|
||||
{
|
||||
View {
|
||||
model,
|
||||
component: Arc::new(
|
||||
move |model: &mut M, props: P, cx: &mut ViewContext<'_, M>| {
|
||||
render(model, props, cx).into_any_element()
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&self, props: P, cx: &mut WindowContext) -> AnyElement {
|
||||
self.model
|
||||
.update(cx, |model, cx| self.component.render(model, props, cx))
|
||||
}
|
||||
}
|
||||
|
||||
/// A mapping from properties P to an element tree.
|
||||
pub trait Component<P>: 'static {
|
||||
/// Render the properties
|
||||
fn render(&self, props: P, cx: &mut WindowContext) -> AnyElement;
|
||||
}
|
||||
|
||||
/// A mapping from a stateful model M and properties P to an element tree.
|
||||
pub trait StatefulComponent<M, P>: 'static {
|
||||
/// Render the model with the given properties
|
||||
fn render(&self, model: &mut M, props: P, cx: &mut ViewContext<M>) -> AnyElement;
|
||||
}
|
||||
|
||||
impl<P, F> Component<P> for F
|
||||
where
|
||||
F: Fn(P, &mut WindowContext) -> AnyElement + 'static,
|
||||
{
|
||||
fn render(&self, props: P, cx: &mut WindowContext) -> AnyElement {
|
||||
(self)(props, cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, P, F> StatefulComponent<M, P> for F
|
||||
where
|
||||
F: for<'a, 'b, 'c> Fn(&'a mut M, P, &'b mut ViewContext<'c, M>) -> AnyElement + 'static,
|
||||
{
|
||||
fn render(&self, model: &mut M, props: P, cx: &mut ViewContext<M>) -> AnyElement {
|
||||
(self)(model, props, cx)
|
||||
}
|
||||
}
|
||||
|
||||
/// A dynamically typed view. It can be rendered with props P or downcast back to a typed view.
|
||||
pub struct AnyView<P> {
|
||||
model: AnyModel,
|
||||
/// An upcasted render function that takes the dynamic reference.
|
||||
render: Arc<dyn Fn(&AnyModel, P, &mut WindowContext) -> AnyElement>,
|
||||
/// The original render function to enable downcasting to a View.
|
||||
typed_render: Arc<dyn Any>,
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
hash, point, prelude::*, px, size, transparent_black, Action, AnyDrag, AnyElement, AnyTooltip,
|
||||
AnyView, AppContext, Arena, Asset, AsyncWindowContext, AvailableSpace, Bounds, BoxShadow,
|
||||
Context, Corners, CursorStyle, DevicePixels, DispatchActionListener, DispatchNodeId,
|
||||
StaticContext, Corners, CursorStyle, DevicePixels, DispatchActionListener, DispatchNodeId,
|
||||
DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, Flatten,
|
||||
FontId, Global, GlobalElementId, GlyphId, Hsla, ImageData, InputHandler, IsZero, KeyBinding,
|
||||
KeyContext, KeyDownEvent, KeyEvent, KeyMatch, KeymatchResult, Keystroke, KeystrokeEvent,
|
||||
@@ -3536,7 +3536,7 @@ impl WindowContext<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Context for WindowContext<'_> {
|
||||
impl StaticContext for WindowContext<'_> {
|
||||
type Result<T> = T;
|
||||
|
||||
fn new_model<T>(&mut self, build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T) -> Model<T>
|
||||
@@ -4198,7 +4198,7 @@ impl<'a, V: 'static> ViewContext<'a, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> Context for ViewContext<'_, V> {
|
||||
impl<V> StaticContext for ViewContext<'_, V> {
|
||||
type Result<U> = U;
|
||||
|
||||
fn new_model<T: 'static>(
|
||||
@@ -4348,7 +4348,7 @@ impl<V: 'static + Render> WindowHandle<V> {
|
||||
/// This will fail if the window is closed or if the root view's type does not match `V`.
|
||||
pub fn root<C>(&self, cx: &mut C) -> Result<View<V>>
|
||||
where
|
||||
C: Context,
|
||||
C: StaticContext,
|
||||
{
|
||||
Flatten::flatten(cx.update_window(self.any_handle, |root_view, _| {
|
||||
root_view
|
||||
@@ -4366,7 +4366,7 @@ impl<V: 'static + Render> WindowHandle<V> {
|
||||
update: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
|
||||
) -> Result<R>
|
||||
where
|
||||
C: Context,
|
||||
C: StaticContext,
|
||||
{
|
||||
cx.update_window(self.any_handle, |root_view, cx| {
|
||||
let view = root_view
|
||||
@@ -4400,7 +4400,7 @@ impl<V: 'static + Render> WindowHandle<V> {
|
||||
/// This will fail if the window is closed or if the root view's type does not match `V`.
|
||||
pub fn read_with<C, R>(&self, cx: &C, read_with: impl FnOnce(&V, &AppContext) -> R) -> Result<R>
|
||||
where
|
||||
C: Context,
|
||||
C: StaticContext,
|
||||
{
|
||||
cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx))
|
||||
}
|
||||
@@ -4410,7 +4410,7 @@ impl<V: 'static + Render> WindowHandle<V> {
|
||||
/// This will fail if the window is closed or if the root view's type does not match `V`.
|
||||
pub fn root_view<C>(&self, cx: &C) -> Result<View<V>>
|
||||
where
|
||||
C: Context,
|
||||
C: StaticContext,
|
||||
{
|
||||
cx.read_window(self, |root_view, _cx| root_view.clone())
|
||||
}
|
||||
@@ -4491,7 +4491,7 @@ impl AnyWindowHandle {
|
||||
update: impl FnOnce(AnyView, &mut WindowContext<'_>) -> R,
|
||||
) -> Result<R>
|
||||
where
|
||||
C: Context,
|
||||
C: StaticContext,
|
||||
{
|
||||
cx.update_window(self, update)
|
||||
}
|
||||
@@ -4501,7 +4501,7 @@ impl AnyWindowHandle {
|
||||
/// This will fail if the window has been closed.
|
||||
pub fn read<T, C, R>(self, cx: &C, read: impl FnOnce(View<T>, &AppContext) -> R) -> Result<R>
|
||||
where
|
||||
C: Context,
|
||||
C: StaticContext,
|
||||
T: 'static,
|
||||
{
|
||||
let view = self
|
||||
|
||||
@@ -3,7 +3,9 @@ use client::DevServerProjectId;
|
||||
use client::{user::UserStore, Client, ClientSettings};
|
||||
use fs::Fs;
|
||||
use futures::Future;
|
||||
use gpui::{AppContext, AsyncAppContext, Context, Global, Model, ModelContext, Task, WeakModel};
|
||||
use gpui::{
|
||||
AppContext, AsyncAppContext, Global, Model, ModelContext, StaticContext, Task, WeakModel,
|
||||
};
|
||||
use language::LanguageRegistry;
|
||||
use node_runtime::NodeRuntime;
|
||||
use postage::stream::Stream;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use gpui::{
|
||||
canvas, div, fill, img, opaque_grey, point, size, AnyElement, AppContext, Bounds, Context,
|
||||
canvas, div, fill, img, opaque_grey, point, size, AnyElement, AppContext, Bounds, StaticContext,
|
||||
EventEmitter, FocusHandle, FocusableView, Img, InteractiveElement, IntoElement, Model,
|
||||
ObjectFit, ParentElement, Render, Styled, Task, View, ViewContext, VisualContext, WeakView,
|
||||
WindowContext,
|
||||
|
||||
@@ -7,7 +7,7 @@ use clock::ReplicaId;
|
||||
use collections::BTreeMap;
|
||||
use futures::FutureExt as _;
|
||||
use gpui::{AppContext, BorrowAppContext, Model};
|
||||
use gpui::{Context, TestAppContext};
|
||||
use gpui::{StaticContext, TestAppContext};
|
||||
use indoc::indoc;
|
||||
use proto::deserialize_operation;
|
||||
use rand::prelude::*;
|
||||
|
||||
@@ -3,7 +3,7 @@ use copilot::Copilot;
|
||||
use editor::{actions::MoveToEnd, Editor, EditorEvent};
|
||||
use futures::{channel::mpsc, StreamExt};
|
||||
use gpui::{
|
||||
actions, div, AnchorCorner, AnyElement, AppContext, Context, EventEmitter, FocusHandle,
|
||||
actions, div, AnchorCorner, AnyElement, AppContext, StaticContext, EventEmitter, FocusHandle,
|
||||
FocusableView, IntoElement, Model, ModelContext, ParentElement, Render, Styled, Subscription,
|
||||
View, ViewContext, VisualContext, WeakModel, WindowContext,
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::lsp_log::LogMenuItem;
|
||||
|
||||
use super::*;
|
||||
use futures::StreamExt;
|
||||
use gpui::{Context, TestAppContext, VisualTestContext};
|
||||
use gpui::{StaticContext, TestAppContext, VisualTestContext};
|
||||
use language::{
|
||||
tree_sitter_rust, FakeLspAdapter, Language, LanguageConfig, LanguageMatcher, LanguageServerName,
|
||||
};
|
||||
|
||||
@@ -319,7 +319,7 @@ async fn get_cached_server_binary(container_dir: PathBuf) -> Option<LanguageServ
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::{BorrowAppContext, Context, TestAppContext};
|
||||
use gpui::{BorrowAppContext, StaticContext, TestAppContext};
|
||||
use language::{language_settings::AllLanguageSettings, AutoindentMode, Buffer};
|
||||
use settings::SettingsStore;
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
@@ -135,7 +135,7 @@ async fn get_cached_server_binary(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::{Context, TestAppContext};
|
||||
use gpui::{StaticContext, TestAppContext};
|
||||
use unindent::Unindent;
|
||||
|
||||
#[gpui::test]
|
||||
|
||||
@@ -201,7 +201,7 @@ pub(super) fn python_task_context() -> ContextProviderWithTasks {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::{BorrowAppContext, Context, ModelContext, TestAppContext};
|
||||
use gpui::{BorrowAppContext, ModelContext, StaticContext, TestAppContext};
|
||||
use language::{language_settings::AllLanguageSettings, AutoindentMode, Buffer};
|
||||
use settings::SettingsStore;
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
@@ -504,7 +504,7 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::language;
|
||||
use gpui::{BorrowAppContext, Context, Hsla, TestAppContext};
|
||||
use gpui::{BorrowAppContext, Hsla, StaticContext, TestAppContext};
|
||||
use language::language_settings::AllLanguageSettings;
|
||||
use settings::SettingsStore;
|
||||
use theme::SyntaxTheme;
|
||||
|
||||
@@ -435,7 +435,7 @@ async fn get_cached_eslint_server_binary(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::{Context, TestAppContext};
|
||||
use gpui::{StaticContext, TestAppContext};
|
||||
use unindent::Unindent;
|
||||
|
||||
#[gpui::test]
|
||||
|
||||
@@ -42,7 +42,7 @@ use theme::SyntaxTheme;
|
||||
use util::post_inc;
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use gpui::Context;
|
||||
use gpui::StaticContext;
|
||||
|
||||
const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];
|
||||
|
||||
@@ -4649,7 +4649,7 @@ where
|
||||
mod tests {
|
||||
use super::*;
|
||||
use futures::StreamExt;
|
||||
use gpui::{AppContext, Context, TestAppContext};
|
||||
use gpui::{AppContext, StaticContext, TestAppContext};
|
||||
use language::{Buffer, Rope};
|
||||
use parking_lot::RwLock;
|
||||
use rand::prelude::*;
|
||||
|
||||
@@ -4,7 +4,7 @@ use client::{ChannelId, Client, UserStore};
|
||||
use collections::HashMap;
|
||||
use db::smol::stream::StreamExt;
|
||||
use gpui::{
|
||||
AppContext, AsyncAppContext, Context as _, EventEmitter, Global, Model, ModelContext, Task,
|
||||
AppContext, AsyncAppContext, StaticContext as _, EventEmitter, Global, Model, ModelContext, Task,
|
||||
};
|
||||
use rpc::{proto, Notification, TypedEnvelope};
|
||||
use std::{ops::Range, sync::Arc};
|
||||
|
||||
@@ -3,7 +3,7 @@ use anyhow::Result;
|
||||
use client::Client;
|
||||
use collections::{HashMap, HashSet};
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use gpui::{AppContext, AsyncAppContext, Context, Global, Model, ModelContext, Task, WeakModel};
|
||||
use gpui::{AppContext, AsyncAppContext, StaticContext, Global, Model, ModelContext, Task, WeakModel};
|
||||
use postage::stream::Stream;
|
||||
use rpc::proto;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
@@ -35,8 +35,9 @@ use fuzzy::CharBag;
|
||||
use git::{blame::Blame, repository::GitRepository};
|
||||
use globset::{Glob, GlobSet, GlobSetBuilder};
|
||||
use gpui::{
|
||||
AnyModel, AppContext, AsyncAppContext, BackgroundExecutor, BorrowAppContext, Context, Entity,
|
||||
EventEmitter, Model, ModelContext, PromptLevel, SharedString, Task, WeakModel, WindowContext,
|
||||
AnyModel, AppContext, AsyncAppContext, BackgroundExecutor, BorrowAppContext, Entity,
|
||||
EventEmitter, Model, ModelContext, PromptLevel, SharedString, StaticContext, Task, WeakModel,
|
||||
WindowContext,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use language::{
|
||||
|
||||
@@ -13,7 +13,7 @@ use futures::{
|
||||
channel::mpsc::{unbounded, UnboundedSender},
|
||||
StreamExt,
|
||||
};
|
||||
use gpui::{AppContext, Context, Model, ModelContext, Task};
|
||||
use gpui::{AppContext, Model, ModelContext, StaticContext, Task};
|
||||
use itertools::Itertools;
|
||||
use language::{ContextProvider, Language, Location};
|
||||
use task::{
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use crate::Project;
|
||||
use collections::HashMap;
|
||||
use gpui::{
|
||||
AnyWindowHandle, AppContext, Context, Entity, Model, ModelContext, SharedString, WeakModel,
|
||||
AnyWindowHandle, AppContext, Entity, Model, ModelContext, SharedString, StaticContext,
|
||||
WeakModel,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use settings::{Settings, SettingsLocation};
|
||||
|
||||
@@ -1091,7 +1091,7 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use editor::{display_map::DisplayRow, DisplayPoint, Editor};
|
||||
use gpui::{Context, Hsla, TestAppContext, VisualTestContext};
|
||||
use gpui::{Hsla, StaticContext, TestAppContext, VisualTestContext};
|
||||
use language::Buffer;
|
||||
use project::Project;
|
||||
use smol::stream::StreamExt as _;
|
||||
|
||||
@@ -12,9 +12,9 @@ use editor::{
|
||||
Anchor, Editor, EditorElement, EditorEvent, EditorStyle, MultiBuffer, MAX_TAB_TITLE_LEN,
|
||||
};
|
||||
use gpui::{
|
||||
actions, div, Action, AnyElement, AnyView, AppContext, Context as _, Element, EntityId,
|
||||
EventEmitter, FocusHandle, FocusableView, FontStyle, Global, Hsla, InteractiveElement,
|
||||
IntoElement, Model, ModelContext, ParentElement, Point, Render, SharedString, Styled,
|
||||
actions, div, Action, AnyElement, AnyView, AppContext, Element, EntityId, EventEmitter,
|
||||
FocusHandle, FocusableView, FontStyle, Global, Hsla, InteractiveElement, IntoElement, Model,
|
||||
ModelContext, ParentElement, Point, Render, SharedString, StaticContext as _, Styled,
|
||||
Subscription, Task, TextStyle, UpdateGlobal, View, ViewContext, VisualContext, WeakModel,
|
||||
WeakView, WhiteSpace, WindowContext,
|
||||
};
|
||||
|
||||
@@ -10,8 +10,8 @@ use fs::Fs;
|
||||
use futures::{future::Shared, stream::StreamExt, FutureExt};
|
||||
use futures_batch::ChunksTimeoutStreamExt;
|
||||
use gpui::{
|
||||
AppContext, AsyncAppContext, BorrowAppContext, Context, Entity, EntityId, EventEmitter, Global,
|
||||
Model, ModelContext, Subscription, Task, WeakModel,
|
||||
AppContext, AsyncAppContext, BorrowAppContext, Entity, EntityId, EventEmitter, Global, Model,
|
||||
ModelContext, StaticContext, Subscription, Task, WeakModel,
|
||||
};
|
||||
use heed::types::{SerdeBincode, Str};
|
||||
use language::LanguageRegistry;
|
||||
|
||||
@@ -78,7 +78,7 @@ fn released(entity_id: EntityId, cx: &mut AppContext) {
|
||||
mod test {
|
||||
use crate::{test::VimTestContext, Vim};
|
||||
use editor::Editor;
|
||||
use gpui::{Context, Entity, VisualTestContext};
|
||||
use gpui::{Entity, StaticContext, VisualTestContext};
|
||||
use language::Buffer;
|
||||
|
||||
// regression test for blur called with a different active editor
|
||||
|
||||
@@ -118,7 +118,7 @@ mod test {
|
||||
state::Mode,
|
||||
test::{NeovimBackedTestContext, VimTestContext},
|
||||
};
|
||||
use gpui::{point, px, size, Context};
|
||||
use gpui::{point, px, size, StaticContext};
|
||||
use indoc::indoc;
|
||||
use language::Point;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use gpui::{px, size, Context, UpdateGlobal};
|
||||
use gpui::{px, size, StaticContext, UpdateGlobal};
|
||||
use indoc::indoc;
|
||||
use settings::SettingsStore;
|
||||
use std::{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use editor::test::editor_lsp_test_context::EditorLspTestContext;
|
||||
use gpui::{Context, View, VisualContext};
|
||||
use gpui::{StaticContext, View, VisualContext};
|
||||
use search::{project_search::ProjectSearchBar, BufferSearchBar};
|
||||
|
||||
use crate::{state::Operator, *};
|
||||
|
||||
@@ -869,8 +869,8 @@ pub mod test {
|
||||
use super::{Item, ItemEvent, TabContentParams};
|
||||
use crate::{ItemId, ItemNavHistory, Pane, Workspace, WorkspaceId};
|
||||
use gpui::{
|
||||
AnyElement, AppContext, Context as _, EntityId, EventEmitter, FocusableView,
|
||||
InteractiveElement, IntoElement, Model, Render, SharedString, Task, View, ViewContext,
|
||||
AnyElement, AppContext, EntityId, EventEmitter, FocusableView, InteractiveElement,
|
||||
IntoElement, Model, Render, SharedString, StaticContext as _, Task, View, ViewContext,
|
||||
VisualContext, WeakView,
|
||||
};
|
||||
use project::{Project, ProjectEntryId, ProjectPath, WorktreeId};
|
||||
|
||||
@@ -80,7 +80,7 @@ use theme::{ActiveTheme, SystemAppearance, ThemeSettings};
|
||||
pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};
|
||||
pub use ui;
|
||||
use ui::{
|
||||
div, h_flex, Context as _, Div, Element, FluentBuilder, InteractiveElement as _, IntoElement,
|
||||
div, h_flex, StaticContext as _, Div, Element, FluentBuilder, InteractiveElement as _, IntoElement,
|
||||
Label, ParentElement as _, Pixels, SharedString, Styled as _, ViewContext, VisualContext as _,
|
||||
WindowContext,
|
||||
};
|
||||
@@ -453,7 +453,7 @@ impl AppState {
|
||||
pub fn test(cx: &mut AppContext) -> Arc<Self> {
|
||||
use node_runtime::FakeNodeRuntime;
|
||||
use settings::SettingsStore;
|
||||
use ui::Context as _;
|
||||
use ui::StaticContext as _;
|
||||
|
||||
if !cx.has_global::<SettingsStore>() {
|
||||
let settings_store = SettingsStore::test(cx);
|
||||
@@ -6210,7 +6210,7 @@ mod tests {
|
||||
}
|
||||
|
||||
mod register_project_item_tests {
|
||||
use ui::Context as _;
|
||||
use ui::StaticContext as _;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ use git::{
|
||||
DOT_GIT, GITIGNORE,
|
||||
};
|
||||
use gpui::{
|
||||
AppContext, AsyncAppContext, BackgroundExecutor, Context, EventEmitter, Model, ModelContext,
|
||||
Task,
|
||||
AppContext, AsyncAppContext, BackgroundExecutor, EventEmitter, Model, ModelContext,
|
||||
StaticContext, Task,
|
||||
};
|
||||
use ignore::IgnoreStack;
|
||||
use itertools::Itertools;
|
||||
|
||||
@@ -18,7 +18,7 @@ use fs::RealFs;
|
||||
use futures::{future, StreamExt};
|
||||
use git::GitHostingProviderRegistry;
|
||||
use gpui::{
|
||||
App, AppContext, AsyncAppContext, Context, Global, Task, UpdateGlobal as _, VisualContext,
|
||||
App, AppContext, AsyncAppContext, StaticContext, Global, Task, UpdateGlobal as _, VisualContext,
|
||||
};
|
||||
use image_viewer;
|
||||
use language::LanguageRegistry;
|
||||
|
||||
@@ -10,7 +10,7 @@ use client::ZED_URL_SCHEME;
|
||||
use collections::VecDeque;
|
||||
use editor::{scroll::Autoscroll, Editor, MultiBuffer};
|
||||
use gpui::{
|
||||
actions, point, px, AppContext, AsyncAppContext, Context, FocusableView, MenuItem, PromptLevel,
|
||||
actions, point, px, AppContext, AsyncAppContext, StaticContext, FocusableView, MenuItem, PromptLevel,
|
||||
ReadGlobal, TitlebarOptions, View, ViewContext, VisualContext, WindowKind, WindowOptions,
|
||||
};
|
||||
pub use open_listener::*;
|
||||
|
||||
@@ -4,7 +4,7 @@ use client::telemetry::Telemetry;
|
||||
use collections::HashMap;
|
||||
use copilot::{Copilot, CopilotCompletionProvider};
|
||||
use editor::{Editor, EditorMode};
|
||||
use gpui::{AnyWindowHandle, AppContext, Context, ViewContext, WeakView};
|
||||
use gpui::{AnyWindowHandle, AppContext, StaticContext, ViewContext, WeakView};
|
||||
use language::language_settings::all_language_settings;
|
||||
use settings::SettingsStore;
|
||||
use supermaven::{Supermaven, SupermavenCompletionProvider};
|
||||
|
||||
Reference in New Issue
Block a user