mirror of
https://github.com/helix-editor/termina.git
synced 2025-10-06 00:22:43 +02:00
Add a WindowSize
struct for the terminal dimensions
See <d14e5c51c6 (r156782395)
>.
The tuple can be confusing, especially since it's reversed compared to
crossterm.
Also <https://github.com/helix-editor/termina/issues/5#issuecomment-2869972748>
Co-authored-by: museun <museun@users.noreply.github.com>
This commit is contained in:
@@ -9,7 +9,7 @@ use std::{
|
||||
use termina::{
|
||||
escape::csi::{self, KittyKeyboardFlags},
|
||||
event::{KeyCode, KeyEvent},
|
||||
Event, OneBased, PlatformTerminal, Terminal,
|
||||
Event, PlatformTerminal, Terminal, WindowSize,
|
||||
};
|
||||
|
||||
const HELP: &str = r#"Blocking read()
|
||||
@@ -99,8 +99,8 @@ fn main() -> io::Result<()> {
|
||||
eprintln!("Failed to read the cursor position within 50msec\r");
|
||||
}
|
||||
}
|
||||
Event::WindowResized { rows, cols } => {
|
||||
let new_size = flush_resize_events(&terminal, (rows, cols));
|
||||
Event::WindowResized(dimensions) => {
|
||||
let new_size = flush_resize_events(&terminal, dimensions);
|
||||
println!("Resize from {size:?} to {new_size:?}\r");
|
||||
size = new_size;
|
||||
}
|
||||
@@ -124,15 +124,12 @@ fn main() -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn flush_resize_events(
|
||||
terminal: &PlatformTerminal,
|
||||
original_size: (OneBased, OneBased),
|
||||
) -> (OneBased, OneBased) {
|
||||
fn flush_resize_events(terminal: &PlatformTerminal, original_size: WindowSize) -> WindowSize {
|
||||
let mut size = original_size;
|
||||
let filter = |event: &Event| matches!(event, Event::WindowResized { .. });
|
||||
while let Ok(true) = terminal.poll(filter, Some(Duration::from_millis(50))) {
|
||||
if let Ok(Event::WindowResized { rows, cols }) = terminal.read(filter) {
|
||||
size = (rows, cols)
|
||||
if let Ok(Event::WindowResized(dimensions)) = terminal.read(filter) {
|
||||
size = dimensions;
|
||||
}
|
||||
}
|
||||
size
|
||||
|
@@ -4,7 +4,7 @@
|
||||
|
||||
use crate::{
|
||||
escape::{csi::Csi, dcs::Dcs},
|
||||
OneBased,
|
||||
WindowSize,
|
||||
};
|
||||
|
||||
pub(crate) mod reader;
|
||||
@@ -17,10 +17,7 @@ pub enum Event {
|
||||
Key(KeyEvent),
|
||||
Mouse(MouseEvent),
|
||||
/// The window was resized to the given dimensions.
|
||||
WindowResized {
|
||||
rows: OneBased,
|
||||
cols: OneBased,
|
||||
},
|
||||
WindowResized(WindowSize),
|
||||
FocusIn,
|
||||
FocusOut,
|
||||
/// A "bracketed" paste.
|
||||
|
@@ -16,7 +16,7 @@ use std::{
|
||||
use parking_lot::Mutex;
|
||||
use rustix::termios;
|
||||
|
||||
use crate::{parse::Parser, terminal::FileDescriptor, Event, OneBased};
|
||||
use crate::{parse::Parser, terminal::FileDescriptor, Event};
|
||||
|
||||
use super::{EventSource, PollTimeout};
|
||||
|
||||
@@ -122,10 +122,7 @@ impl EventSource for UnixEventSource {
|
||||
while read_complete(&self.sigwinch_pipe, &mut [0; 1024])? != 0 {}
|
||||
|
||||
let winsize = termios::tcgetwinsize(&self.write)?;
|
||||
// winsize is already one-based.
|
||||
let rows = OneBased::new(winsize.ws_row).unwrap();
|
||||
let cols = OneBased::new(winsize.ws_col).unwrap();
|
||||
let event = Event::WindowResized { rows, cols };
|
||||
let event = Event::WindowResized(winsize.into());
|
||||
return Ok(Some(event));
|
||||
}
|
||||
|
||||
|
13
src/lib.rs
13
src/lib.rs
@@ -59,3 +59,16 @@ impl From<NonZeroU16> for OneBased {
|
||||
Self(n)
|
||||
}
|
||||
}
|
||||
|
||||
/// The dimensions of a terminal screen.
|
||||
///
|
||||
/// For both Unix and Windows, Termina returns the width and height
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct WindowSize {
|
||||
/// The width - the number of columns.
|
||||
#[doc(alias = "width")]
|
||||
pub cols: u16,
|
||||
/// The height - the number of rows.
|
||||
#[doc(alias = "height")]
|
||||
pub rows: u16,
|
||||
}
|
||||
|
@@ -91,7 +91,7 @@ impl Parser {
|
||||
mod windows {
|
||||
use windows_sys::Win32::System::Console;
|
||||
|
||||
use crate::OneBased;
|
||||
use crate::{OneBased, WindowSize};
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -125,7 +125,10 @@ mod windows {
|
||||
let Some(cols) = OneBased::new(record.dwSize.X as u16) else {
|
||||
continue;
|
||||
};
|
||||
self.events.push_back(Event::WindowResized { rows, cols });
|
||||
self.events.push_back(Event::WindowResized(WindowSize {
|
||||
rows: rows.get(),
|
||||
cols: cols.get(),
|
||||
}));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ pub use unix::*;
|
||||
#[cfg(windows)]
|
||||
pub use windows::*;
|
||||
|
||||
use crate::{Event, EventReader, OneBased};
|
||||
use crate::{Event, EventReader, WindowSize};
|
||||
|
||||
/// An alias to the terminal available for the current platform.
|
||||
///
|
||||
@@ -48,7 +48,7 @@ pub trait Terminal: io::Write {
|
||||
/// While in "cooked" mode a terminal will interpret the incoming data in ways that are useful
|
||||
/// such as waiting for an Enter key press to pass input to the application.
|
||||
fn enter_cooked_mode(&mut self) -> io::Result<()>;
|
||||
fn get_dimensions(&self) -> io::Result<(OneBased, OneBased)>;
|
||||
fn get_dimensions(&self) -> io::Result<WindowSize>;
|
||||
fn event_reader(&self) -> EventReader;
|
||||
/// Checks if there is an `Event` available.
|
||||
///
|
||||
|
@@ -5,7 +5,7 @@ use std::{
|
||||
os::unix::prelude::*,
|
||||
};
|
||||
|
||||
use crate::{event::source::UnixEventSource, Event, EventReader, OneBased};
|
||||
use crate::{event::source::UnixEventSource, Event, EventReader, WindowSize};
|
||||
|
||||
use super::Terminal;
|
||||
|
||||
@@ -81,6 +81,15 @@ fn open_pty() -> io::Result<(FileDescriptor, FileDescriptor)> {
|
||||
Ok((read, write))
|
||||
}
|
||||
|
||||
impl From<termios::Winsize> for WindowSize {
|
||||
fn from(size: termios::Winsize) -> Self {
|
||||
Self {
|
||||
cols: size.ws_col,
|
||||
rows: size.ws_row,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CREDIT: <https://github.com/wezterm/wezterm/blob/a87358516004a652ad840bc1661bdf65ffc89b43/termwiz/src/terminal/unix.rs>
|
||||
// Some discussion, though: Termwiz's terminals combine the terminal interaction (reading
|
||||
// dimensions, reading events, writing bytes, etc.) all in one type. Crossterm splits these
|
||||
@@ -139,12 +148,9 @@ impl Terminal for UnixTerminal {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_dimensions(&self) -> io::Result<(OneBased, OneBased)> {
|
||||
fn get_dimensions(&self) -> io::Result<WindowSize> {
|
||||
let winsize = termios::tcgetwinsize(self.write.get_ref())?;
|
||||
// winsize is already one-based.
|
||||
let rows = OneBased::new(winsize.ws_row).unwrap();
|
||||
let cols = OneBased::new(winsize.ws_col).unwrap();
|
||||
Ok((rows, cols))
|
||||
Ok(winsize.into())
|
||||
}
|
||||
|
||||
fn event_reader(&self) -> EventReader {
|
||||
|
@@ -15,7 +15,7 @@ use windows_sys::Win32::{
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{event::source::WindowsEventSource, Event, EventReader, OneBased};
|
||||
use crate::{event::source::WindowsEventSource, Event, EventReader, OneBased, WindowSize};
|
||||
|
||||
use super::Terminal;
|
||||
|
||||
@@ -243,7 +243,7 @@ impl OutputHandle {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_dimensions(&self) -> io::Result<(OneBased, OneBased)> {
|
||||
fn get_dimensions(&self) -> io::Result<WindowSize> {
|
||||
let mut info: CONSOLE_SCREEN_BUFFER_INFO = unsafe { mem::zeroed() };
|
||||
if unsafe { GetConsoleScreenBufferInfo(self.as_raw_handle(), &mut info) } == 0 {
|
||||
bail!(
|
||||
@@ -253,7 +253,10 @@ impl OutputHandle {
|
||||
}
|
||||
let rows = OneBased::from_zero_based((info.srWindow.Bottom - info.srWindow.Top) as u16);
|
||||
let cols = OneBased::from_zero_based((info.srWindow.Right - info.srWindow.Left) as u16);
|
||||
Ok((rows, cols))
|
||||
Ok(WindowSize {
|
||||
rows: rows.get(),
|
||||
cols: cols.get(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,7 +402,7 @@ impl Terminal for WindowsTerminal {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_dimensions(&self) -> io::Result<(OneBased, OneBased)> {
|
||||
fn get_dimensions(&self) -> io::Result<WindowSize> {
|
||||
// NOTE: setting dimensions should be done by VT instead of `SetConsoleScreenBufferInfo`.
|
||||
// <https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#window-width>
|
||||
self.output.get_ref().get_dimensions()
|
||||
|
Reference in New Issue
Block a user