diff --git a/crates/editor/src/actions.rs b/crates/editor/src/actions.rs index 1002df6ad0..a3fe74c3c2 100644 --- a/crates/editor/src/actions.rs +++ b/crates/editor/src/actions.rs @@ -52,16 +52,11 @@ pub struct SelectToEndOfLine { #[derive(PartialEq, Clone, Deserialize, Default)] pub struct ToggleCodeActions { + // Display row from which the action was deployed. #[serde(default)] pub deployed_from_indicator: Option, } -#[derive(PartialEq, Clone, Deserialize, Default)] -pub struct ToggleTestRunner { - #[serde(default)] - pub deployed_from_row: Option, -} - #[derive(PartialEq, Clone, Deserialize, Default)] pub struct ConfirmCompletion { #[serde(default)] diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 4e457234c4..7e7b3dcd97 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -504,7 +504,7 @@ pub struct Editor { >, last_bounds: Option>, expect_bounds_change: Option>, - tasks: HashMap, + tasks: HashMap<(BufferId, u32), (usize, RunnableTasks)>, tasks_update_task: Option>, } @@ -3839,7 +3839,7 @@ impl Editor { } } drop(context_menu); - + let snapshot = self.snapshot(cx); let deployed_from_indicator = action.deployed_from_indicator; let mut task = self.code_actions_task.take(); let action = action.clone(); @@ -3851,11 +3851,24 @@ impl Editor { let spawned_test_task = this.update(&mut cx, |this, cx| { if this.focus_handle.is_focused(cx) { - let buffer_row = action + let display_row = action .deployed_from_indicator + .map(|row| { + DisplayPoint::new(row, 0) + .to_point(&snapshot.display_snapshot) + .row + }) .unwrap_or_else(|| this.selections.newest::(cx).head().row); - let tasks = this.tasks.get(&buffer_row).map(|t| Arc::new(t.to_owned())); - let (location, code_actions) = this + let (buffer, buffer_row) = snapshot + .buffer_snapshot + .buffer_line_for_row(display_row) + .and_then(|(buffer_snapshot, range)| { + this.buffer + .read(cx) + .buffer(buffer_snapshot.remote_id()) + .map(|buffer| (buffer, range.start.row)) + })?; + let (_, code_actions) = this .available_code_actions .clone() .and_then(|(location, code_actions)| { @@ -3869,25 +3882,20 @@ impl Editor { } }) .unzip(); + let buffer_id = buffer.read(cx).remote_id(); + let tasks = this + .tasks + .get(&(buffer_id, buffer_row)) + .map(|t| Arc::new(t.to_owned())); if tasks.is_none() && code_actions.is_none() { return None; } - let buffer = location.map(|location| location.buffer).or_else(|| { - let snapshot = this.snapshot(cx); - let (buffer_snapshot, _) = - snapshot.buffer_snapshot.buffer_line_for_row(buffer_row)?; - let buffer_id = buffer_snapshot.remote_id(); - this.buffer().read(cx).buffer(buffer_id) - }); - let Some(buffer) = buffer else { - return None; - }; this.completion_tasks.clear(); this.discard_inline_completion(cx); let task_context = tasks.as_ref().zip(this.workspace.clone()).and_then( |(tasks, (workspace, _))| { - let position = Point::new(buffer_row, tasks.column); + let position = Point::new(buffer_row, tasks.1.column); let range_start = buffer.read(cx).anchor_at(position, Bias::Right); let location = Location { buffer: buffer.clone(), @@ -3906,6 +3914,7 @@ impl Editor { .map(|(tasks, task_context)| { Arc::new(ResolvedTasks { templates: tasks + .1 .templates .iter() .filter_map(|(kind, template)| { @@ -3914,7 +3923,7 @@ impl Editor { .map(|task| (kind.clone(), task)) }) .collect(), - position: Point::new(buffer_row, tasks.column), + position: Point::new(buffer_row, tasks.1.column), }) }); let spawn_straight_away = tasks @@ -4505,8 +4514,8 @@ impl Editor { self.tasks.clear() } - fn insert_tasks(&mut self, row: u32, tasks: RunnableTasks) { - if let Some(_) = self.tasks.insert(row, tasks) { + fn insert_tasks(&mut self, key: (BufferId, u32), value: (usize, RunnableTasks)) { + if let Some(_) = self.tasks.insert(key, value) { // This case should hopefully be rare, but just in case... log::error!("multiple different run targets found on a single line, only the last target will be rendered") } @@ -7726,8 +7735,8 @@ impl Editor { this.update(&mut cx, |this, _| { this.clear_tasks(); - for (row, tasks) in rows { - this.insert_tasks(row, tasks); + for (key, value) in rows { + this.insert_tasks(key, value); } }) .ok(); @@ -7736,19 +7745,19 @@ impl Editor { fn fetch_runnable_ranges( snapshot: &DisplaySnapshot, range: Range, - ) -> Vec<(Range, Runnable)> { + ) -> Vec<(BufferId, Range, Runnable)> { snapshot.buffer_snapshot.runnable_ranges(range).collect() } fn runnable_rows( project: Model, snapshot: DisplaySnapshot, - runnable_ranges: Vec<(Range, Runnable)>, + runnable_ranges: Vec<(BufferId, Range, Runnable)>, mut cx: AsyncWindowContext, - ) -> Vec<(u32, RunnableTasks)> { + ) -> Vec<((BufferId, u32), (usize, RunnableTasks))> { runnable_ranges .into_iter() - .filter_map(|(multi_buffer_range, mut runnable)| { + .filter_map(|(buffer_id, multi_buffer_range, mut runnable)| { let (tasks, _) = cx .update(|cx| Self::resolve_runnable(project.clone(), &mut runnable, cx)) .ok()?; @@ -7756,12 +7765,21 @@ impl Editor { return None; } let point = multi_buffer_range.start.to_point(&snapshot.buffer_snapshot); + let row = snapshot + .buffer_snapshot + .buffer_line_for_row(point.row)? + .1 + .start + .row; Some(( - point.row, - RunnableTasks { - templates: tasks, - column: point.column, - }, + (buffer_id, row), + ( + multi_buffer_range.start, + RunnableTasks { + templates: tasks, + column: point.column, + }, + ), )) }) .collect() @@ -10102,6 +10120,7 @@ impl Editor { predecessor, excerpts, } => { + self.tasks_update_task = Some(self.refresh_runnables(cx)); cx.emit(EditorEvent::ExcerptsAdded { buffer: buffer.clone(), predecessor: *predecessor, diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 7a4aa2222b..052c40a6dd 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1406,20 +1406,24 @@ impl EditorElement { }; editor .tasks - .keys() - .filter_map(|row| { + .iter() + .filter_map(|((_, row), (multibuffer_offset, _))| { if snapshot.is_line_folded(*row) { return None; } + let display_row = snapshot + .buffer_snapshot + .offset_to_point(*multibuffer_offset) + .to_display_point(&snapshot.display_snapshot) + .row(); + let button = editor.render_run_indicator( &self.style, Some(*row) == active_task_indicator_row, - *row, + display_row, cx, ); - let display_row = Point::new(*row, 0) - .to_display_point(&snapshot.display_snapshot) - .row(); + let button = prepaint_gutter_button( button, display_row, @@ -4035,20 +4039,25 @@ impl Element for EditorElement { if gutter_settings.code_actions { let newest_selection_point = newest_selection_head.to_point(&snapshot.display_snapshot); - let has_test_indicator = self - .editor - .read(cx) - .tasks - .contains_key(&newest_selection_point.row); - if !has_test_indicator { - code_actions_indicator = self.layout_code_actions_indicator( - line_height, - newest_selection_head, - scroll_pixel_position, - &gutter_dimensions, - &gutter_hitbox, - cx, - ); + let buffer = snapshot + .buffer_snapshot + .buffer_line_for_row(newest_selection_point.row); + if let Some((buffer, range)) = buffer { + let buffer_id = buffer.remote_id(); + let row = range.start.row; + let has_test_indicator = + self.editor.read(cx).tasks.contains_key(&(buffer_id, row)); + + if !has_test_indicator { + code_actions_indicator = self.layout_code_actions_indicator( + line_height, + newest_selection_head, + scroll_pixel_position, + &gutter_dimensions, + &gutter_hitbox, + cx, + ); + } } } } diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index 5d6a69b901..9f8c8410eb 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -3168,7 +3168,7 @@ impl MultiBufferSnapshot { pub fn runnable_ranges( &self, range: Range, - ) -> impl Iterator, Runnable)> + '_ { + ) -> impl Iterator, Runnable)> + '_ { let range = range.start.to_offset(self)..range.end.to_offset(self); self.excerpts_for_range(range.clone()) .flat_map(move |(excerpt, excerpt_offset)| { @@ -3183,10 +3183,10 @@ impl MultiBufferSnapshot { excerpt_offset + (match_range.start - excerpt_buffer_start); match_range.end = excerpt_offset + (match_range.end - excerpt_buffer_start); - (match_range, runnable) + (excerpt.buffer_id, match_range, runnable) }) - .skip_while(move |(match_range, _)| match_range.end < range.start) - .take_while(move |(match_range, _)| match_range.start < range.end) + .skip_while(move |(_, match_range, _)| match_range.end < range.start) + .take_while(move |(_, match_range, _)| match_range.start < range.end) }) }