diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index 3d8775efaf..7ec19ef70e 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -17,7 +17,9 @@ use client::telemetry::Telemetry; use collections::{BTreeSet, HashMap, HashSet}; use editor::{ actions::{FoldAt, MoveToEndOfLine, Newline, ShowCompletions, UnfoldAt}, - display_map::{BlockDisposition, BlockId, BlockProperties, BlockStyle, Crease, ToDisplayPoint}, + display_map::{ + BlockDisposition, BlockId, BlockProperties, BlockStyle, Crease, RenderBlock, ToDisplayPoint, + }, scroll::{Autoscroll, AutoscrollStrategy}, Anchor, Editor, EditorEvent, RowExt, ToOffset as _, ToPoint, }; @@ -2200,6 +2202,7 @@ pub struct ContextEditor { blocks: HashSet, scroll_position: Option, pending_slash_command_creases: HashMap, CreaseId>, + pending_slash_command_blocks: HashMap, BlockId>, _subscriptions: Vec, } @@ -2273,6 +2276,7 @@ impl ContextEditor { fs, workspace: workspace.downgrade(), pending_slash_command_creases: HashMap::default(), + pending_slash_command_blocks: HashMap::default(), _subscriptions, }; this.update_message_headers(cx); @@ -2534,7 +2538,8 @@ impl ContextEditor { ContextEvent::PendingSlashCommandsUpdated { removed, updated } => { self.editor.update(cx, |editor, cx| { let buffer = editor.buffer().read(cx).snapshot(cx); - let excerpt_id = *buffer.as_singleton().unwrap().0; + let (excerpt_id, buffer_id, _) = buffer.as_singleton().unwrap(); + let excerpt_id = *excerpt_id; editor.remove_creases( removed @@ -2543,6 +2548,16 @@ impl ContextEditor { cx, ); + editor.remove_blocks( + HashSet::from_iter( + removed.iter().filter_map(|range| { + self.pending_slash_command_blocks.remove(range) + }), + ), + None, + cx, + ); + let crease_ids = editor.insert_creases( updated.iter().map(|command| { let workspace = self.workspace.clone(); @@ -2575,7 +2590,7 @@ impl ContextEditor { move |row, _, _, _cx: &mut WindowContext| { render_pending_slash_command_gutter_decoration( row, - command.status.clone(), + &command.status, confirm_command.clone(), ) } @@ -2609,12 +2624,43 @@ impl ContextEditor { cx, ); + let block_ids = editor.insert_blocks( + updated + .iter() + .filter_map(|command| match &command.status { + PendingSlashCommandStatus::Error(error) => { + Some((command, error.clone())) + } + _ => None, + }) + .map(|(command, error_message)| BlockProperties { + style: BlockStyle::Fixed, + position: Anchor { + buffer_id: Some(buffer_id), + excerpt_id, + text_anchor: command.source_range.start, + }, + height: 1, + disposition: BlockDisposition::Below, + render: slash_command_error_block_renderer(error_message), + }), + None, + cx, + ); + self.pending_slash_command_creases.extend( updated .iter() .map(|command| command.source_range.clone()) .zip(crease_ids), ); + + self.pending_slash_command_blocks.extend( + updated + .iter() + .map(|command| command.source_range.clone()) + .zip(block_ids), + ); }) } ContextEvent::SlashCommandFinished { @@ -3204,7 +3250,7 @@ fn render_slash_command_output_toggle( fn render_pending_slash_command_gutter_decoration( row: MultiBufferRow, - status: PendingSlashCommandStatus, + status: &PendingSlashCommandStatus, confirm_command: Arc, ) -> AnyElement { let mut icon = IconButton::new( @@ -3222,11 +3268,7 @@ fn render_pending_slash_command_gutter_decoration( PendingSlashCommandStatus::Running { .. } => { icon = icon.selected(true); } - PendingSlashCommandStatus::Error(error) => { - icon = icon - .icon_color(Color::Error) - .tooltip(move |cx| Tooltip::text(format!("error: {error}"), cx)); - } + PendingSlashCommandStatus::Error(_) => icon = icon.icon_color(Color::Error), } icon.into_any_element() @@ -3277,6 +3319,19 @@ fn make_lsp_adapter_delegate( }) } +fn slash_command_error_block_renderer(message: String) -> RenderBlock { + Box::new(move |_| { + div() + .pl_6() + .child( + Label::new(format!("error: {}", message)) + .single_line() + .color(Color::Error), + ) + .into_any() + }) +} + #[cfg(test)] mod tests { use super::*;