Eliminate GPUI View, ViewContext, and WindowContext types (#22632)
There's still a bit more work to do on this, but this PR is compiling (with warnings) after eliminating the key types. When the tasks below are complete, this will be the new narrative for GPUI: - `Entity<T>` - This replaces `View<T>`/`Model<T>`. It represents a unit of state, and if `T` implements `Render`, then `Entity<T>` implements `Element`. - `&mut App` This replaces `AppContext` and represents the app. - `&mut Context<T>` This replaces `ModelContext` and derefs to `App`. It is provided by the framework when updating an entity. - `&mut Window` Broken out of `&mut WindowContext` which no longer exists. Every method that once took `&mut WindowContext` now takes `&mut Window, &mut App` and every method that took `&mut ViewContext<T>` now takes `&mut Window, &mut Context<T>` Not pictured here are the two other failed attempts. It's been quite a month! Tasks: - [x] Remove `View`, `ViewContext`, `WindowContext` and thread through `Window` - [x] [@cole-miller @mikayla-maki] Redraw window when entities change - [x] [@cole-miller @mikayla-maki] Get examples and Zed running - [x] [@cole-miller @mikayla-maki] Fix Zed rendering - [x] [@mikayla-maki] Fix todo! macros and comments - [x] Fix a bug where the editor would not be redrawn because of view caching - [x] remove publicness window.notify() and replace with `AppContext::notify` - [x] remove `observe_new_window_models`, replace with `observe_new_models` with an optional window - [x] Fix a bug where the project panel would not be redrawn because of the wrong refresh() call being used - [x] Fix the tests - [x] Fix warnings by eliminating `Window` params or using `_` - [x] Fix conflicts - [x] Simplify generic code where possible - [x] Rename types - [ ] Update docs ### issues post merge - [x] Issues switching between normal and insert mode - [x] Assistant re-rendering failure - [x] Vim test failures - [x] Mac build issue Release Notes: - N/A --------- Co-authored-by: Antonio Scandurra <me@as-cii.com> Co-authored-by: Cole Miller <cole@zed.dev> Co-authored-by: Mikayla <mikayla@zed.dev> Co-authored-by: Joseph <joseph@zed.dev> Co-authored-by: max <max@zed.dev> Co-authored-by: Michael Sloan <michael@zed.dev> Co-authored-by: Mikayla Maki <mikaylamaki@Mikaylas-MacBook-Pro.local> Co-authored-by: Mikayla <mikayla.c.maki@gmail.com> Co-authored-by: joão <joao@zed.dev>
This commit is contained in:
parent
21b4a0d50e
commit
6fca1d2b0b
648 changed files with 36248 additions and 28208 deletions
|
@ -9,7 +9,7 @@ mod slash_command_picker;
|
|||
use std::sync::Arc;
|
||||
|
||||
use client::Client;
|
||||
use gpui::AppContext;
|
||||
use gpui::App;
|
||||
|
||||
pub use crate::context::*;
|
||||
pub use crate::context_editor::*;
|
||||
|
@ -18,6 +18,6 @@ pub use crate::context_store::*;
|
|||
pub use crate::patch::*;
|
||||
pub use crate::slash_command::*;
|
||||
|
||||
pub fn init(client: Arc<Client>, _cx: &mut AppContext) {
|
||||
pub fn init(client: Arc<Client>, _cx: &mut App) {
|
||||
context_store::init(&client.into());
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@ use feature_flags::{FeatureFlagAppExt, ToolUseFeatureFlag};
|
|||
use fs::{Fs, RemoveOptions};
|
||||
use futures::{future::Shared, FutureExt, StreamExt};
|
||||
use gpui::{
|
||||
AppContext, Context as _, EventEmitter, Model, ModelContext, RenderImage, SharedString,
|
||||
Subscription, Task,
|
||||
App, AppContext as _, Context, Entity, EventEmitter, RenderImage, SharedString, Subscription,
|
||||
Task,
|
||||
};
|
||||
use language::{AnchorRangeExt, Bias, Buffer, LanguageRegistry, OffsetRangeExt, Point, ToOffset};
|
||||
use language_model::{
|
||||
|
@ -588,13 +588,13 @@ pub enum XmlTagKind {
|
|||
Operation,
|
||||
}
|
||||
|
||||
pub struct Context {
|
||||
pub struct AssistantContext {
|
||||
id: ContextId,
|
||||
timestamp: clock::Lamport,
|
||||
version: clock::Global,
|
||||
pending_ops: Vec<ContextOperation>,
|
||||
operations: Vec<ContextOperation>,
|
||||
buffer: Model<Buffer>,
|
||||
buffer: Entity<Buffer>,
|
||||
parsed_slash_commands: Vec<ParsedSlashCommand>,
|
||||
invoked_slash_commands: HashMap<InvokedSlashCommandId, InvokedSlashCommand>,
|
||||
edits_since_last_parse: language::Subscription,
|
||||
|
@ -619,7 +619,7 @@ pub struct Context {
|
|||
language_registry: Arc<LanguageRegistry>,
|
||||
patches: Vec<AssistantPatch>,
|
||||
xml_tags: Vec<XmlTag>,
|
||||
project: Option<Model<Project>>,
|
||||
project: Option<Entity<Project>>,
|
||||
prompt_builder: Arc<PromptBuilder>,
|
||||
}
|
||||
|
||||
|
@ -645,17 +645,17 @@ impl ContextAnnotation for XmlTag {
|
|||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<ContextEvent> for Context {}
|
||||
impl EventEmitter<ContextEvent> for AssistantContext {}
|
||||
|
||||
impl Context {
|
||||
impl AssistantContext {
|
||||
pub fn local(
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
project: Option<Model<Project>>,
|
||||
project: Option<Entity<Project>>,
|
||||
telemetry: Option<Arc<Telemetry>>,
|
||||
prompt_builder: Arc<PromptBuilder>,
|
||||
slash_commands: Arc<SlashCommandWorkingSet>,
|
||||
tools: Arc<ToolWorkingSet>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
Self::new(
|
||||
ContextId::new(),
|
||||
|
@ -680,11 +680,11 @@ impl Context {
|
|||
prompt_builder: Arc<PromptBuilder>,
|
||||
slash_commands: Arc<SlashCommandWorkingSet>,
|
||||
tools: Arc<ToolWorkingSet>,
|
||||
project: Option<Model<Project>>,
|
||||
project: Option<Entity<Project>>,
|
||||
telemetry: Option<Arc<Telemetry>>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
let buffer = cx.new_model(|_cx| {
|
||||
let buffer = cx.new(|_cx| {
|
||||
let buffer = Buffer::remote(
|
||||
language::BufferId::new(1).unwrap(),
|
||||
replica_id,
|
||||
|
@ -755,7 +755,7 @@ impl Context {
|
|||
this
|
||||
}
|
||||
|
||||
pub(crate) fn serialize(&self, cx: &AppContext) -> SavedContext {
|
||||
pub(crate) fn serialize(&self, cx: &App) -> SavedContext {
|
||||
let buffer = self.buffer.read(cx);
|
||||
SavedContext {
|
||||
id: Some(self.id.clone()),
|
||||
|
@ -803,9 +803,9 @@ impl Context {
|
|||
prompt_builder: Arc<PromptBuilder>,
|
||||
slash_commands: Arc<SlashCommandWorkingSet>,
|
||||
tools: Arc<ToolWorkingSet>,
|
||||
project: Option<Model<Project>>,
|
||||
project: Option<Entity<Project>>,
|
||||
telemetry: Option<Arc<Telemetry>>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
let id = saved_context.id.clone().unwrap_or_else(ContextId::new);
|
||||
let mut this = Self::new(
|
||||
|
@ -837,7 +837,7 @@ impl Context {
|
|||
self.timestamp.replica_id
|
||||
}
|
||||
|
||||
pub fn version(&self, cx: &AppContext) -> ContextVersion {
|
||||
pub fn version(&self, cx: &App) -> ContextVersion {
|
||||
ContextVersion {
|
||||
context: self.version.clone(),
|
||||
buffer: self.buffer.read(cx).version(),
|
||||
|
@ -852,11 +852,7 @@ impl Context {
|
|||
&self.tools
|
||||
}
|
||||
|
||||
pub fn set_capability(
|
||||
&mut self,
|
||||
capability: language::Capability,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
pub fn set_capability(&mut self, capability: language::Capability, cx: &mut Context<Self>) {
|
||||
self.buffer
|
||||
.update(cx, |buffer, cx| buffer.set_capability(capability, cx));
|
||||
}
|
||||
|
@ -870,7 +866,7 @@ impl Context {
|
|||
pub fn serialize_ops(
|
||||
&self,
|
||||
since: &ContextVersion,
|
||||
cx: &AppContext,
|
||||
cx: &App,
|
||||
) -> Task<Vec<proto::ContextOperation>> {
|
||||
let buffer_ops = self
|
||||
.buffer
|
||||
|
@ -905,7 +901,7 @@ impl Context {
|
|||
pub fn apply_ops(
|
||||
&mut self,
|
||||
ops: impl IntoIterator<Item = ContextOperation>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let mut buffer_ops = Vec::new();
|
||||
for op in ops {
|
||||
|
@ -919,7 +915,7 @@ impl Context {
|
|||
self.flush_ops(cx);
|
||||
}
|
||||
|
||||
fn flush_ops(&mut self, cx: &mut ModelContext<Context>) {
|
||||
fn flush_ops(&mut self, cx: &mut Context<AssistantContext>) {
|
||||
let mut changed_messages = HashSet::default();
|
||||
let mut summary_changed = false;
|
||||
|
||||
|
@ -1038,7 +1034,7 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
fn can_apply_op(&self, op: &ContextOperation, cx: &AppContext) -> bool {
|
||||
fn can_apply_op(&self, op: &ContextOperation, cx: &App) -> bool {
|
||||
if !self.version.observed_all(op.version()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1069,7 +1065,7 @@ impl Context {
|
|||
fn has_received_operations_for_anchor_range(
|
||||
&self,
|
||||
range: Range<text::Anchor>,
|
||||
cx: &AppContext,
|
||||
cx: &App,
|
||||
) -> bool {
|
||||
let version = &self.buffer.read(cx).version;
|
||||
let observed_start = range.start == language::Anchor::MIN
|
||||
|
@ -1081,12 +1077,12 @@ impl Context {
|
|||
observed_start && observed_end
|
||||
}
|
||||
|
||||
fn push_op(&mut self, op: ContextOperation, cx: &mut ModelContext<Self>) {
|
||||
fn push_op(&mut self, op: ContextOperation, cx: &mut Context<Self>) {
|
||||
self.operations.push(op.clone());
|
||||
cx.emit(ContextEvent::Operation(op));
|
||||
}
|
||||
|
||||
pub fn buffer(&self) -> &Model<Buffer> {
|
||||
pub fn buffer(&self) -> &Entity<Buffer> {
|
||||
&self.buffer
|
||||
}
|
||||
|
||||
|
@ -1094,7 +1090,7 @@ impl Context {
|
|||
self.language_registry.clone()
|
||||
}
|
||||
|
||||
pub fn project(&self) -> Option<Model<Project>> {
|
||||
pub fn project(&self) -> Option<Entity<Project>> {
|
||||
self.project.clone()
|
||||
}
|
||||
|
||||
|
@ -1110,7 +1106,7 @@ impl Context {
|
|||
self.summary.as_ref()
|
||||
}
|
||||
|
||||
pub fn patch_containing(&self, position: Point, cx: &AppContext) -> Option<&AssistantPatch> {
|
||||
pub fn patch_containing(&self, position: Point, cx: &App) -> Option<&AssistantPatch> {
|
||||
let buffer = self.buffer.read(cx);
|
||||
let index = self.patches.binary_search_by(|patch| {
|
||||
let patch_range = patch.range.to_point(&buffer);
|
||||
|
@ -1136,7 +1132,7 @@ impl Context {
|
|||
pub fn patch_for_range(
|
||||
&self,
|
||||
range: &Range<language::Anchor>,
|
||||
cx: &AppContext,
|
||||
cx: &App,
|
||||
) -> Option<&AssistantPatch> {
|
||||
let buffer = self.buffer.read(cx);
|
||||
let index = self.patch_index_for_range(range, buffer).ok()?;
|
||||
|
@ -1167,7 +1163,7 @@ impl Context {
|
|||
&self.slash_command_output_sections
|
||||
}
|
||||
|
||||
pub fn contains_files(&self, cx: &AppContext) -> bool {
|
||||
pub fn contains_files(&self, cx: &App) -> bool {
|
||||
let buffer = self.buffer.read(cx);
|
||||
self.slash_command_output_sections.iter().any(|section| {
|
||||
section.is_valid(buffer)
|
||||
|
@ -1189,7 +1185,7 @@ impl Context {
|
|||
self.pending_tool_uses_by_id.get(id)
|
||||
}
|
||||
|
||||
fn set_language(&mut self, cx: &mut ModelContext<Self>) {
|
||||
fn set_language(&mut self, cx: &mut Context<Self>) {
|
||||
let markdown = self.language_registry.language_for_name("Markdown");
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let markdown = markdown.await?;
|
||||
|
@ -1203,9 +1199,9 @@ impl Context {
|
|||
|
||||
fn handle_buffer_event(
|
||||
&mut self,
|
||||
_: Model<Buffer>,
|
||||
_: Entity<Buffer>,
|
||||
event: &language::BufferEvent,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
match event {
|
||||
language::BufferEvent::Operation {
|
||||
|
@ -1227,7 +1223,7 @@ impl Context {
|
|||
self.token_count
|
||||
}
|
||||
|
||||
pub(crate) fn count_remaining_tokens(&mut self, cx: &mut ModelContext<Self>) {
|
||||
pub(crate) fn count_remaining_tokens(&mut self, cx: &mut Context<Self>) {
|
||||
// Assume it will be a Chat request, even though that takes fewer tokens (and risks going over the limit),
|
||||
// because otherwise you see in the UI that your empty message has a bunch of tokens already used.
|
||||
let request = self.to_completion_request(RequestType::Chat, cx);
|
||||
|
@ -1255,7 +1251,7 @@ impl Context {
|
|||
&mut self,
|
||||
cache_configuration: &Option<LanguageModelCacheConfiguration>,
|
||||
speculative: bool,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
let cache_configuration =
|
||||
cache_configuration
|
||||
|
@ -1357,7 +1353,7 @@ impl Context {
|
|||
new_anchor_needs_caching
|
||||
}
|
||||
|
||||
fn start_cache_warming(&mut self, model: &Arc<dyn LanguageModel>, cx: &mut ModelContext<Self>) {
|
||||
fn start_cache_warming(&mut self, model: &Arc<dyn LanguageModel>, cx: &mut Context<Self>) {
|
||||
let cache_configuration = model.cache_configuration();
|
||||
|
||||
if !self.mark_cache_anchors(&cache_configuration, true, cx) {
|
||||
|
@ -1407,7 +1403,7 @@ impl Context {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn update_cache_status_for_completion(&mut self, cx: &mut ModelContext<Self>) {
|
||||
pub fn update_cache_status_for_completion(&mut self, cx: &mut Context<Self>) {
|
||||
let cached_message_ids: Vec<MessageId> = self
|
||||
.messages_metadata
|
||||
.iter()
|
||||
|
@ -1432,7 +1428,7 @@ impl Context {
|
|||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn reparse(&mut self, cx: &mut ModelContext<Self>) {
|
||||
pub fn reparse(&mut self, cx: &mut Context<Self>) {
|
||||
let buffer = self.buffer.read(cx).text_snapshot();
|
||||
let mut row_ranges = self
|
||||
.edits_since_last_parse
|
||||
|
@ -1505,7 +1501,7 @@ impl Context {
|
|||
buffer: &BufferSnapshot,
|
||||
updated: &mut Vec<ParsedSlashCommand>,
|
||||
removed: &mut Vec<Range<text::Anchor>>,
|
||||
cx: &AppContext,
|
||||
cx: &App,
|
||||
) {
|
||||
let old_range = self.pending_command_indices_for_range(range.clone(), cx);
|
||||
|
||||
|
@ -1559,7 +1555,7 @@ impl Context {
|
|||
fn invalidate_pending_slash_commands(
|
||||
&mut self,
|
||||
buffer: &BufferSnapshot,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let mut invalidated_command_ids = Vec::new();
|
||||
for (&command_id, command) in self.invoked_slash_commands.iter_mut() {
|
||||
|
@ -1593,7 +1589,7 @@ impl Context {
|
|||
buffer: &BufferSnapshot,
|
||||
updated: &mut Vec<Range<text::Anchor>>,
|
||||
removed: &mut Vec<Range<text::Anchor>>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
// Rebuild the XML tags in the edited range.
|
||||
let intersecting_tags_range =
|
||||
|
@ -1636,7 +1632,7 @@ impl Context {
|
|||
&self,
|
||||
buffer: &BufferSnapshot,
|
||||
range: Range<text::Anchor>,
|
||||
cx: &AppContext,
|
||||
cx: &App,
|
||||
) -> Vec<XmlTag> {
|
||||
let mut messages = self.messages(cx).peekable();
|
||||
|
||||
|
@ -1693,7 +1689,7 @@ impl Context {
|
|||
tags_start_ix: usize,
|
||||
buffer_end: text::Anchor,
|
||||
buffer: &BufferSnapshot,
|
||||
cx: &AppContext,
|
||||
cx: &App,
|
||||
) -> Vec<AssistantPatch> {
|
||||
let mut new_patches = Vec::new();
|
||||
let mut pending_patch = None;
|
||||
|
@ -1851,7 +1847,7 @@ impl Context {
|
|||
pub fn pending_command_for_position(
|
||||
&mut self,
|
||||
position: language::Anchor,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<&mut ParsedSlashCommand> {
|
||||
let buffer = self.buffer.read(cx);
|
||||
match self
|
||||
|
@ -1875,7 +1871,7 @@ impl Context {
|
|||
pub fn pending_commands_for_range(
|
||||
&self,
|
||||
range: Range<language::Anchor>,
|
||||
cx: &AppContext,
|
||||
cx: &App,
|
||||
) -> &[ParsedSlashCommand] {
|
||||
let range = self.pending_command_indices_for_range(range, cx);
|
||||
&self.parsed_slash_commands[range]
|
||||
|
@ -1884,7 +1880,7 @@ impl Context {
|
|||
fn pending_command_indices_for_range(
|
||||
&self,
|
||||
range: Range<language::Anchor>,
|
||||
cx: &AppContext,
|
||||
cx: &App,
|
||||
) -> Range<usize> {
|
||||
self.indices_intersecting_buffer_range(&self.parsed_slash_commands, range, cx)
|
||||
}
|
||||
|
@ -1893,7 +1889,7 @@ impl Context {
|
|||
&self,
|
||||
all_annotations: &[T],
|
||||
range: Range<language::Anchor>,
|
||||
cx: &AppContext,
|
||||
cx: &App,
|
||||
) -> Range<usize> {
|
||||
let buffer = self.buffer.read(cx);
|
||||
let start_ix = match all_annotations
|
||||
|
@ -1916,7 +1912,7 @@ impl Context {
|
|||
name: &str,
|
||||
output: Task<SlashCommandResult>,
|
||||
ensure_trailing_newline: bool,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let version = self.version.clone();
|
||||
let command_id = InvokedSlashCommandId(self.next_timestamp());
|
||||
|
@ -2184,7 +2180,7 @@ impl Context {
|
|||
fn insert_slash_command_output_section(
|
||||
&mut self,
|
||||
section: SlashCommandOutputSection<language::Anchor>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let buffer = self.buffer.read(cx);
|
||||
let insertion_ix = match self
|
||||
|
@ -2214,7 +2210,7 @@ impl Context {
|
|||
&mut self,
|
||||
tool_use_id: LanguageModelToolUseId,
|
||||
output: Task<Result<String>>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let insert_output_task = cx.spawn(|this, mut cx| {
|
||||
let tool_use_id = tool_use_id.clone();
|
||||
|
@ -2272,11 +2268,11 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn completion_provider_changed(&mut self, cx: &mut ModelContext<Self>) {
|
||||
pub fn completion_provider_changed(&mut self, cx: &mut Context<Self>) {
|
||||
self.count_remaining_tokens(cx);
|
||||
}
|
||||
|
||||
fn get_last_valid_message_id(&self, cx: &ModelContext<Self>) -> Option<MessageId> {
|
||||
fn get_last_valid_message_id(&self, cx: &Context<Self>) -> Option<MessageId> {
|
||||
self.message_anchors.iter().rev().find_map(|message| {
|
||||
message
|
||||
.start
|
||||
|
@ -2288,7 +2284,7 @@ impl Context {
|
|||
pub fn assist(
|
||||
&mut self,
|
||||
request_type: RequestType,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<MessageAnchor> {
|
||||
let model_registry = LanguageModelRegistry::read_global(cx);
|
||||
let provider = model_registry.active_provider()?;
|
||||
|
@ -2519,7 +2515,7 @@ impl Context {
|
|||
pub fn to_completion_request(
|
||||
&self,
|
||||
request_type: RequestType,
|
||||
cx: &AppContext,
|
||||
cx: &App,
|
||||
) -> LanguageModelRequest {
|
||||
let buffer = self.buffer.read(cx);
|
||||
|
||||
|
@ -2631,7 +2627,7 @@ impl Context {
|
|||
completion_request
|
||||
}
|
||||
|
||||
pub fn cancel_last_assist(&mut self, cx: &mut ModelContext<Self>) -> bool {
|
||||
pub fn cancel_last_assist(&mut self, cx: &mut Context<Self>) -> bool {
|
||||
if let Some(pending_completion) = self.pending_completions.pop() {
|
||||
self.update_metadata(pending_completion.assistant_message_id, cx, |metadata| {
|
||||
if metadata.status == MessageStatus::Pending {
|
||||
|
@ -2644,7 +2640,7 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn cycle_message_roles(&mut self, ids: HashSet<MessageId>, cx: &mut ModelContext<Self>) {
|
||||
pub fn cycle_message_roles(&mut self, ids: HashSet<MessageId>, cx: &mut Context<Self>) {
|
||||
for id in &ids {
|
||||
if let Some(metadata) = self.messages_metadata.get(id) {
|
||||
let role = metadata.role.cycle();
|
||||
|
@ -2655,7 +2651,7 @@ impl Context {
|
|||
self.message_roles_updated(ids, cx);
|
||||
}
|
||||
|
||||
fn message_roles_updated(&mut self, ids: HashSet<MessageId>, cx: &mut ModelContext<Self>) {
|
||||
fn message_roles_updated(&mut self, ids: HashSet<MessageId>, cx: &mut Context<Self>) {
|
||||
let mut ranges = Vec::new();
|
||||
for message in self.messages(cx) {
|
||||
if ids.contains(&message.id) {
|
||||
|
@ -2678,7 +2674,7 @@ impl Context {
|
|||
pub fn update_metadata(
|
||||
&mut self,
|
||||
id: MessageId,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
f: impl FnOnce(&mut MessageMetadata),
|
||||
) {
|
||||
let version = self.version.clone();
|
||||
|
@ -2702,7 +2698,7 @@ impl Context {
|
|||
message_id: MessageId,
|
||||
role: Role,
|
||||
status: MessageStatus,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<MessageAnchor> {
|
||||
if let Some(prev_message_ix) = self
|
||||
.message_anchors
|
||||
|
@ -2736,7 +2732,7 @@ impl Context {
|
|||
offset: usize,
|
||||
role: Role,
|
||||
status: MessageStatus,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> MessageAnchor {
|
||||
let start = self.buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit([(offset..offset, "\n")], None, cx);
|
||||
|
@ -2766,7 +2762,7 @@ impl Context {
|
|||
anchor
|
||||
}
|
||||
|
||||
pub fn insert_content(&mut self, content: Content, cx: &mut ModelContext<Self>) {
|
||||
pub fn insert_content(&mut self, content: Content, cx: &mut Context<Self>) {
|
||||
let buffer = self.buffer.read(cx);
|
||||
let insertion_ix = match self
|
||||
.contents
|
||||
|
@ -2782,7 +2778,7 @@ impl Context {
|
|||
cx.emit(ContextEvent::MessagesEdited);
|
||||
}
|
||||
|
||||
pub fn contents<'a>(&'a self, cx: &'a AppContext) -> impl 'a + Iterator<Item = Content> {
|
||||
pub fn contents<'a>(&'a self, cx: &'a App) -> impl 'a + Iterator<Item = Content> {
|
||||
let buffer = self.buffer.read(cx);
|
||||
self.contents
|
||||
.iter()
|
||||
|
@ -2796,7 +2792,7 @@ impl Context {
|
|||
pub fn split_message(
|
||||
&mut self,
|
||||
range: Range<usize>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> (Option<MessageAnchor>, Option<MessageAnchor>) {
|
||||
let start_message = self.message_for_offset(range.start, cx);
|
||||
let end_message = self.message_for_offset(range.end, cx);
|
||||
|
@ -2922,7 +2918,7 @@ impl Context {
|
|||
&mut self,
|
||||
new_anchor: MessageAnchor,
|
||||
new_metadata: MessageMetadata,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
cx.emit(ContextEvent::MessagesEdited);
|
||||
|
||||
|
@ -2940,7 +2936,7 @@ impl Context {
|
|||
self.message_anchors.insert(insertion_ix, new_anchor);
|
||||
}
|
||||
|
||||
pub fn summarize(&mut self, replace_old: bool, cx: &mut ModelContext<Self>) {
|
||||
pub fn summarize(&mut self, replace_old: bool, cx: &mut Context<Self>) {
|
||||
let Some(provider) = LanguageModelRegistry::read_global(cx).active_provider() else {
|
||||
return;
|
||||
};
|
||||
|
@ -3018,14 +3014,14 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
fn message_for_offset(&self, offset: usize, cx: &AppContext) -> Option<Message> {
|
||||
fn message_for_offset(&self, offset: usize, cx: &App) -> Option<Message> {
|
||||
self.messages_for_offsets([offset], cx).pop()
|
||||
}
|
||||
|
||||
pub fn messages_for_offsets(
|
||||
&self,
|
||||
offsets: impl IntoIterator<Item = usize>,
|
||||
cx: &AppContext,
|
||||
cx: &App,
|
||||
) -> Vec<Message> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
|
@ -3058,14 +3054,14 @@ impl Context {
|
|||
fn messages_from_anchors<'a>(
|
||||
&'a self,
|
||||
message_anchors: impl Iterator<Item = &'a MessageAnchor> + 'a,
|
||||
cx: &'a AppContext,
|
||||
cx: &'a App,
|
||||
) -> impl 'a + Iterator<Item = Message> {
|
||||
let buffer = self.buffer.read(cx);
|
||||
|
||||
Self::messages_from_iters(buffer, &self.messages_metadata, message_anchors.enumerate())
|
||||
}
|
||||
|
||||
pub fn messages<'a>(&'a self, cx: &'a AppContext) -> impl 'a + Iterator<Item = Message> {
|
||||
pub fn messages<'a>(&'a self, cx: &'a App) -> impl 'a + Iterator<Item = Message> {
|
||||
self.messages_from_anchors(self.message_anchors.iter(), cx)
|
||||
}
|
||||
|
||||
|
@ -3113,7 +3109,7 @@ impl Context {
|
|||
&mut self,
|
||||
debounce: Option<Duration>,
|
||||
fs: Arc<dyn Fs>,
|
||||
cx: &mut ModelContext<Context>,
|
||||
cx: &mut Context<AssistantContext>,
|
||||
) {
|
||||
if self.replica_id() != ReplicaId::default() {
|
||||
// Prevent saving a remote context for now.
|
||||
|
@ -3179,7 +3175,7 @@ impl Context {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn custom_summary(&mut self, custom_summary: String, cx: &mut ModelContext<Self>) {
|
||||
pub fn custom_summary(&mut self, custom_summary: String, cx: &mut Context<Self>) {
|
||||
let timestamp = self.next_timestamp();
|
||||
let summary = self.summary.get_or_insert(ContextSummary::default());
|
||||
summary.timestamp = timestamp;
|
||||
|
@ -3339,8 +3335,8 @@ impl SavedContext {
|
|||
|
||||
fn into_ops(
|
||||
self,
|
||||
buffer: &Model<Buffer>,
|
||||
cx: &mut ModelContext<Context>,
|
||||
buffer: &Entity<Buffer>,
|
||||
cx: &mut Context<AssistantContext>,
|
||||
) -> Vec<ContextOperation> {
|
||||
let mut operations = Vec::new();
|
||||
let mut version = clock::Global::new();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
AssistantEdit, AssistantEditKind, CacheStatus, Context, ContextEvent, ContextId,
|
||||
AssistantContext, AssistantEdit, AssistantEditKind, CacheStatus, ContextEvent, ContextId,
|
||||
ContextOperation, InvokedSlashCommandId, MessageCacheMetadata, MessageId, MessageStatus,
|
||||
};
|
||||
use anyhow::Result;
|
||||
|
@ -15,7 +15,7 @@ use futures::{
|
|||
channel::mpsc,
|
||||
stream::{self, StreamExt},
|
||||
};
|
||||
use gpui::{prelude::*, AppContext, Model, SharedString, Task, TestAppContext, WeakView};
|
||||
use gpui::{prelude::*, App, Entity, SharedString, Task, TestAppContext, WeakEntity};
|
||||
use language::{Buffer, BufferSnapshot, LanguageRegistry, LspAdapterDelegate};
|
||||
use language_model::{LanguageModelCacheConfiguration, LanguageModelRegistry, Role};
|
||||
use parking_lot::Mutex;
|
||||
|
@ -34,7 +34,7 @@ use std::{
|
|||
sync::{atomic::AtomicBool, Arc},
|
||||
};
|
||||
use text::{network::Network, OffsetRangeExt as _, ReplicaId, ToOffset};
|
||||
use ui::{IconName, WindowContext};
|
||||
use ui::{IconName, Window};
|
||||
use unindent::Unindent;
|
||||
use util::{
|
||||
test::{generate_marked_text, marked_text_ranges},
|
||||
|
@ -43,14 +43,14 @@ use util::{
|
|||
use workspace::Workspace;
|
||||
|
||||
#[gpui::test]
|
||||
fn test_inserting_and_removing_messages(cx: &mut AppContext) {
|
||||
fn test_inserting_and_removing_messages(cx: &mut App) {
|
||||
let settings_store = SettingsStore::test(cx);
|
||||
LanguageModelRegistry::test(cx);
|
||||
cx.set_global(settings_store);
|
||||
let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
|
||||
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
|
||||
let context = cx.new_model(|cx| {
|
||||
Context::local(
|
||||
let context = cx.new(|cx| {
|
||||
AssistantContext::local(
|
||||
registry,
|
||||
None,
|
||||
None,
|
||||
|
@ -183,15 +183,15 @@ fn test_inserting_and_removing_messages(cx: &mut AppContext) {
|
|||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_message_splitting(cx: &mut AppContext) {
|
||||
fn test_message_splitting(cx: &mut App) {
|
||||
let settings_store = SettingsStore::test(cx);
|
||||
cx.set_global(settings_store);
|
||||
LanguageModelRegistry::test(cx);
|
||||
let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
|
||||
|
||||
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
|
||||
let context = cx.new_model(|cx| {
|
||||
Context::local(
|
||||
let context = cx.new(|cx| {
|
||||
AssistantContext::local(
|
||||
registry.clone(),
|
||||
None,
|
||||
None,
|
||||
|
@ -287,14 +287,14 @@ fn test_message_splitting(cx: &mut AppContext) {
|
|||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_messages_for_offsets(cx: &mut AppContext) {
|
||||
fn test_messages_for_offsets(cx: &mut App) {
|
||||
let settings_store = SettingsStore::test(cx);
|
||||
LanguageModelRegistry::test(cx);
|
||||
cx.set_global(settings_store);
|
||||
let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
|
||||
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
|
||||
let context = cx.new_model(|cx| {
|
||||
Context::local(
|
||||
let context = cx.new(|cx| {
|
||||
AssistantContext::local(
|
||||
registry,
|
||||
None,
|
||||
None,
|
||||
|
@ -367,9 +367,9 @@ fn test_messages_for_offsets(cx: &mut AppContext) {
|
|||
);
|
||||
|
||||
fn message_ids_for_offsets(
|
||||
context: &Model<Context>,
|
||||
context: &Entity<AssistantContext>,
|
||||
offsets: &[usize],
|
||||
cx: &AppContext,
|
||||
cx: &App,
|
||||
) -> Vec<MessageId> {
|
||||
context
|
||||
.read(cx)
|
||||
|
@ -407,8 +407,8 @@ async fn test_slash_commands(cx: &mut TestAppContext) {
|
|||
|
||||
let registry = Arc::new(LanguageRegistry::test(cx.executor()));
|
||||
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
|
||||
let context = cx.new_model(|cx| {
|
||||
Context::local(
|
||||
let context = cx.new(|cx| {
|
||||
AssistantContext::local(
|
||||
registry.clone(),
|
||||
None,
|
||||
None,
|
||||
|
@ -608,7 +608,7 @@ async fn test_slash_commands(cx: &mut TestAppContext) {
|
|||
|
||||
#[track_caller]
|
||||
fn assert_text_and_context_ranges(
|
||||
buffer: &Model<Buffer>,
|
||||
buffer: &Entity<Buffer>,
|
||||
ranges: &RefCell<ContextRanges>,
|
||||
expected_marked_text: &str,
|
||||
cx: &mut TestAppContext,
|
||||
|
@ -697,8 +697,8 @@ async fn test_workflow_step_parsing(cx: &mut TestAppContext) {
|
|||
|
||||
// Create a new context
|
||||
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
|
||||
let context = cx.new_model(|cx| {
|
||||
Context::local(
|
||||
let context = cx.new(|cx| {
|
||||
AssistantContext::local(
|
||||
registry.clone(),
|
||||
Some(project),
|
||||
None,
|
||||
|
@ -962,8 +962,8 @@ async fn test_workflow_step_parsing(cx: &mut TestAppContext) {
|
|||
|
||||
// Ensure steps are re-parsed when deserializing.
|
||||
let serialized_context = context.read_with(cx, |context, cx| context.serialize(cx));
|
||||
let deserialized_context = cx.new_model(|cx| {
|
||||
Context::deserialize(
|
||||
let deserialized_context = cx.new(|cx| {
|
||||
AssistantContext::deserialize(
|
||||
serialized_context,
|
||||
Default::default(),
|
||||
registry.clone(),
|
||||
|
@ -1006,7 +1006,11 @@ async fn test_workflow_step_parsing(cx: &mut TestAppContext) {
|
|||
cx,
|
||||
);
|
||||
|
||||
fn edit(context: &Model<Context>, new_text_marked_with_edits: &str, cx: &mut TestAppContext) {
|
||||
fn edit(
|
||||
context: &Entity<AssistantContext>,
|
||||
new_text_marked_with_edits: &str,
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
context.update(cx, |context, cx| {
|
||||
context.buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit_via_marked_text(&new_text_marked_with_edits.unindent(), None, cx);
|
||||
|
@ -1017,7 +1021,7 @@ async fn test_workflow_step_parsing(cx: &mut TestAppContext) {
|
|||
|
||||
#[track_caller]
|
||||
fn expect_patches(
|
||||
context: &Model<Context>,
|
||||
context: &Entity<AssistantContext>,
|
||||
expected_marked_text: &str,
|
||||
expected_suggestions: &[&[AssistantEdit]],
|
||||
cx: &mut TestAppContext,
|
||||
|
@ -1077,8 +1081,8 @@ async fn test_serialization(cx: &mut TestAppContext) {
|
|||
cx.update(LanguageModelRegistry::test);
|
||||
let registry = Arc::new(LanguageRegistry::test(cx.executor()));
|
||||
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
|
||||
let context = cx.new_model(|cx| {
|
||||
Context::local(
|
||||
let context = cx.new(|cx| {
|
||||
AssistantContext::local(
|
||||
registry.clone(),
|
||||
None,
|
||||
None,
|
||||
|
@ -1121,8 +1125,8 @@ async fn test_serialization(cx: &mut TestAppContext) {
|
|||
);
|
||||
|
||||
let serialized_context = context.read_with(cx, |context, cx| context.serialize(cx));
|
||||
let deserialized_context = cx.new_model(|cx| {
|
||||
Context::deserialize(
|
||||
let deserialized_context = cx.new(|cx| {
|
||||
AssistantContext::deserialize(
|
||||
serialized_context,
|
||||
Default::default(),
|
||||
registry.clone(),
|
||||
|
@ -1179,8 +1183,8 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
|
|||
let context_id = ContextId::new();
|
||||
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
|
||||
for i in 0..num_peers {
|
||||
let context = cx.new_model(|cx| {
|
||||
Context::new(
|
||||
let context = cx.new(|cx| {
|
||||
AssistantContext::new(
|
||||
context_id.clone(),
|
||||
i as ReplicaId,
|
||||
language::Capability::ReadWrite,
|
||||
|
@ -1434,14 +1438,14 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
|
|||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_mark_cache_anchors(cx: &mut AppContext) {
|
||||
fn test_mark_cache_anchors(cx: &mut App) {
|
||||
let settings_store = SettingsStore::test(cx);
|
||||
LanguageModelRegistry::test(cx);
|
||||
cx.set_global(settings_store);
|
||||
let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
|
||||
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
|
||||
let context = cx.new_model(|cx| {
|
||||
Context::local(
|
||||
let context = cx.new(|cx| {
|
||||
AssistantContext::local(
|
||||
registry,
|
||||
None,
|
||||
None,
|
||||
|
@ -1594,7 +1598,7 @@ fn test_mark_cache_anchors(cx: &mut AppContext) {
|
|||
);
|
||||
}
|
||||
|
||||
fn messages(context: &Model<Context>, cx: &AppContext) -> Vec<(MessageId, Role, Range<usize>)> {
|
||||
fn messages(context: &Entity<AssistantContext>, cx: &App) -> Vec<(MessageId, Role, Range<usize>)> {
|
||||
context
|
||||
.read(cx)
|
||||
.messages(cx)
|
||||
|
@ -1603,8 +1607,8 @@ fn messages(context: &Model<Context>, cx: &AppContext) -> Vec<(MessageId, Role,
|
|||
}
|
||||
|
||||
fn messages_cache(
|
||||
context: &Model<Context>,
|
||||
cx: &AppContext,
|
||||
context: &Entity<AssistantContext>,
|
||||
cx: &App,
|
||||
) -> Vec<(MessageId, Option<MessageCacheMetadata>)> {
|
||||
context
|
||||
.read(cx)
|
||||
|
@ -1633,8 +1637,9 @@ impl SlashCommand for FakeSlashCommand {
|
|||
self: Arc<Self>,
|
||||
_arguments: &[String],
|
||||
_cancel: Arc<AtomicBool>,
|
||||
_workspace: Option<WeakView<Workspace>>,
|
||||
_cx: &mut WindowContext,
|
||||
_workspace: Option<WeakEntity<Workspace>>,
|
||||
_window: &mut Window,
|
||||
_cx: &mut App,
|
||||
) -> Task<Result<Vec<ArgumentCompletion>>> {
|
||||
Task::ready(Ok(vec![]))
|
||||
}
|
||||
|
@ -1648,9 +1653,10 @@ impl SlashCommand for FakeSlashCommand {
|
|||
_arguments: &[String],
|
||||
_context_slash_command_output_sections: &[SlashCommandOutputSection<language::Anchor>],
|
||||
_context_buffer: BufferSnapshot,
|
||||
_workspace: WeakView<Workspace>,
|
||||
_workspace: WeakEntity<Workspace>,
|
||||
_delegate: Option<Arc<dyn LspAdapterDelegate>>,
|
||||
_cx: &mut WindowContext,
|
||||
_window: &mut Window,
|
||||
_cx: &mut App,
|
||||
) -> Task<SlashCommandResult> {
|
||||
Task::ready(Ok(SlashCommandOutput {
|
||||
text: format!("Executed fake command: {}", self.0),
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,6 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use gpui::{
|
||||
AppContext, EventEmitter, FocusHandle, FocusableView, Model, Subscription, Task, View, WeakView,
|
||||
};
|
||||
use gpui::{App, Entity, EventEmitter, FocusHandle, Focusable, Subscription, Task, WeakEntity};
|
||||
use picker::{Picker, PickerDelegate};
|
||||
use project::Project;
|
||||
use ui::utils::{format_distance_from_now, DateTimeType};
|
||||
|
@ -25,21 +23,23 @@ enum SavedContextPickerEvent {
|
|||
}
|
||||
|
||||
pub struct ContextHistory {
|
||||
picker: View<Picker<SavedContextPickerDelegate>>,
|
||||
picker: Entity<Picker<SavedContextPickerDelegate>>,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
workspace: WeakView<Workspace>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
}
|
||||
|
||||
impl ContextHistory {
|
||||
pub fn new(
|
||||
project: Model<Project>,
|
||||
context_store: Model<ContextStore>,
|
||||
workspace: WeakView<Workspace>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
project: Entity<Project>,
|
||||
context_store: Entity<ContextStore>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
let picker = cx.new_view(|cx| {
|
||||
let picker = cx.new(|cx| {
|
||||
Picker::uniform_list(
|
||||
SavedContextPickerDelegate::new(project, context_store.clone()),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
.modal(false)
|
||||
|
@ -47,10 +47,11 @@ impl ContextHistory {
|
|||
});
|
||||
|
||||
let subscriptions = vec![
|
||||
cx.observe(&context_store, |this, _, cx| {
|
||||
this.picker.update(cx, |picker, cx| picker.refresh(cx));
|
||||
cx.observe_in(&context_store, window, |this, _, window, cx| {
|
||||
this.picker
|
||||
.update(cx, |picker, cx| picker.refresh(window, cx));
|
||||
}),
|
||||
cx.subscribe(&picker, Self::handle_picker_event),
|
||||
cx.subscribe_in(&picker, window, Self::handle_picker_event),
|
||||
];
|
||||
|
||||
Self {
|
||||
|
@ -62,9 +63,10 @@ impl ContextHistory {
|
|||
|
||||
fn handle_picker_event(
|
||||
&mut self,
|
||||
_: View<Picker<SavedContextPickerDelegate>>,
|
||||
_: &Entity<Picker<SavedContextPickerDelegate>>,
|
||||
event: &SavedContextPickerEvent,
|
||||
cx: &mut ViewContext<Self>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let SavedContextPickerEvent::Confirmed(context) = event;
|
||||
|
||||
|
@ -76,12 +78,12 @@ impl ContextHistory {
|
|||
.update(cx, |workspace, cx| match context {
|
||||
ContextMetadata::Remote(metadata) => {
|
||||
assistant_panel_delegate
|
||||
.open_remote_context(workspace, metadata.id.clone(), cx)
|
||||
.open_remote_context(workspace, metadata.id.clone(), window, cx)
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
ContextMetadata::Saved(metadata) => {
|
||||
assistant_panel_delegate
|
||||
.open_saved_context(workspace, metadata.path.clone(), cx)
|
||||
.open_saved_context(workspace, metadata.path.clone(), window, cx)
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
})
|
||||
|
@ -90,13 +92,13 @@ impl ContextHistory {
|
|||
}
|
||||
|
||||
impl Render for ContextHistory {
|
||||
fn render(&mut self, _: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
div().size_full().child(self.picker.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl FocusableView for ContextHistory {
|
||||
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
|
||||
impl Focusable for ContextHistory {
|
||||
fn focus_handle(&self, cx: &App) -> FocusHandle {
|
||||
self.picker.focus_handle(cx)
|
||||
}
|
||||
}
|
||||
|
@ -106,14 +108,14 @@ impl EventEmitter<()> for ContextHistory {}
|
|||
impl Item for ContextHistory {
|
||||
type Event = ();
|
||||
|
||||
fn tab_content_text(&self, _cx: &WindowContext) -> Option<SharedString> {
|
||||
fn tab_content_text(&self, _window: &Window, _cx: &App) -> Option<SharedString> {
|
||||
Some("History".into())
|
||||
}
|
||||
}
|
||||
|
||||
struct SavedContextPickerDelegate {
|
||||
store: Model<ContextStore>,
|
||||
project: Model<Project>,
|
||||
store: Entity<ContextStore>,
|
||||
project: Entity<Project>,
|
||||
matches: Vec<ContextMetadata>,
|
||||
selected_index: usize,
|
||||
}
|
||||
|
@ -121,7 +123,7 @@ struct SavedContextPickerDelegate {
|
|||
impl EventEmitter<SavedContextPickerEvent> for Picker<SavedContextPickerDelegate> {}
|
||||
|
||||
impl SavedContextPickerDelegate {
|
||||
fn new(project: Model<Project>, store: Model<ContextStore>) -> Self {
|
||||
fn new(project: Entity<Project>, store: Entity<ContextStore>) -> Self {
|
||||
Self {
|
||||
project,
|
||||
store,
|
||||
|
@ -142,15 +144,25 @@ impl PickerDelegate for SavedContextPickerDelegate {
|
|||
self.selected_index
|
||||
}
|
||||
|
||||
fn set_selected_index(&mut self, ix: usize, _cx: &mut ViewContext<Picker<Self>>) {
|
||||
fn set_selected_index(
|
||||
&mut self,
|
||||
ix: usize,
|
||||
_window: &mut Window,
|
||||
_cx: &mut Context<Picker<Self>>,
|
||||
) {
|
||||
self.selected_index = ix;
|
||||
}
|
||||
|
||||
fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc<str> {
|
||||
fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc<str> {
|
||||
"Search...".into()
|
||||
}
|
||||
|
||||
fn update_matches(&mut self, query: String, cx: &mut ViewContext<Picker<Self>>) -> Task<()> {
|
||||
fn update_matches(
|
||||
&mut self,
|
||||
query: String,
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Picker<Self>>,
|
||||
) -> Task<()> {
|
||||
let search = self.store.read(cx).search(query, cx);
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let matches = search.await;
|
||||
|
@ -169,19 +181,20 @@ impl PickerDelegate for SavedContextPickerDelegate {
|
|||
})
|
||||
}
|
||||
|
||||
fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext<Picker<Self>>) {
|
||||
fn confirm(&mut self, _secondary: bool, _window: &mut Window, cx: &mut Context<Picker<Self>>) {
|
||||
if let Some(metadata) = self.matches.get(self.selected_index) {
|
||||
cx.emit(SavedContextPickerEvent::Confirmed(metadata.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
fn dismissed(&mut self, _cx: &mut ViewContext<Picker<Self>>) {}
|
||||
fn dismissed(&mut self, _window: &mut Window, _cx: &mut Context<Picker<Self>>) {}
|
||||
|
||||
fn render_match(
|
||||
&self,
|
||||
ix: usize,
|
||||
selected: bool,
|
||||
cx: &mut ViewContext<Picker<Self>>,
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Picker<Self>>,
|
||||
) -> Option<Self::ListItem> {
|
||||
let context = self.matches.get(ix)?;
|
||||
let item = match context {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
Context, ContextEvent, ContextId, ContextOperation, ContextVersion, SavedContext,
|
||||
AssistantContext, ContextEvent, ContextId, ContextOperation, ContextVersion, SavedContext,
|
||||
SavedContextMetadata,
|
||||
};
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
|
@ -14,7 +14,7 @@ use fs::Fs;
|
|||
use futures::StreamExt;
|
||||
use fuzzy::StringMatchCandidate;
|
||||
use gpui::{
|
||||
AppContext, AsyncAppContext, Context as _, EventEmitter, Model, ModelContext, Task, WeakModel,
|
||||
App, AppContext as _, AsyncAppContext, Context, Entity, EventEmitter, Task, WeakEntity,
|
||||
};
|
||||
use language::LanguageRegistry;
|
||||
use paths::contexts_dir;
|
||||
|
@ -50,7 +50,7 @@ pub struct RemoteContextMetadata {
|
|||
pub struct ContextStore {
|
||||
contexts: Vec<ContextHandle>,
|
||||
contexts_metadata: Vec<SavedContextMetadata>,
|
||||
context_server_manager: Model<ContextServerManager>,
|
||||
context_server_manager: Entity<ContextServerManager>,
|
||||
context_server_slash_command_ids: HashMap<Arc<str>, Vec<SlashCommandId>>,
|
||||
context_server_tool_ids: HashMap<Arc<str>, Vec<ToolId>>,
|
||||
host_contexts: Vec<RemoteContextMetadata>,
|
||||
|
@ -61,7 +61,7 @@ pub struct ContextStore {
|
|||
telemetry: Arc<Telemetry>,
|
||||
_watch_updates: Task<Option<()>>,
|
||||
client: Arc<Client>,
|
||||
project: Model<Project>,
|
||||
project: Entity<Project>,
|
||||
project_is_shared: bool,
|
||||
client_subscription: Option<client::Subscription>,
|
||||
_project_subscriptions: Vec<gpui::Subscription>,
|
||||
|
@ -75,19 +75,19 @@ pub enum ContextStoreEvent {
|
|||
impl EventEmitter<ContextStoreEvent> for ContextStore {}
|
||||
|
||||
enum ContextHandle {
|
||||
Weak(WeakModel<Context>),
|
||||
Strong(Model<Context>),
|
||||
Weak(WeakEntity<AssistantContext>),
|
||||
Strong(Entity<AssistantContext>),
|
||||
}
|
||||
|
||||
impl ContextHandle {
|
||||
fn upgrade(&self) -> Option<Model<Context>> {
|
||||
fn upgrade(&self) -> Option<Entity<AssistantContext>> {
|
||||
match self {
|
||||
ContextHandle::Weak(weak) => weak.upgrade(),
|
||||
ContextHandle::Strong(strong) => Some(strong.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn downgrade(&self) -> WeakModel<Context> {
|
||||
fn downgrade(&self) -> WeakEntity<AssistantContext> {
|
||||
match self {
|
||||
ContextHandle::Weak(weak) => weak.clone(),
|
||||
ContextHandle::Strong(strong) => strong.downgrade(),
|
||||
|
@ -97,12 +97,12 @@ impl ContextHandle {
|
|||
|
||||
impl ContextStore {
|
||||
pub fn new(
|
||||
project: Model<Project>,
|
||||
project: Entity<Project>,
|
||||
prompt_builder: Arc<PromptBuilder>,
|
||||
slash_commands: Arc<SlashCommandWorkingSet>,
|
||||
tools: Arc<ToolWorkingSet>,
|
||||
cx: &mut AppContext,
|
||||
) -> Task<Result<Model<Self>>> {
|
||||
cx: &mut App,
|
||||
) -> Task<Result<Entity<Self>>> {
|
||||
let fs = project.read(cx).fs().clone();
|
||||
let languages = project.read(cx).languages().clone();
|
||||
let telemetry = project.read(cx).client().telemetry().clone();
|
||||
|
@ -110,10 +110,10 @@ impl ContextStore {
|
|||
const CONTEXT_WATCH_DURATION: Duration = Duration::from_millis(100);
|
||||
let (mut events, _) = fs.watch(contexts_dir(), CONTEXT_WATCH_DURATION).await;
|
||||
|
||||
let this = cx.new_model(|cx: &mut ModelContext<Self>| {
|
||||
let this = cx.new(|cx: &mut Context<Self>| {
|
||||
let context_server_factory_registry =
|
||||
ContextServerFactoryRegistry::default_global(cx);
|
||||
let context_server_manager = cx.new_model(|cx| {
|
||||
let context_server_manager = cx.new(|cx| {
|
||||
ContextServerManager::new(context_server_factory_registry, project.clone(), cx)
|
||||
});
|
||||
let mut this = Self {
|
||||
|
@ -163,7 +163,7 @@ impl ContextStore {
|
|||
}
|
||||
|
||||
async fn handle_advertise_contexts(
|
||||
this: Model<Self>,
|
||||
this: Entity<Self>,
|
||||
envelope: TypedEnvelope<proto::AdvertiseContexts>,
|
||||
mut cx: AsyncAppContext,
|
||||
) -> Result<()> {
|
||||
|
@ -182,7 +182,7 @@ impl ContextStore {
|
|||
}
|
||||
|
||||
async fn handle_open_context(
|
||||
this: Model<Self>,
|
||||
this: Entity<Self>,
|
||||
envelope: TypedEnvelope<proto::OpenContext>,
|
||||
mut cx: AsyncAppContext,
|
||||
) -> Result<proto::OpenContextResponse> {
|
||||
|
@ -212,7 +212,7 @@ impl ContextStore {
|
|||
}
|
||||
|
||||
async fn handle_create_context(
|
||||
this: Model<Self>,
|
||||
this: Entity<Self>,
|
||||
_: TypedEnvelope<proto::CreateContext>,
|
||||
mut cx: AsyncAppContext,
|
||||
) -> Result<proto::CreateContextResponse> {
|
||||
|
@ -240,7 +240,7 @@ impl ContextStore {
|
|||
}
|
||||
|
||||
async fn handle_update_context(
|
||||
this: Model<Self>,
|
||||
this: Entity<Self>,
|
||||
envelope: TypedEnvelope<proto::UpdateContext>,
|
||||
mut cx: AsyncAppContext,
|
||||
) -> Result<()> {
|
||||
|
@ -256,7 +256,7 @@ impl ContextStore {
|
|||
}
|
||||
|
||||
async fn handle_synchronize_contexts(
|
||||
this: Model<Self>,
|
||||
this: Entity<Self>,
|
||||
envelope: TypedEnvelope<proto::SynchronizeContexts>,
|
||||
mut cx: AsyncAppContext,
|
||||
) -> Result<proto::SynchronizeContextsResponse> {
|
||||
|
@ -299,7 +299,7 @@ impl ContextStore {
|
|||
})?
|
||||
}
|
||||
|
||||
fn handle_project_changed(&mut self, _: Model<Project>, cx: &mut ModelContext<Self>) {
|
||||
fn handle_project_changed(&mut self, _: Entity<Project>, cx: &mut Context<Self>) {
|
||||
let is_shared = self.project.read(cx).is_shared();
|
||||
let was_shared = mem::replace(&mut self.project_is_shared, is_shared);
|
||||
if is_shared == was_shared {
|
||||
|
@ -320,7 +320,7 @@ impl ContextStore {
|
|||
.client
|
||||
.subscribe_to_entity(remote_id)
|
||||
.log_err()
|
||||
.map(|subscription| subscription.set_model(&cx.handle(), &mut cx.to_async()));
|
||||
.map(|subscription| subscription.set_model(&cx.model(), &mut cx.to_async()));
|
||||
self.advertise_contexts(cx);
|
||||
} else {
|
||||
self.client_subscription = None;
|
||||
|
@ -329,9 +329,9 @@ impl ContextStore {
|
|||
|
||||
fn handle_project_event(
|
||||
&mut self,
|
||||
_: Model<Project>,
|
||||
_: Entity<Project>,
|
||||
event: &project::Event,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
match event {
|
||||
project::Event::Reshared => {
|
||||
|
@ -361,9 +361,9 @@ impl ContextStore {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create(&mut self, cx: &mut ModelContext<Self>) -> Model<Context> {
|
||||
let context = cx.new_model(|cx| {
|
||||
Context::local(
|
||||
pub fn create(&mut self, cx: &mut Context<Self>) -> Entity<AssistantContext> {
|
||||
let context = cx.new(|cx| {
|
||||
AssistantContext::local(
|
||||
self.languages.clone(),
|
||||
Some(self.project.clone()),
|
||||
Some(self.telemetry.clone()),
|
||||
|
@ -379,8 +379,8 @@ impl ContextStore {
|
|||
|
||||
pub fn create_remote_context(
|
||||
&mut self,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Model<Context>>> {
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Entity<AssistantContext>>> {
|
||||
let project = self.project.read(cx);
|
||||
let Some(project_id) = project.remote_id() else {
|
||||
return Task::ready(Err(anyhow!("project was not remote")));
|
||||
|
@ -399,8 +399,8 @@ impl ContextStore {
|
|||
let response = request.await?;
|
||||
let context_id = ContextId::from_proto(response.context_id);
|
||||
let context_proto = response.context.context("invalid context")?;
|
||||
let context = cx.new_model(|cx| {
|
||||
Context::new(
|
||||
let context = cx.new(|cx| {
|
||||
AssistantContext::new(
|
||||
context_id.clone(),
|
||||
replica_id,
|
||||
capability,
|
||||
|
@ -439,8 +439,8 @@ impl ContextStore {
|
|||
pub fn open_local_context(
|
||||
&mut self,
|
||||
path: PathBuf,
|
||||
cx: &ModelContext<Self>,
|
||||
) -> Task<Result<Model<Context>>> {
|
||||
cx: &Context<Self>,
|
||||
) -> Task<Result<Entity<AssistantContext>>> {
|
||||
if let Some(existing_context) = self.loaded_context_for_path(&path, cx) {
|
||||
return Task::ready(Ok(existing_context));
|
||||
}
|
||||
|
@ -462,8 +462,8 @@ impl ContextStore {
|
|||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let saved_context = load.await?;
|
||||
let context = cx.new_model(|cx| {
|
||||
Context::deserialize(
|
||||
let context = cx.new(|cx| {
|
||||
AssistantContext::deserialize(
|
||||
saved_context,
|
||||
path.clone(),
|
||||
languages,
|
||||
|
@ -486,7 +486,7 @@ impl ContextStore {
|
|||
})
|
||||
}
|
||||
|
||||
fn loaded_context_for_path(&self, path: &Path, cx: &AppContext) -> Option<Model<Context>> {
|
||||
fn loaded_context_for_path(&self, path: &Path, cx: &App) -> Option<Entity<AssistantContext>> {
|
||||
self.contexts.iter().find_map(|context| {
|
||||
let context = context.upgrade()?;
|
||||
if context.read(cx).path() == Some(path) {
|
||||
|
@ -497,7 +497,11 @@ impl ContextStore {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn loaded_context_for_id(&self, id: &ContextId, cx: &AppContext) -> Option<Model<Context>> {
|
||||
pub fn loaded_context_for_id(
|
||||
&self,
|
||||
id: &ContextId,
|
||||
cx: &App,
|
||||
) -> Option<Entity<AssistantContext>> {
|
||||
self.contexts.iter().find_map(|context| {
|
||||
let context = context.upgrade()?;
|
||||
if context.read(cx).id() == id {
|
||||
|
@ -511,8 +515,8 @@ impl ContextStore {
|
|||
pub fn open_remote_context(
|
||||
&mut self,
|
||||
context_id: ContextId,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Model<Context>>> {
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<Entity<AssistantContext>>> {
|
||||
let project = self.project.read(cx);
|
||||
let Some(project_id) = project.remote_id() else {
|
||||
return Task::ready(Err(anyhow!("project was not remote")));
|
||||
|
@ -537,8 +541,8 @@ impl ContextStore {
|
|||
cx.spawn(|this, mut cx| async move {
|
||||
let response = request.await?;
|
||||
let context_proto = response.context.context("invalid context")?;
|
||||
let context = cx.new_model(|cx| {
|
||||
Context::new(
|
||||
let context = cx.new(|cx| {
|
||||
AssistantContext::new(
|
||||
context_id.clone(),
|
||||
replica_id,
|
||||
capability,
|
||||
|
@ -574,7 +578,7 @@ impl ContextStore {
|
|||
})
|
||||
}
|
||||
|
||||
fn register_context(&mut self, context: &Model<Context>, cx: &mut ModelContext<Self>) {
|
||||
fn register_context(&mut self, context: &Entity<AssistantContext>, cx: &mut Context<Self>) {
|
||||
let handle = if self.project_is_shared {
|
||||
ContextHandle::Strong(context.clone())
|
||||
} else {
|
||||
|
@ -587,9 +591,9 @@ impl ContextStore {
|
|||
|
||||
fn handle_context_event(
|
||||
&mut self,
|
||||
context: Model<Context>,
|
||||
context: Entity<AssistantContext>,
|
||||
event: &ContextEvent,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let Some(project_id) = self.project.read(cx).remote_id() else {
|
||||
return;
|
||||
|
@ -614,7 +618,7 @@ impl ContextStore {
|
|||
}
|
||||
}
|
||||
|
||||
fn advertise_contexts(&self, cx: &AppContext) {
|
||||
fn advertise_contexts(&self, cx: &App) {
|
||||
let Some(project_id) = self.project.read(cx).remote_id() else {
|
||||
return;
|
||||
};
|
||||
|
@ -648,7 +652,7 @@ impl ContextStore {
|
|||
.ok();
|
||||
}
|
||||
|
||||
fn synchronize_contexts(&mut self, cx: &mut ModelContext<Self>) {
|
||||
fn synchronize_contexts(&mut self, cx: &mut Context<Self>) {
|
||||
let Some(project_id) = self.project.read(cx).remote_id() else {
|
||||
return;
|
||||
};
|
||||
|
@ -703,7 +707,7 @@ impl ContextStore {
|
|||
.detach_and_log_err(cx);
|
||||
}
|
||||
|
||||
pub fn search(&self, query: String, cx: &AppContext) -> Task<Vec<SavedContextMetadata>> {
|
||||
pub fn search(&self, query: String, cx: &App) -> Task<Vec<SavedContextMetadata>> {
|
||||
let metadata = self.contexts_metadata.clone();
|
||||
let executor = cx.background_executor().clone();
|
||||
cx.background_executor().spawn(async move {
|
||||
|
@ -737,7 +741,7 @@ impl ContextStore {
|
|||
&self.host_contexts
|
||||
}
|
||||
|
||||
fn reload(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
|
||||
fn reload(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
|
||||
let fs = self.fs.clone();
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
fs.create_dir(contexts_dir()).await?;
|
||||
|
@ -786,7 +790,7 @@ impl ContextStore {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn restart_context_servers(&mut self, cx: &mut ModelContext<Self>) {
|
||||
pub fn restart_context_servers(&mut self, cx: &mut Context<Self>) {
|
||||
cx.update_model(
|
||||
&self.context_server_manager,
|
||||
|context_server_manager, cx| {
|
||||
|
@ -799,7 +803,7 @@ impl ContextStore {
|
|||
);
|
||||
}
|
||||
|
||||
fn register_context_server_handlers(&self, cx: &mut ModelContext<Self>) {
|
||||
fn register_context_server_handlers(&self, cx: &mut Context<Self>) {
|
||||
cx.subscribe(
|
||||
&self.context_server_manager.clone(),
|
||||
Self::handle_context_server_event,
|
||||
|
@ -809,9 +813,9 @@ impl ContextStore {
|
|||
|
||||
fn handle_context_server_event(
|
||||
&mut self,
|
||||
context_server_manager: Model<ContextServerManager>,
|
||||
context_server_manager: Entity<ContextServerManager>,
|
||||
event: &context_server::manager::Event,
|
||||
cx: &mut ModelContext<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let slash_command_working_set = self.slash_commands.clone();
|
||||
let tool_working_set = self.tools.clone();
|
||||
|
|
|
@ -2,7 +2,7 @@ use anyhow::{anyhow, Context as _, Result};
|
|||
use collections::HashMap;
|
||||
use editor::ProposedChangesEditor;
|
||||
use futures::{future, TryFutureExt as _};
|
||||
use gpui::{AppContext, AsyncAppContext, Model, SharedString};
|
||||
use gpui::{App, AsyncAppContext, Entity, SharedString};
|
||||
use language::{AutoindentMode, Buffer, BufferSnapshot};
|
||||
use project::{Project, ProjectPath};
|
||||
use std::{cmp, ops::Range, path::Path, sync::Arc};
|
||||
|
@ -56,7 +56,7 @@ pub enum AssistantEditKind {
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ResolvedPatch {
|
||||
pub edit_groups: HashMap<Model<Buffer>, Vec<ResolvedEditGroup>>,
|
||||
pub edit_groups: HashMap<Entity<Buffer>, Vec<ResolvedEditGroup>>,
|
||||
pub errors: Vec<AssistantPatchResolutionError>,
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ impl SearchMatrix {
|
|||
}
|
||||
|
||||
impl ResolvedPatch {
|
||||
pub fn apply(&self, editor: &ProposedChangesEditor, cx: &mut AppContext) {
|
||||
pub fn apply(&self, editor: &ProposedChangesEditor, cx: &mut App) {
|
||||
for (buffer, groups) in &self.edit_groups {
|
||||
let branch = editor.branch_buffer_for_base(buffer).unwrap();
|
||||
Self::apply_edit_groups(groups, &branch, cx);
|
||||
|
@ -129,11 +129,7 @@ impl ResolvedPatch {
|
|||
editor.recalculate_all_buffer_diffs();
|
||||
}
|
||||
|
||||
fn apply_edit_groups(
|
||||
groups: &Vec<ResolvedEditGroup>,
|
||||
buffer: &Model<Buffer>,
|
||||
cx: &mut AppContext,
|
||||
) {
|
||||
fn apply_edit_groups(groups: &Vec<ResolvedEditGroup>, buffer: &Entity<Buffer>, cx: &mut App) {
|
||||
let mut edits = Vec::new();
|
||||
for group in groups {
|
||||
for suggestion in &group.edits {
|
||||
|
@ -232,9 +228,9 @@ impl AssistantEdit {
|
|||
|
||||
pub async fn resolve(
|
||||
&self,
|
||||
project: Model<Project>,
|
||||
project: Entity<Project>,
|
||||
mut cx: AsyncAppContext,
|
||||
) -> Result<(Model<Buffer>, ResolvedEdit)> {
|
||||
) -> Result<(Entity<Buffer>, ResolvedEdit)> {
|
||||
let path = self.path.clone();
|
||||
let kind = self.kind.clone();
|
||||
let buffer = project
|
||||
|
@ -427,7 +423,7 @@ impl AssistantEditKind {
|
|||
impl AssistantPatch {
|
||||
pub async fn resolve(
|
||||
&self,
|
||||
project: Model<Project>,
|
||||
project: Entity<Project>,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> ResolvedPatch {
|
||||
let mut resolve_tasks = Vec::new();
|
||||
|
@ -555,7 +551,7 @@ impl Eq for AssistantPatch {}
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use gpui::{AppContext, Context};
|
||||
use gpui::{App, AppContext as _};
|
||||
use language::{
|
||||
language_settings::AllLanguageSettings, Language, LanguageConfig, LanguageMatcher,
|
||||
};
|
||||
|
@ -565,7 +561,7 @@ mod tests {
|
|||
use util::test::{generate_marked_text, marked_text_ranges};
|
||||
|
||||
#[gpui::test]
|
||||
fn test_resolve_location(cx: &mut AppContext) {
|
||||
fn test_resolve_location(cx: &mut App) {
|
||||
assert_location_resolution(
|
||||
concat!(
|
||||
" Lorem\n",
|
||||
|
@ -636,7 +632,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_resolve_edits(cx: &mut AppContext) {
|
||||
fn test_resolve_edits(cx: &mut App) {
|
||||
init_test(cx);
|
||||
|
||||
assert_edits(
|
||||
|
@ -902,7 +898,7 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
fn init_test(cx: &mut AppContext) {
|
||||
fn init_test(cx: &mut App) {
|
||||
let settings_store = SettingsStore::test(cx);
|
||||
cx.set_global(settings_store);
|
||||
language::init(cx);
|
||||
|
@ -912,13 +908,9 @@ mod tests {
|
|||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_location_resolution(
|
||||
text_with_expected_range: &str,
|
||||
query: &str,
|
||||
cx: &mut AppContext,
|
||||
) {
|
||||
fn assert_location_resolution(text_with_expected_range: &str, query: &str, cx: &mut App) {
|
||||
let (text, _) = marked_text_ranges(text_with_expected_range, false);
|
||||
let buffer = cx.new_model(|cx| Buffer::local(text.clone(), cx));
|
||||
let buffer = cx.new(|cx| Buffer::local(text.clone(), cx));
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
let range = AssistantEditKind::resolve_location(&snapshot, query).to_offset(&snapshot);
|
||||
let text_with_actual_range = generate_marked_text(&text, &[range], false);
|
||||
|
@ -930,10 +922,10 @@ mod tests {
|
|||
old_text: String,
|
||||
edits: Vec<AssistantEditKind>,
|
||||
new_text: String,
|
||||
cx: &mut AppContext,
|
||||
cx: &mut App,
|
||||
) {
|
||||
let buffer =
|
||||
cx.new_model(|cx| Buffer::local(old_text, cx).with_language(Arc::new(rust_lang()), cx));
|
||||
cx.new(|cx| Buffer::local(old_text, cx).with_language(Arc::new(rust_lang()), cx));
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
let resolved_edits = edits
|
||||
.into_iter()
|
||||
|
|
|
@ -4,7 +4,7 @@ pub use assistant_slash_command::SlashCommand;
|
|||
use assistant_slash_command::{AfterCompletion, SlashCommandLine, SlashCommandWorkingSet};
|
||||
use editor::{CompletionProvider, Editor};
|
||||
use fuzzy::{match_strings, StringMatchCandidate};
|
||||
use gpui::{Model, Task, ViewContext, WeakView, WindowContext};
|
||||
use gpui::{App, Context, Entity, Task, WeakEntity, Window};
|
||||
use language::{Anchor, Buffer, Documentation, LanguageServerId, ToPoint};
|
||||
use parking_lot::Mutex;
|
||||
use project::CompletionIntent;
|
||||
|
@ -23,15 +23,15 @@ use workspace::Workspace;
|
|||
pub struct SlashCommandCompletionProvider {
|
||||
cancel_flag: Mutex<Arc<AtomicBool>>,
|
||||
slash_commands: Arc<SlashCommandWorkingSet>,
|
||||
editor: Option<WeakView<ContextEditor>>,
|
||||
workspace: Option<WeakView<Workspace>>,
|
||||
editor: Option<WeakEntity<ContextEditor>>,
|
||||
workspace: Option<WeakEntity<Workspace>>,
|
||||
}
|
||||
|
||||
impl SlashCommandCompletionProvider {
|
||||
pub fn new(
|
||||
slash_commands: Arc<SlashCommandWorkingSet>,
|
||||
editor: Option<WeakView<ContextEditor>>,
|
||||
workspace: Option<WeakView<Workspace>>,
|
||||
editor: Option<WeakEntity<ContextEditor>>,
|
||||
workspace: Option<WeakEntity<Workspace>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
cancel_flag: Mutex::new(Arc::new(AtomicBool::new(false))),
|
||||
|
@ -46,7 +46,8 @@ impl SlashCommandCompletionProvider {
|
|||
command_name: &str,
|
||||
command_range: Range<Anchor>,
|
||||
name_range: Range<Anchor>,
|
||||
cx: &mut WindowContext,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<Vec<project::Completion>>> {
|
||||
let slash_commands = self.slash_commands.clone();
|
||||
let candidates = slash_commands
|
||||
|
@ -58,7 +59,7 @@ impl SlashCommandCompletionProvider {
|
|||
let command_name = command_name.to_string();
|
||||
let editor = self.editor.clone();
|
||||
let workspace = self.workspace.clone();
|
||||
cx.spawn(|mut cx| async move {
|
||||
window.spawn(cx, |mut cx| async move {
|
||||
let matches = match_strings(
|
||||
&candidates,
|
||||
&command_name,
|
||||
|
@ -69,7 +70,7 @@ impl SlashCommandCompletionProvider {
|
|||
)
|
||||
.await;
|
||||
|
||||
cx.update(|cx| {
|
||||
cx.update(|_, cx| {
|
||||
matches
|
||||
.into_iter()
|
||||
.filter_map(|mat| {
|
||||
|
@ -91,28 +92,31 @@ impl SlashCommandCompletionProvider {
|
|||
let editor = editor.clone();
|
||||
let workspace = workspace.clone();
|
||||
Arc::new(
|
||||
move |intent: CompletionIntent, cx: &mut WindowContext| {
|
||||
if !requires_argument
|
||||
&& (!accepts_arguments || intent.is_complete())
|
||||
{
|
||||
editor
|
||||
.update(cx, |editor, cx| {
|
||||
editor.run_command(
|
||||
command_range.clone(),
|
||||
&command_name,
|
||||
&[],
|
||||
true,
|
||||
workspace.clone(),
|
||||
cx,
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
false
|
||||
} else {
|
||||
requires_argument || accepts_arguments
|
||||
}
|
||||
},
|
||||
) as Arc<_>
|
||||
move |intent: CompletionIntent,
|
||||
window: &mut Window,
|
||||
cx: &mut App| {
|
||||
if !requires_argument
|
||||
&& (!accepts_arguments || intent.is_complete())
|
||||
{
|
||||
editor
|
||||
.update(cx, |editor, cx| {
|
||||
editor.run_command(
|
||||
command_range.clone(),
|
||||
&command_name,
|
||||
&[],
|
||||
true,
|
||||
workspace.clone(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
false
|
||||
} else {
|
||||
requires_argument || accepts_arguments
|
||||
}
|
||||
},
|
||||
) as Arc<_>
|
||||
});
|
||||
Some(project::Completion {
|
||||
old_range: name_range.clone(),
|
||||
|
@ -130,6 +134,7 @@ impl SlashCommandCompletionProvider {
|
|||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn complete_command_argument(
|
||||
&self,
|
||||
command_name: &str,
|
||||
|
@ -137,7 +142,8 @@ impl SlashCommandCompletionProvider {
|
|||
command_range: Range<Anchor>,
|
||||
argument_range: Range<Anchor>,
|
||||
last_argument_range: Range<Anchor>,
|
||||
cx: &mut WindowContext,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<Vec<project::Completion>>> {
|
||||
let new_cancel_flag = Arc::new(AtomicBool::new(false));
|
||||
let mut flag = self.cancel_flag.lock();
|
||||
|
@ -148,6 +154,7 @@ impl SlashCommandCompletionProvider {
|
|||
arguments,
|
||||
new_cancel_flag.clone(),
|
||||
self.workspace.clone(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
let command_name: Arc<str> = command_name.into();
|
||||
|
@ -175,7 +182,9 @@ impl SlashCommandCompletionProvider {
|
|||
|
||||
let command_range = command_range.clone();
|
||||
let command_name = command_name.clone();
|
||||
move |intent: CompletionIntent, cx: &mut WindowContext| {
|
||||
move |intent: CompletionIntent,
|
||||
window: &mut Window,
|
||||
cx: &mut App| {
|
||||
if new_argument.after_completion.run()
|
||||
|| intent.is_complete()
|
||||
{
|
||||
|
@ -187,6 +196,7 @@ impl SlashCommandCompletionProvider {
|
|||
&completed_arguments,
|
||||
true,
|
||||
workspace.clone(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
})
|
||||
|
@ -230,10 +240,11 @@ impl SlashCommandCompletionProvider {
|
|||
impl CompletionProvider for SlashCommandCompletionProvider {
|
||||
fn completions(
|
||||
&self,
|
||||
buffer: &Model<Buffer>,
|
||||
buffer: &Entity<Buffer>,
|
||||
buffer_position: Anchor,
|
||||
_: editor::CompletionContext,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Editor>,
|
||||
) -> Task<Result<Vec<project::Completion>>> {
|
||||
let Some((name, arguments, command_range, last_argument_range)) =
|
||||
buffer.update(cx, |buffer, _cx| {
|
||||
|
@ -288,30 +299,31 @@ impl CompletionProvider for SlashCommandCompletionProvider {
|
|||
command_range,
|
||||
argument_range,
|
||||
last_argument_range,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
} else {
|
||||
self.complete_command_name(&name, command_range, last_argument_range, cx)
|
||||
self.complete_command_name(&name, command_range, last_argument_range, window, cx)
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_completions(
|
||||
&self,
|
||||
_: Model<Buffer>,
|
||||
_: Entity<Buffer>,
|
||||
_: Vec<usize>,
|
||||
_: Rc<RefCell<Box<[project::Completion]>>>,
|
||||
_: &mut ViewContext<Editor>,
|
||||
_: &mut Context<Editor>,
|
||||
) -> Task<Result<bool>> {
|
||||
Task::ready(Ok(true))
|
||||
}
|
||||
|
||||
fn is_completion_trigger(
|
||||
&self,
|
||||
buffer: &Model<Buffer>,
|
||||
buffer: &Entity<Buffer>,
|
||||
position: language::Anchor,
|
||||
_text: &str,
|
||||
_trigger_in_words: bool,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
cx: &mut Context<Editor>,
|
||||
) -> bool {
|
||||
let buffer = buffer.read(cx);
|
||||
let position = position.to_point(buffer);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use assistant_slash_command::SlashCommandWorkingSet;
|
||||
use gpui::{AnyElement, DismissEvent, SharedString, Task, WeakView};
|
||||
use gpui::{AnyElement, DismissEvent, SharedString, Task, WeakEntity};
|
||||
use picker::{Picker, PickerDelegate, PickerEditorPosition};
|
||||
use ui::{prelude::*, ListItem, ListItemSpacing, PopoverMenu, PopoverTrigger, Tooltip};
|
||||
|
||||
|
@ -10,7 +10,7 @@ use crate::context_editor::ContextEditor;
|
|||
#[derive(IntoElement)]
|
||||
pub(super) struct SlashCommandSelector<T: PopoverTrigger> {
|
||||
working_set: Arc<SlashCommandWorkingSet>,
|
||||
active_context_editor: WeakView<ContextEditor>,
|
||||
active_context_editor: WeakEntity<ContextEditor>,
|
||||
trigger: T,
|
||||
}
|
||||
|
||||
|
@ -27,8 +27,8 @@ enum SlashCommandEntry {
|
|||
Info(SlashCommandInfo),
|
||||
Advert {
|
||||
name: SharedString,
|
||||
renderer: fn(&mut WindowContext) -> AnyElement,
|
||||
on_confirm: fn(&mut WindowContext),
|
||||
renderer: fn(&mut Window, &mut App) -> AnyElement,
|
||||
on_confirm: fn(&mut Window, &mut App),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -44,14 +44,14 @@ impl AsRef<str> for SlashCommandEntry {
|
|||
pub(crate) struct SlashCommandDelegate {
|
||||
all_commands: Vec<SlashCommandEntry>,
|
||||
filtered_commands: Vec<SlashCommandEntry>,
|
||||
active_context_editor: WeakView<ContextEditor>,
|
||||
active_context_editor: WeakEntity<ContextEditor>,
|
||||
selected_index: usize,
|
||||
}
|
||||
|
||||
impl<T: PopoverTrigger> SlashCommandSelector<T> {
|
||||
pub(crate) fn new(
|
||||
working_set: Arc<SlashCommandWorkingSet>,
|
||||
active_context_editor: WeakView<ContextEditor>,
|
||||
active_context_editor: WeakEntity<ContextEditor>,
|
||||
trigger: T,
|
||||
) -> Self {
|
||||
SlashCommandSelector {
|
||||
|
@ -73,18 +73,23 @@ impl PickerDelegate for SlashCommandDelegate {
|
|||
self.selected_index
|
||||
}
|
||||
|
||||
fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext<Picker<Self>>) {
|
||||
fn set_selected_index(&mut self, ix: usize, _: &mut Window, cx: &mut Context<Picker<Self>>) {
|
||||
self.selected_index = ix.min(self.filtered_commands.len().saturating_sub(1));
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc<str> {
|
||||
fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc<str> {
|
||||
"Select a command...".into()
|
||||
}
|
||||
|
||||
fn update_matches(&mut self, query: String, cx: &mut ViewContext<Picker<Self>>) -> Task<()> {
|
||||
fn update_matches(
|
||||
&mut self,
|
||||
query: String,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Picker<Self>>,
|
||||
) -> Task<()> {
|
||||
let all_commands = self.all_commands.clone();
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
cx.spawn_in(window, |this, mut cx| async move {
|
||||
let filtered_commands = cx
|
||||
.background_executor()
|
||||
.spawn(async move {
|
||||
|
@ -104,9 +109,9 @@ impl PickerDelegate for SlashCommandDelegate {
|
|||
})
|
||||
.await;
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.update_in(&mut cx, |this, window, cx| {
|
||||
this.delegate.filtered_commands = filtered_commands;
|
||||
this.delegate.set_selected_index(0, cx);
|
||||
this.delegate.set_selected_index(0, window, cx);
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
|
@ -139,25 +144,25 @@ impl PickerDelegate for SlashCommandDelegate {
|
|||
ret
|
||||
}
|
||||
|
||||
fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext<Picker<Self>>) {
|
||||
fn confirm(&mut self, _secondary: bool, window: &mut Window, cx: &mut Context<Picker<Self>>) {
|
||||
if let Some(command) = self.filtered_commands.get(self.selected_index) {
|
||||
match command {
|
||||
SlashCommandEntry::Info(info) => {
|
||||
self.active_context_editor
|
||||
.update(cx, |context_editor, cx| {
|
||||
context_editor.insert_command(&info.name, cx)
|
||||
context_editor.insert_command(&info.name, window, cx)
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
SlashCommandEntry::Advert { on_confirm, .. } => {
|
||||
on_confirm(cx);
|
||||
on_confirm(window, cx);
|
||||
}
|
||||
}
|
||||
cx.emit(DismissEvent);
|
||||
}
|
||||
}
|
||||
|
||||
fn dismissed(&mut self, _cx: &mut ViewContext<Picker<Self>>) {}
|
||||
fn dismissed(&mut self, _window: &mut Window, _cx: &mut Context<Picker<Self>>) {}
|
||||
|
||||
fn editor_position(&self) -> PickerEditorPosition {
|
||||
PickerEditorPosition::End
|
||||
|
@ -167,7 +172,8 @@ impl PickerDelegate for SlashCommandDelegate {
|
|||
&self,
|
||||
ix: usize,
|
||||
selected: bool,
|
||||
cx: &mut ViewContext<Picker<Self>>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Picker<Self>>,
|
||||
) -> Option<Self::ListItem> {
|
||||
let command_info = self.filtered_commands.get(ix)?;
|
||||
|
||||
|
@ -179,7 +185,7 @@ impl PickerDelegate for SlashCommandDelegate {
|
|||
.toggle_state(selected)
|
||||
.tooltip({
|
||||
let description = info.description.clone();
|
||||
move |cx| cx.new_view(|_| Tooltip::new(description.clone())).into()
|
||||
move |_, cx| cx.new(|_| Tooltip::new(description.clone())).into()
|
||||
})
|
||||
.child(
|
||||
v_flex()
|
||||
|
@ -229,14 +235,14 @@ impl PickerDelegate for SlashCommandDelegate {
|
|||
.inset(true)
|
||||
.spacing(ListItemSpacing::Dense)
|
||||
.toggle_state(selected)
|
||||
.child(renderer(cx)),
|
||||
.child(renderer(window, cx)),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PopoverTrigger> RenderOnce for SlashCommandSelector<T> {
|
||||
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let all_models = self
|
||||
.working_set
|
||||
.featured_command_names(cx)
|
||||
|
@ -259,7 +265,7 @@ impl<T: PopoverTrigger> RenderOnce for SlashCommandSelector<T> {
|
|||
})
|
||||
.chain([SlashCommandEntry::Advert {
|
||||
name: "create-your-command".into(),
|
||||
renderer: |cx| {
|
||||
renderer: |_, cx| {
|
||||
v_flex()
|
||||
.w_full()
|
||||
.child(
|
||||
|
@ -293,7 +299,7 @@ impl<T: PopoverTrigger> RenderOnce for SlashCommandSelector<T> {
|
|||
)
|
||||
.into_any_element()
|
||||
},
|
||||
on_confirm: |cx| cx.open_url("https://zed.dev/docs/extensions/slash-commands"),
|
||||
on_confirm: |_, cx| cx.open_url("https://zed.dev/docs/extensions/slash-commands"),
|
||||
}])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
@ -304,8 +310,9 @@ impl<T: PopoverTrigger> RenderOnce for SlashCommandSelector<T> {
|
|||
selected_index: 0,
|
||||
};
|
||||
|
||||
let picker_view = cx.new_view(|cx| {
|
||||
let picker = Picker::uniform_list(delegate, cx).max_height(Some(rems(20.).into()));
|
||||
let picker_view = cx.new(|cx| {
|
||||
let picker =
|
||||
Picker::uniform_list(delegate, window, cx).max_height(Some(rems(20.).into()));
|
||||
picker
|
||||
});
|
||||
|
||||
|
@ -314,7 +321,7 @@ impl<T: PopoverTrigger> RenderOnce for SlashCommandSelector<T> {
|
|||
.update(cx, |this, _| this.slash_menu_handle.clone())
|
||||
.ok();
|
||||
PopoverMenu::new("model-switcher")
|
||||
.menu(move |_cx| Some(picker_view.clone()))
|
||||
.menu(move |_window, _cx| Some(picker_view.clone()))
|
||||
.trigger(self.trigger)
|
||||
.attach(gpui::Corner::TopLeft)
|
||||
.anchor(gpui::Corner::BottomLeft)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue