mirror of
https://github.com/itsjunetime/tdf.git
synced 2026-06-01 23:51:46 -04:00
b6bc76edbb
* 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
128 lines
3.9 KiB
Rust
128 lines
3.9 KiB
Rust
use std::num::NonZeroUsize;
|
|
|
|
use ratatui::widgets::Widget;
|
|
|
|
pub struct Skip {
|
|
skip: bool
|
|
}
|
|
|
|
impl Skip {
|
|
pub fn new(skip: bool) -> Self {
|
|
Self { skip }
|
|
}
|
|
}
|
|
|
|
impl Widget for Skip {
|
|
fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer) {
|
|
for x in area.x..(area.x + area.width) {
|
|
for y in area.y..(area.y + area.height) {
|
|
buf[(x, y)].skip = self.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
|
|
]);
|
|
}
|
|
}
|