Sort tasks modal entries by last used time

This commit is contained in:
Kirill Bulatov 2024-02-28 02:01:56 +02:00 committed by Kirill Bulatov
parent 9f7e625d37
commit 96d9df073e
3 changed files with 82 additions and 32 deletions

View file

@ -2,13 +2,16 @@
use std::{any::TypeId, path::Path, sync::Arc};
use collections::{HashMap, VecDeque};
use gpui::{AppContext, Context, Model, ModelContext, Subscription};
use itertools::Itertools;
use task::{Source, Task, TaskId};
use util::post_inc;
/// Inventory tracks available tasks for a given project.
pub struct Inventory {
sources: Vec<SourceInInventory>,
pub last_scheduled_task: Option<TaskId>,
last_scheduled_tasks: VecDeque<TaskId>,
}
struct SourceInInventory {
@ -21,7 +24,7 @@ impl Inventory {
pub(crate) fn new(cx: &mut AppContext) -> Model<Self> {
cx.new_model(|_| Self {
sources: Vec::new(),
last_scheduled_task: None,
last_scheduled_tasks: VecDeque::new(),
})
}
@ -39,6 +42,7 @@ impl Inventory {
self.sources.push(source);
cx.notify();
}
pub fn source<T: Source>(&self) -> Option<Model<Box<dyn Source>>> {
let target_type_id = std::any::TypeId::of::<T>();
self.sources.iter().find_map(
@ -55,25 +59,75 @@ impl Inventory {
}
/// Pulls its sources to list runanbles for the path given (up to the source to decide what to return for no path).
pub fn list_tasks(&self, path: Option<&Path>, cx: &mut AppContext) -> Vec<Arc<dyn Task>> {
let mut tasks = Vec::new();
for source in &self.sources {
tasks.extend(
pub fn list_tasks(
&self,
path: Option<&Path>,
lru: bool,
cx: &mut AppContext,
) -> Vec<Arc<dyn Task>> {
let mut lru_score = 0_u32;
let tasks_by_usage = if lru {
self.last_scheduled_tasks
.iter()
.rev()
.fold(HashMap::default(), |mut tasks, id| {
tasks.entry(id).or_insert_with(|| post_inc(&mut lru_score));
tasks
})
} else {
HashMap::default()
};
self.sources
.iter()
.flat_map(|source| {
source
.source
.update(cx, |source, cx| source.tasks_for_path(path, cx)),
);
}
tasks
.update(cx, |source, cx| source.tasks_for_path(path, cx))
})
.map(|task| {
let usages = if lru {
tasks_by_usage
.get(&task.id())
.copied()
.unwrap_or_else(|| post_inc(&mut lru_score))
} else {
post_inc(&mut lru_score)
};
(task, usages)
})
.sorted_unstable_by(|(task_a, usages_a), (task_b, usages_b)| {
usages_a
.cmp(usages_b)
.then(task_a.name().cmp(task_b.name()))
})
.map(|(task, _)| task)
.collect()
}
/// Returns the last scheduled task, if any of the sources contains one with the matching id.
pub fn last_scheduled_task(&self, cx: &mut AppContext) -> Option<Arc<dyn Task>> {
self.last_scheduled_task.as_ref().and_then(|id| {
self.last_scheduled_tasks.back().and_then(|id| {
// TODO straighten the `Path` story to understand what has to be passed here: or it will break in the future.
self.list_tasks(None, cx)
self.list_tasks(None, false, cx)
.into_iter()
.find(|task| task.id() == id)
})
}
pub fn task_scheduled(&mut self, id: TaskId) {
self.last_scheduled_tasks.push_back(id);
if self.last_scheduled_tasks.len() > 5_000 {
self.last_scheduled_tasks.pop_front();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn todo_kb() {
todo!("TODO kb LRU tests")
}
}