Skip to content

Commit

Permalink
feat(backend): backend provides window_size
Browse files Browse the repository at this point in the history
For image (sixel, iTerm2, Kitty...) support that handles graphics in
terms of `Rect` so that the image area can be included in layouts.

For example: an image is loaded with a known pixel-size, and drawn, but
the image protocol has no mechanism of knowing the actual cell/character
area that been drawn on. It is then impossible to skip overdrawing the
area.

Returning the window size in pixel-width / pixel-height, together with
colums / rows, it can be possible to account the pixel size of each cell
/ character, and then known the `Rect` of a given image, and also resize
the image so that it fits exactly in a `Rect`.
  • Loading branch information
benjajaja committed Aug 6, 2023
1 parent 0f63c43 commit 7cacfcc
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 17 deletions.
8 changes: 8 additions & 0 deletions src/backend/crossterm.rs
Expand Up @@ -175,6 +175,14 @@ where
Ok(Rect::new(0, 0, width, height))
}

fn window_size(&mut self) -> Result<(Rect, (u16, u16)), io::Error> {
let window_size = terminal::window_size()?;
Ok((
Rect::new(0, 0, window_size.columns, window_size.rows),
(window_size.width, window_size.height),
))
}

Check warning on line 184 in src/backend/crossterm.rs

View check run for this annotation

Codecov / codecov/patch

src/backend/crossterm.rs#L178-L184

Added lines #L178 - L184 were not covered by tests

fn flush(&mut self) -> io::Result<()> {
self.buffer.flush()
}
Expand Down
3 changes: 3 additions & 0 deletions src/backend/mod.rs
Expand Up @@ -112,6 +112,9 @@ pub trait Backend {
/// Get the size of the terminal screen as a [`Rect`].
fn size(&self) -> Result<Rect, io::Error>;

/// Get the font size of the terminal screen as [`(width, height)`].
fn window_size(&mut self) -> Result<(Rect, (u16, u16)), io::Error>;

/// Flush any buffered content to the terminal screen.
fn flush(&mut self) -> Result<(), io::Error>;
}
6 changes: 6 additions & 0 deletions src/backend/termion.rs
Expand Up @@ -160,6 +160,12 @@ where
Ok(Rect::new(0, 0, terminal.0, terminal.1))
}

fn window_size(&mut self) -> Result<(Rect, (u16, u16)), io::Error> {
let terminal = termion::terminal_size()?;
let pixels = termion::terminal_size_pixels()?;
Ok((Rect::new(0, 0, terminal.0, terminal.1), pixels))
}

Check warning on line 167 in src/backend/termion.rs

View check run for this annotation

Codecov / codecov/patch

src/backend/termion.rs#L163-L167

Added lines #L163 - L167 were not covered by tests

fn flush(&mut self) -> io::Result<()> {
self.stdout.flush()
}
Expand Down
44 changes: 27 additions & 17 deletions src/backend/termwiz.rs
Expand Up @@ -11,7 +11,7 @@ use termwiz::{
cell::{AttributeChange, Blink, Intensity, Underline},
color::{AnsiColor, ColorAttribute, SrgbaTuple},
surface::{Change, CursorVisibility, Position},
terminal::{buffered::BufferedTerminal, SystemTerminal, Terminal},
terminal::{buffered::BufferedTerminal, ScreenSize, SystemTerminal, Terminal},
};

use crate::{
Expand Down Expand Up @@ -169,22 +169,21 @@ impl Backend for TermwizBackend {
}

fn size(&self) -> Result<Rect, io::Error> {
let (term_width, term_height) = self.buffered_terminal.dimensions();
let max = u16::max_value();
Ok(Rect::new(
0,
0,
if term_width > usize::from(max) {
max
} else {
term_width as u16
},
if term_height > usize::from(max) {
max
} else {
term_height as u16
},
))
Ok(self.buffered_terminal.dimensions().into())
}

Check warning on line 173 in src/backend/termwiz.rs

View check run for this annotation

Codecov / codecov/patch

src/backend/termwiz.rs#L172-L173

Added lines #L172 - L173 were not covered by tests

fn window_size(&mut self) -> Result<(Rect, (u16, u16)), io::Error> {

Check warning on line 175 in src/backend/termwiz.rs

View check run for this annotation

Codecov / codecov/patch

src/backend/termwiz.rs#L175

Added line #L175 was not covered by tests
let ScreenSize {
cols,
rows,
xpixel,
ypixel,
} = self
.buffered_terminal
.terminal()
.get_screen_size()
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
Ok(((cols, rows).into(), (u16_max(xpixel), u16_max(ypixel))))

Check warning on line 186 in src/backend/termwiz.rs

View check run for this annotation

Codecov / codecov/patch

src/backend/termwiz.rs#L177-L186

Added lines #L177 - L186 were not covered by tests
}

fn flush(&mut self) -> Result<(), io::Error> {
Expand Down Expand Up @@ -221,3 +220,14 @@ impl From<Color> for ColorAttribute {
}
}
}

impl From<(usize, usize)> for Rect {
fn from((cols, rows): (usize, usize)) -> Rect {
Rect::new(0, 0, u16_max(cols), u16_max(rows))
}

Check warning on line 227 in src/backend/termwiz.rs

View check run for this annotation

Codecov / codecov/patch

src/backend/termwiz.rs#L225-L227

Added lines #L225 - L227 were not covered by tests
}

#[inline]
fn u16_max(i: usize) -> u16 {
u16::try_from(i).unwrap_or(u16::MAX)
}

Check warning on line 233 in src/backend/termwiz.rs

View check run for this annotation

Codecov / codecov/patch

src/backend/termwiz.rs#L231-L233

Added lines #L231 - L233 were not covered by tests
6 changes: 6 additions & 0 deletions src/backend/test.rs
Expand Up @@ -177,6 +177,12 @@ impl Backend for TestBackend {
Ok(Rect::new(0, 0, self.width, self.height))
}

fn window_size(&mut self) -> Result<(Rect, (u16, u16)), io::Error> {
// Some arbitrary window pixel size, probably doesn't need much testing.
static WINDOW_PIXEL_SIZE: (u16, u16) = (640, 480);
Ok((Rect::new(0, 0, self.width, self.height), WINDOW_PIXEL_SIZE))
}

Check warning on line 184 in src/backend/test.rs

View check run for this annotation

Codecov / codecov/patch

src/backend/test.rs#L180-L184

Added lines #L180 - L184 were not covered by tests

fn flush(&mut self) -> Result<(), io::Error> {
Ok(())
}
Expand Down

0 comments on commit 7cacfcc

Please sign in to comment.