Compare commits

...

3 Commits

Author SHA1 Message Date
itsjunetime f9df806a8f Remove accidental comment 2024-11-17 17:34:59 -07:00
itsjunetime 5e7ec97b43 Flush EventStream when receiving a scroll event to work around high scroll sensitivities 2024-11-17 17:33:43 -07:00
itsjunetime 1aa26b8e8c Manually enable opinionated set of clippy lints 2024-11-16 22:03:31 -07:00
2 changed files with 132 additions and 5 deletions
+90
View File
@@ -61,3 +61,93 @@ harness = false
[[bin]]
name = "for_profiling"
path = "./benches/for_profiling.rs"
[lints.clippy]
uninlined_format_args = "warn"
redundant_closure_for_method_calls = "warn"
cast_lossless = "warn"
single_char_pattern = "warn"
manual_let_else = "warn"
ignored_unit_patterns = "warn"
range_plus_one = "warn"
unreadable_literal = "warn"
redundant_else = "warn"
assigning_clones = "warn"
bool_to_int_with_if = "warn"
borrow_as_ptr = "warn"
cast_ptr_alignment = "warn"
checked_conversions = "warn"
copy_iterator = "warn"
default_trait_access = "warn"
doc_link_with_quotes = "warn"
empty_enum = "warn"
explicit_into_iter_loop = "warn"
explicit_iter_loop = "warn"
filter_map_next = "warn"
flat_map_option = "warn"
fn_params_excessive_bools = "warn"
from_iter_instead_of_collect = "warn"
implicit_clone = "warn"
index_refutable_slice = "warn"
inefficient_to_string = "warn"
invalid_upcast_comparisons = "warn"
iter_filter_is_ok = "warn"
iter_filter_is_some = "warn"
iter_not_returning_iterator = "warn"
large_futures = "warn"
large_stack_arrays = "warn"
large_types_passed_by_value = "warn"
linkedlist = "warn"
macro_use_imports = "warn"
manual_assert = "warn"
manual_instant_elapsed = "warn"
manual_is_power_of_two = "warn"
manual_is_variant_and = "warn"
manual_ok_or = "warn"
manual_string_new = "warn"
many_single_char_names = "warn"
manual_unwrap_or = "warn"
match_on_vec_items = "warn"
match_same_arms = "warn"
match_wildcard_for_single_variants = "warn"
maybe_infinite_iter = "warn"
mismatching_type_param_order = "warn"
missing_fields_in_debug = "warn"
mut_mut = "warn"
needless_bitwise_bool = "warn"
needless_continue = "warn"
needless_for_each = "warn"
needless_pass_by_value = "warn"
needless_raw_string_hashes = "warn"
no_effect_underscore_binding = "warn"
no_mangle_with_rust_abi = "warn"
option_as_ref_cloned = "warn"
option_option = "warn"
ptr_as_ptr = "warn"
ptr_cast_constness = "warn"
range_minus_one = "warn"
ref_as_ptr = "warn"
ref_binding_to_reference = "warn"
ref_option = "warn"
ref_option_ref = "warn"
return_self_not_must_use = "warn"
same_functions_in_if_condition = "warn"
should_panic_without_expect = "warn"
similar_names = "warn"
stable_sort_primitive = "warn"
str_split_at_newline = "warn"
struct_excessive_bools = "warn"
struct_field_names = "warn"
transmute_ptr_to_ptr = "warn"
trivially_copy_pass_by_ref = "warn"
unicode_not_nfc = "warn"
unnecessary_box_returns = "warn"
unnecessary_join = "warn"
unnecessary_literal_bound = "warn"
unnecessary_wraps = "warn"
unnested_or_patterns = "warn"
unused_async = "warn"
unused_self = "warn"
used_underscore_binding = "warn"
used_underscore_items = "warn"
zero_sized_map_values = "warn"
+42 -5
View File
@@ -1,11 +1,14 @@
use std::{
future::poll_fn,
io::{stdout, Read, Write},
num::NonZeroUsize,
path::PathBuf
path::PathBuf,
task::Poll
};
use converter::{run_conversion_loop, ConvertedPage, ConverterMsg};
use crossterm::{
event::{Event, EventStream, MouseEvent, MouseEventKind},
execute,
terminal::{
disable_raw_mode, enable_raw_mode, window_size, EndSynchronizedUpdate,
@@ -14,7 +17,7 @@ use crossterm::{
};
use futures_util::{stream::StreamExt, FutureExt};
use glib::{LogField, LogLevel, LogWriterOutput};
use notify::{Event, EventKind, RecursiveMode, Watcher};
use notify::{EventKind, RecursiveMode, Watcher};
use ratatui::{backend::CrosstermBackend, Terminal};
use ratatui_image::picker::Picker;
use renderer::{RenderError, RenderInfo, RenderNotif};
@@ -123,7 +126,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// We need to create `picker` on this thread because if we create it on the `renderer` thread,
// it messes up something with user input. Input never makes it to the crossterm thing
let picker = Picker::from_query_stdio()?;
let picker = Picker::from_query_stdio()?;
// then we want to spawn off the rendering task
// We need to use the thread::spawn API so that this exists in a thread not owned by tokio,
@@ -132,7 +135,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
renderer::start_rendering(&file_path, render_tx, render_rx, window_size)
});
let mut ev_stream = crossterm::event::EventStream::new();
let mut ev_stream = EventStream::new();
let (to_converter, from_main) = flume::unbounded();
let (to_main, from_converter) = flume::unbounded();
@@ -175,6 +178,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// If we can't get user input, just crash.
let ev = ev.expect("Couldn't get any user input");
flush_if_mouse(&ev, &mut ev_stream).await;
match tui.handle_event(&ev) {
None => needs_redraw = false,
Some(action) => match action {
@@ -244,7 +249,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
fn on_notify_ev(
to_tui_tx: flume::Sender<Result<RenderInfo, RenderError>>,
to_render_tx: flume::Sender<RenderNotif>
) -> impl Fn(notify::Result<Event>) {
) -> impl Fn(notify::Result<notify::Event>) {
move |res| match res {
// If we get an error here, and then an error sending, everything's going wrong. Just give
// up lol.
@@ -267,3 +272,35 @@ fn on_notify_ev(
fn noop(_: LogLevel, _: &[LogField<'_>]) -> LogWriterOutput {
LogWriterOutput::Handled
}
async fn flush_if_mouse(ev: &Event, ev_stream: &mut EventStream) {
// If you have a high scroll sensitivity, on some platforms, crossterm sends 2+ mouse events per
// scroll. However, because tdf scrolls pages once per mouse event, that means that they can't
// scroll the pages of their PDF as they would expect - it jumps multiple pages per one scroll.
// So this just flushes the event queue once we detect a scroll event to make sure those extra
// scrolls are ignored.
//
// Theoretically, this introduces a race condition where events that arrive in between the
// processing of `ev` and the time we call `poll_next_unpin` can get ignored, but that's a very
// very small amount of time, so unlikely to happen. However, if that does become an issue, we
// can just flush the event queue until we see a non-scroll event, then store that event in a
// future that will return it next time we call `tokio::select!` in the main loop. That'll make
// sure we don't miss anything.
if let Event::Mouse(MouseEvent {
kind:
MouseEventKind::ScrollUp
| MouseEventKind::ScrollDown
| MouseEventKind::ScrollLeft
| MouseEventKind::ScrollRight,
..
}) = ev
{
poll_fn(|ctx| {
while ev_stream.poll_next_unpin(ctx).is_ready() {
println!("got another mouse event!");
}
Poll::Ready(())
})
.await;
}
}