mirror of
https://github.com/itsjunetime/tdf.git
synced 2026-06-01 23:51:46 -04:00
New kitty image backend (#74)
* Initial attempt at supporting new backend for kitty images * it's almost working !! * it almost basically works * yaaayyyy it works * Use github kittage * Uhhhh various improvements from kittage and psx-shm * Remove logging * incorporate recovering from deleted images * Make it work correctly with ghostty image eviction too * fall back to stdout if shms don't work * Make help page work again * zooming basically does what you'd expect now * yay zooming woohoo * clean up top and bottom rendering * Only allow zooming in kitty * Add debug logging and fix cursor placement after image display * yaaaay zooming out once you're already zoomed in and respecting kitty's limits for how big of an image to display * mmmm maybe it's finally ready to merge... * Update deps * Switch around list of items on changelog * fmt * Small fixes to avoid panic and allow zooming back in after zooming out
This commit is contained in:
+106
@@ -1,3 +1,5 @@
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
use ratatui::widgets::Widget;
|
||||
|
||||
pub struct Skip {
|
||||
@@ -19,3 +21,107 @@ impl Widget for Skip {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum PlusOrMinus {
|
||||
Plus,
|
||||
Minus
|
||||
}
|
||||
|
||||
pub struct InterleavedAroundWithMax {
|
||||
// starts at this number
|
||||
around: usize,
|
||||
inclusive_min: usize,
|
||||
// this iterator can only produce values in [0..max)
|
||||
exclusive_max: NonZeroUsize,
|
||||
// the next time we call `next()`, this value should be combined with `around` according to
|
||||
// `next_op`, then, after next_op is inverted, incremented if next_op was negative before being
|
||||
// inverted.
|
||||
next_change: usize,
|
||||
// How `next_change` should be applied to `around` next time `next()` is called
|
||||
next_op: PlusOrMinus
|
||||
}
|
||||
|
||||
impl InterleavedAroundWithMax {
|
||||
/// the following must hold or else this is liable to panic or produce nonsense values:
|
||||
/// - inclusive_min < exclusive_max
|
||||
/// - inclusive_min <= around <= exclusive_max
|
||||
pub fn new(around: usize, inclusive_min: usize, exclusive_max: NonZeroUsize) -> Self {
|
||||
Self {
|
||||
around,
|
||||
inclusive_min,
|
||||
exclusive_max,
|
||||
next_change: 0,
|
||||
next_op: PlusOrMinus::Minus
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for InterleavedAroundWithMax {
|
||||
type Item = usize;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let actual_change = self.next_change % (self.exclusive_max.get() - self.inclusive_min);
|
||||
|
||||
let to_return = match self.next_op {
|
||||
// If we're supposed to add them and we need it to wrap, then try to add them together
|
||||
// 'cause we need special behavior if it overflows usize's limits
|
||||
PlusOrMinus::Plus => match self.around.checked_add(actual_change) {
|
||||
// If we added it and it's within the range, we're chillin
|
||||
Some(next_val) if next_val < self.exclusive_max.get() => next_val,
|
||||
// If we added it and it's not within the range, do next_val % (self.max + 1), e.g.
|
||||
// if max is 20, we were at 15, and we added 7, we should get 1 (because +5 would
|
||||
// hit the max, then 0, then 1). So adding 1 before the modulo makes it hit the
|
||||
// right numbers. And we can be sure the + here doesn't overflow 'cause we already
|
||||
// checked the `usize::MAX` up above
|
||||
Some(next_val) => (next_val % self.exclusive_max.get()) + self.inclusive_min,
|
||||
// If we added them and it would've overflowed usize::MAX, then we see how much
|
||||
// of the change would be remaining after reaching `max`
|
||||
None =>
|
||||
(actual_change - (self.exclusive_max.get() - actual_change))
|
||||
+ self.inclusive_min,
|
||||
},
|
||||
PlusOrMinus::Minus => match self.around.checked_sub(actual_change) {
|
||||
// If we can just minus it, cool cool. All is good.
|
||||
Some(next_val) if next_val >= self.inclusive_min => next_val,
|
||||
// If we can minus it but it goes below our min, then see how much below it went
|
||||
// and just manually wrap it around
|
||||
Some(next_val) => self.exclusive_max.get() - (self.inclusive_min - next_val),
|
||||
// If we can't...
|
||||
None => {
|
||||
// then we see how much of the change would be remaining after hitting the
|
||||
// minimum
|
||||
let remaining = actual_change - (self.around - self.inclusive_min);
|
||||
|
||||
// and then we take that away from the top!
|
||||
self.exclusive_max.get() - remaining
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.next_op = match self.next_op {
|
||||
PlusOrMinus::Plus => PlusOrMinus::Minus,
|
||||
PlusOrMinus::Minus => {
|
||||
self.next_change = (self.next_change + 1) % self.exclusive_max.get();
|
||||
PlusOrMinus::Plus
|
||||
}
|
||||
};
|
||||
|
||||
Some(to_return)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn iter_works() {
|
||||
let got = InterleavedAroundWithMax::new(5, 2, NonZeroUsize::new(21).unwrap())
|
||||
.take(30)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(got, vec![
|
||||
5, 6, 4, 7, 3, 8, 2, 9, 20, 10, 19, 11, 18, 12, 17, 13, 16, 14, 15, 15, 14, 16, 13, 17,
|
||||
12, 18, 11, 19, 10, 20
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user