tasks: Fix divider position in modal (#11049)

Piotr Osiewicz created

The divider between templates and recent runs is constant, regardless of
the currently used filter string; this can lead to situations where an
user can remove the predefined task, which isn't good at all.

Additionally, in this PR I've made it so that recent runs always show up
before task templates in filtered list.

Release Notes:

- Fixed position of list divider in task modal.

Change summary

crates/tasks_ui/src/modal.rs | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)

Detailed changes

crates/tasks_ui/src/modal.rs 🔗

@@ -62,6 +62,7 @@ pub(crate) struct TasksModalDelegate {
     inventory: Model<Inventory>,
     candidates: Option<Vec<(TaskSourceKind, ResolvedTask)>>,
     last_used_candidate_index: Option<usize>,
+    divider_index: Option<usize>,
     matches: Vec<StringMatch>,
     selected_index: usize,
     workspace: WeakView<Workspace>,
@@ -82,6 +83,7 @@ impl TasksModalDelegate {
             candidates: None,
             matches: Vec::new(),
             last_used_candidate_index: None,
+            divider_index: None,
             selected_index: 0,
             prompt: String::default(),
             task_context,
@@ -255,7 +257,17 @@ impl PickerDelegate for TasksModalDelegate {
                 .update(&mut cx, |picker, _| {
                     let delegate = &mut picker.delegate;
                     delegate.matches = matches;
+                    if let Some(index) = delegate.last_used_candidate_index {
+                        delegate.matches.sort_by_key(|m| m.candidate_id > index);
+                    }
+
                     delegate.prompt = query;
+                    delegate.divider_index = delegate.last_used_candidate_index.and_then(|index| {
+                        let index = delegate
+                            .matches
+                            .partition_point(|matching_task| matching_task.candidate_id <= index);
+                        Some(index).and_then(|index| (index != 0).then(|| index - 1))
+                    });
 
                     if delegate.matches.is_empty() {
                         delegate.selected_index = 0;
@@ -352,7 +364,7 @@ impl PickerDelegate for TasksModalDelegate {
                 })
                 .map(|item| {
                     let item = if matches!(source_kind, TaskSourceKind::UserInput)
-                        || Some(ix) <= self.last_used_candidate_index
+                        || Some(ix) <= self.divider_index
                     {
                         let task_index = hit.candidate_id;
                         let delete_button = div().child(
@@ -412,7 +424,7 @@ impl PickerDelegate for TasksModalDelegate {
     }
 
     fn separators_after_indices(&self) -> Vec<usize> {
-        if let Some(i) = self.last_used_candidate_index {
+        if let Some(i) = self.divider_index {
             vec![i]
         } else {
             Vec::new()