mirror of
https://github.com/gitui-org/gitui
synced 2026-05-24 01:18:21 +00:00
allow async job to return dynamic notification
This commit is contained in:
parent
e5688e3b8b
commit
b9e4631ff4
8 changed files with 45 additions and 40 deletions
|
|
@ -8,31 +8,30 @@ use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
/// trait that defines an async task we can run on a threadpool
|
/// trait that defines an async task we can run on a threadpool
|
||||||
pub trait AsyncJob: Send + Sync + Clone {
|
pub trait AsyncJob: Send + Sync + Clone {
|
||||||
|
/// defines what notification to send after finish running job
|
||||||
|
type Notification: Copy + Send + 'static;
|
||||||
|
|
||||||
/// can run a synchronous time intensive task
|
/// can run a synchronous time intensive task
|
||||||
fn run(&mut self);
|
fn run(&mut self) -> Self::Notification;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Abstraction for a FIFO task queue that will only queue up **one** `next` job.
|
/// Abstraction for a FIFO task queue that will only queue up **one** `next` job.
|
||||||
/// It keeps overwriting the next job until it is actually taken to be processed
|
/// It keeps overwriting the next job until it is actually taken to be processed
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AsyncSingleJob<J: AsyncJob, T: Copy + Send + 'static> {
|
pub struct AsyncSingleJob<J: AsyncJob> {
|
||||||
next: Arc<Mutex<Option<J>>>,
|
next: Arc<Mutex<Option<J>>>,
|
||||||
last: Arc<Mutex<Option<J>>>,
|
last: Arc<Mutex<Option<J>>>,
|
||||||
sender: Sender<T>,
|
sender: Sender<J::Notification>,
|
||||||
pending: Arc<Mutex<()>>,
|
pending: Arc<Mutex<()>>,
|
||||||
notification: T,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<J: 'static + AsyncJob, T: Copy + Send + 'static>
|
impl<J: 'static + AsyncJob> AsyncSingleJob<J> {
|
||||||
AsyncSingleJob<J, T>
|
|
||||||
{
|
|
||||||
///
|
///
|
||||||
pub fn new(sender: Sender<T>, value: T) -> Self {
|
pub fn new(sender: Sender<J::Notification>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
next: Arc::new(Mutex::new(None)),
|
next: Arc::new(Mutex::new(None)),
|
||||||
last: Arc::new(Mutex::new(None)),
|
last: Arc::new(Mutex::new(None)),
|
||||||
pending: Arc::new(Mutex::new(())),
|
pending: Arc::new(Mutex::new(())),
|
||||||
notification: value,
|
|
||||||
sender,
|
sender,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -96,13 +95,13 @@ impl<J: 'static + AsyncJob, T: Copy + Send + 'static>
|
||||||
{
|
{
|
||||||
let _pending = self.pending.lock()?;
|
let _pending = self.pending.lock()?;
|
||||||
|
|
||||||
task.run();
|
let notification = task.run();
|
||||||
|
|
||||||
if let Ok(mut last) = self.last.lock() {
|
if let Ok(mut last) = self.last.lock() {
|
||||||
*last = Some(task);
|
*last = Some(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.sender.send(self.notification)?;
|
self.sender.send(notification)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_for_job();
|
self.check_for_job();
|
||||||
|
|
@ -143,8 +142,12 @@ mod test {
|
||||||
value_to_add: u32,
|
value_to_add: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TestNotificaton = ();
|
||||||
|
|
||||||
impl AsyncJob for TestJob {
|
impl AsyncJob for TestJob {
|
||||||
fn run(&mut self) {
|
type Notification = TestNotificaton;
|
||||||
|
|
||||||
|
fn run(&mut self) -> Self::Notification {
|
||||||
println!("[job] wait");
|
println!("[job] wait");
|
||||||
|
|
||||||
while !self.finish.load(Ordering::SeqCst) {
|
while !self.finish.load(Ordering::SeqCst) {
|
||||||
|
|
@ -161,17 +164,17 @@ mod test {
|
||||||
self.v.fetch_add(self.value_to_add, Ordering::SeqCst);
|
self.v.fetch_add(self.value_to_add, Ordering::SeqCst);
|
||||||
|
|
||||||
println!("[job] value: {}", res);
|
println!("[job] value: {}", res);
|
||||||
|
|
||||||
|
()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Notificaton = ();
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_overwrite() {
|
fn test_overwrite() {
|
||||||
let (sender, receiver) = unbounded();
|
let (sender, receiver) = unbounded();
|
||||||
|
|
||||||
let mut job: AsyncSingleJob<TestJob, Notificaton> =
|
let mut job: AsyncSingleJob<TestJob> =
|
||||||
AsyncSingleJob::new(sender, ());
|
AsyncSingleJob::new(sender);
|
||||||
|
|
||||||
let task = TestJob {
|
let task = TestJob {
|
||||||
v: Arc::new(AtomicU32::new(1)),
|
v: Arc::new(AtomicU32::new(1)),
|
||||||
|
|
@ -199,7 +202,7 @@ mod test {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_for_job(job: &AsyncSingleJob<TestJob, Notificaton>) {
|
fn wait_for_job(job: &AsyncSingleJob<TestJob>) {
|
||||||
while job.is_pending() {
|
while job.is_pending() {
|
||||||
thread::sleep(Duration::from_millis(10));
|
thread::sleep(Duration::from_millis(10));
|
||||||
}
|
}
|
||||||
|
|
@ -209,8 +212,8 @@ mod test {
|
||||||
fn test_cancel() {
|
fn test_cancel() {
|
||||||
let (sender, receiver) = unbounded();
|
let (sender, receiver) = unbounded();
|
||||||
|
|
||||||
let mut job: AsyncSingleJob<TestJob, Notificaton> =
|
let mut job: AsyncSingleJob<TestJob> =
|
||||||
AsyncSingleJob::new(sender, ());
|
AsyncSingleJob::new(sender);
|
||||||
|
|
||||||
let task = TestJob {
|
let task = TestJob {
|
||||||
v: Arc::new(AtomicU32::new(1)),
|
v: Arc::new(AtomicU32::new(1)),
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@ pub enum AsyncGitNotification {
|
||||||
Fetch,
|
Fetch,
|
||||||
///
|
///
|
||||||
Blame,
|
Blame,
|
||||||
|
///
|
||||||
|
RemoteTags,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// current working directory `./`
|
/// current working directory `./`
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
error::Result,
|
error::Result,
|
||||||
sync::cred::BasicAuthCredential,
|
sync::cred::BasicAuthCredential,
|
||||||
sync::remotes::{get_default_remote, tags_missing_remote},
|
sync::remotes::{get_default_remote, tags_missing_remote},
|
||||||
CWD,
|
AsyncGitNotification, CWD,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
@ -50,7 +50,9 @@ impl AsyncRemoteTagsJob {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncJob for AsyncRemoteTagsJob {
|
impl AsyncJob for AsyncRemoteTagsJob {
|
||||||
fn run(&mut self) {
|
type Notification = AsyncGitNotification;
|
||||||
|
|
||||||
|
fn run(&mut self) -> Self::Notification {
|
||||||
if let Ok(mut state) = self.state.lock() {
|
if let Ok(mut state) = self.state.lock() {
|
||||||
*state = state.take().map(|state| match state {
|
*state = state.take().map(|state| match state {
|
||||||
JobState::Request(basic_credential) => {
|
JobState::Request(basic_credential) => {
|
||||||
|
|
@ -70,5 +72,7 @@ impl AsyncJob for AsyncRemoteTagsJob {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AsyncGitNotification::RemoteTags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@ impl App {
|
||||||
),
|
),
|
||||||
tags_popup: TagListComponent::new(
|
tags_popup: TagListComponent::new(
|
||||||
&queue,
|
&queue,
|
||||||
sender_app,
|
sender,
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
key_config.clone(),
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,7 @@ use tui::{
|
||||||
|
|
||||||
pub struct SyntaxTextComponent {
|
pub struct SyntaxTextComponent {
|
||||||
current_file: Option<(String, Either<ui::SyntaxText, String>)>,
|
current_file: Option<(String, Either<ui::SyntaxText, String>)>,
|
||||||
async_highlighting:
|
async_highlighting: AsyncSingleJob<AsyncSyntaxJob>,
|
||||||
AsyncSingleJob<AsyncSyntaxJob, AsyncAppNotification>,
|
|
||||||
key_config: SharedKeyConfig,
|
key_config: SharedKeyConfig,
|
||||||
paragraph_state: Cell<ParagraphState>,
|
paragraph_state: Cell<ParagraphState>,
|
||||||
focused: bool,
|
focused: bool,
|
||||||
|
|
@ -48,10 +47,7 @@ impl SyntaxTextComponent {
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
async_highlighting: AsyncSingleJob::new(
|
async_highlighting: AsyncSingleJob::new(sender.clone()),
|
||||||
sender.clone(),
|
|
||||||
AsyncAppNotification::SyntaxHighlighting,
|
|
||||||
),
|
|
||||||
current_file: None,
|
current_file: None,
|
||||||
paragraph_state: Cell::new(ParagraphState::default()),
|
paragraph_state: Cell::new(ParagraphState::default()),
|
||||||
focused: false,
|
focused: false,
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use crate::{
|
||||||
queue::{Action, InternalEvent, Queue},
|
queue::{Action, InternalEvent, Queue},
|
||||||
strings,
|
strings,
|
||||||
ui::{self, Size},
|
ui::{self, Size},
|
||||||
AsyncAppNotification, AsyncNotification,
|
AsyncNotification,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use asyncgit::{
|
use asyncgit::{
|
||||||
|
|
@ -46,8 +46,7 @@ pub struct TagListComponent {
|
||||||
current_height: std::cell::Cell<usize>,
|
current_height: std::cell::Cell<usize>,
|
||||||
missing_remote_tags: Option<Vec<String>>,
|
missing_remote_tags: Option<Vec<String>>,
|
||||||
basic_credential: Option<BasicAuthCredential>,
|
basic_credential: Option<BasicAuthCredential>,
|
||||||
async_remote_tags:
|
async_remote_tags: AsyncSingleJob<AsyncRemoteTagsJob>,
|
||||||
AsyncSingleJob<AsyncRemoteTagsJob, AsyncAppNotification>,
|
|
||||||
key_config: SharedKeyConfig,
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,7 +250,7 @@ impl Component for TagListComponent {
|
||||||
impl TagListComponent {
|
impl TagListComponent {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
queue: &Queue,
|
queue: &Queue,
|
||||||
sender: &Sender<AsyncAppNotification>,
|
sender: &Sender<AsyncGitNotification>,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
key_config: SharedKeyConfig,
|
key_config: SharedKeyConfig,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
@ -264,10 +263,7 @@ impl TagListComponent {
|
||||||
current_height: std::cell::Cell::new(0),
|
current_height: std::cell::Cell::new(0),
|
||||||
basic_credential: None,
|
basic_credential: None,
|
||||||
missing_remote_tags: None,
|
missing_remote_tags: None,
|
||||||
async_remote_tags: AsyncSingleJob::new(
|
async_remote_tags: AsyncSingleJob::new(sender.clone()),
|
||||||
sender.clone(),
|
|
||||||
AsyncAppNotification::RemoteTags,
|
|
||||||
),
|
|
||||||
key_config,
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -301,7 +297,7 @@ impl TagListComponent {
|
||||||
pub fn update(&mut self, ev: AsyncNotification) {
|
pub fn update(&mut self, ev: AsyncNotification) {
|
||||||
if matches!(
|
if matches!(
|
||||||
ev,
|
ev,
|
||||||
AsyncNotification::App(AsyncAppNotification::RemoteTags)
|
AsyncNotification::Git(AsyncGitNotification::RemoteTags)
|
||||||
) {
|
) {
|
||||||
if let Some(job) = self.async_remote_tags.take_last() {
|
if let Some(job) = self.async_remote_tags.take_last() {
|
||||||
if let Some(Ok(missing_remote_tags)) = job.result() {
|
if let Some(Ok(missing_remote_tags)) = job.result() {
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,6 @@ pub enum QueueEvent {
|
||||||
pub enum AsyncAppNotification {
|
pub enum AsyncAppNotification {
|
||||||
///
|
///
|
||||||
SyntaxHighlighting,
|
SyntaxHighlighting,
|
||||||
///
|
|
||||||
RemoteTags,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ use syntect::{
|
||||||
};
|
};
|
||||||
use tui::text::{Span, Spans};
|
use tui::text::{Span, Spans};
|
||||||
|
|
||||||
|
use crate::AsyncAppNotification;
|
||||||
|
|
||||||
struct SyntaxLine {
|
struct SyntaxLine {
|
||||||
items: Vec<(Style, usize, Range<usize>)>,
|
items: Vec<(Style, usize, Range<usize>)>,
|
||||||
}
|
}
|
||||||
|
|
@ -175,7 +177,9 @@ impl AsyncSyntaxJob {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncJob for AsyncSyntaxJob {
|
impl AsyncJob for AsyncSyntaxJob {
|
||||||
fn run(&mut self) {
|
type Notification = AsyncAppNotification;
|
||||||
|
|
||||||
|
fn run(&mut self) -> Self::Notification {
|
||||||
if let Ok(mut state) = self.state.lock() {
|
if let Ok(mut state) = self.state.lock() {
|
||||||
*state = state.take().map(|state| match state {
|
*state = state.take().map(|state| match state {
|
||||||
JobState::Request((content, path)) => {
|
JobState::Request((content, path)) => {
|
||||||
|
|
@ -186,5 +190,7 @@ impl AsyncJob for AsyncSyntaxJob {
|
||||||
JobState::Response(res) => JobState::Response(res),
|
JobState::Response(res) => JobState::Response(res),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AsyncAppNotification::SyntaxHighlighting
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue