mirror of
https://github.com/gitui-org/gitui
synced 2026-05-24 09:28:21 +00:00
almost a magnitude of perf win by moving input polling into thread
This commit is contained in:
parent
8618e404d4
commit
eefd31ad05
3 changed files with 66 additions and 19 deletions
|
|
@ -13,7 +13,7 @@ Over the last 2 years my go to GUI tool for this was [fork](https://git-fork.com
|
||||||
* [x] (un)stage files
|
* [x] (un)stage files
|
||||||
* [x] inspect diffs
|
* [x] inspect diffs
|
||||||
* [x] commit
|
* [x] commit
|
||||||
* [ ] input polling in thread
|
* [x] input polling in thread
|
||||||
* [ ] file watcher instead of polling git
|
* [ ] file watcher instead of polling git
|
||||||
* [ ] log view
|
* [ ] log view
|
||||||
|
|
||||||
|
|
|
||||||
18
src/main.rs
18
src/main.rs
|
|
@ -6,7 +6,7 @@ mod git_utils;
|
||||||
mod poll;
|
mod poll;
|
||||||
mod tui_utils;
|
mod tui_utils;
|
||||||
|
|
||||||
use app::App;
|
use crate::{app::App, poll::QueueEvent};
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
event::{DisableMouseCapture, EnableMouseCapture},
|
event::{DisableMouseCapture, EnableMouseCapture},
|
||||||
terminal::{
|
terminal::{
|
||||||
|
|
@ -15,8 +15,7 @@ use crossterm::{
|
||||||
},
|
},
|
||||||
ExecutableCommand, Result,
|
ExecutableCommand, Result,
|
||||||
};
|
};
|
||||||
use poll::PollResult;
|
use std::io;
|
||||||
use std::{io, time::Duration};
|
|
||||||
use tui::{backend::CrosstermBackend, Terminal};
|
use tui::{backend::CrosstermBackend, Terminal};
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
|
@ -33,18 +32,17 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
|
|
||||||
|
let receiver = poll::start_polling_thread();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
app.update();
|
app.update();
|
||||||
|
|
||||||
terminal.draw(|mut f| app.draw(&mut f))?;
|
terminal.draw(|mut f| app.draw(&mut f))?;
|
||||||
|
|
||||||
loop {
|
let events = receiver.recv().unwrap();
|
||||||
if let PollResult::Event(e) =
|
for e in events {
|
||||||
poll::poll(Duration::from_millis(10))
|
if let QueueEvent::Event(ev) = e {
|
||||||
{
|
app.event(ev);
|
||||||
app.event(e);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
65
src/poll.rs
65
src/poll.rs
|
|
@ -1,20 +1,69 @@
|
||||||
use crossterm::event::{self, Event};
|
use crossterm::event::{self, Event};
|
||||||
use std::time::Duration;
|
use std::{
|
||||||
|
sync::mpsc::{self, Receiver},
|
||||||
|
thread::{self, sleep},
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
/// as
|
///
|
||||||
pub enum PollResult {
|
#[derive(Clone)]
|
||||||
Timeout,
|
pub enum QueueEvent {
|
||||||
|
Tick,
|
||||||
Event(Event),
|
Event(Event),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MAX_POLL_DURATION: Duration = Duration::from_secs(2);
|
||||||
|
static MIN_POLL_DURATION: Duration = Duration::from_millis(5);
|
||||||
|
static MAX_BATCHING_DURATION: Duration = Duration::from_millis(25);
|
||||||
|
static TICK_DURATION: Duration = Duration::from_secs(2);
|
||||||
|
|
||||||
|
/// we run 2 threads feeding us with update events.
|
||||||
///
|
///
|
||||||
pub fn poll(dur: Duration) -> PollResult {
|
/// Thread 1:
|
||||||
|
/// We will
|
||||||
|
pub fn start_polling_thread() -> Receiver<Vec<QueueEvent>> {
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
let tx1 = tx.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
let mut last_send = Instant::now();
|
||||||
|
let mut batch = Vec::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let timeout = if batch.len() > 0 {
|
||||||
|
MIN_POLL_DURATION
|
||||||
|
} else {
|
||||||
|
MAX_POLL_DURATION
|
||||||
|
};
|
||||||
|
if let Some(e) = poll(timeout) {
|
||||||
|
batch.push(QueueEvent::Event(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
if batch.len() > 0
|
||||||
|
&& last_send.elapsed() > MAX_BATCHING_DURATION
|
||||||
|
{
|
||||||
|
tx1.send(batch).unwrap();
|
||||||
|
batch = Vec::new();
|
||||||
|
last_send = Instant::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
thread::spawn(move || loop {
|
||||||
|
tx.send(vec![QueueEvent::Tick]).unwrap();
|
||||||
|
sleep(TICK_DURATION);
|
||||||
|
});
|
||||||
|
|
||||||
|
rx
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
fn poll(dur: Duration) -> Option<Event> {
|
||||||
if event::poll(dur).unwrap() {
|
if event::poll(dur).unwrap() {
|
||||||
// It's guaranteed that read() wont block if `poll` returns `Ok(true)`
|
// It's guaranteed that read() wont block if `poll` returns `Ok(true)`
|
||||||
let event = event::read().unwrap();
|
let event = event::read().unwrap();
|
||||||
|
Some(event)
|
||||||
PollResult::Event(event)
|
|
||||||
} else {
|
} else {
|
||||||
PollResult::Timeout
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue