Compare commits

..

5 commits

Author SHA1 Message Date
57aa8c5930 Bump version to 0.3.4 2025-03-08 19:30:44 +01:00
e3af509358 Add bell widget 2025-03-08 19:10:29 +01:00
89b4595ed9 Print bell character 2025-03-08 19:05:38 +01:00
96b2e13c4a Bump version to 0.3.3 2025-02-28 14:30:45 +01:00
712c1537ad Fix incorrect width estimation of ascii control characters 2025-02-28 14:29:53 +01:00
7 changed files with 87 additions and 5 deletions

View file

@ -13,6 +13,17 @@ Procedure when bumping the version number:
## Unreleased ## Unreleased
## v0.3.4 - 2025-03-8
### Added
- `Frame::set_bell` to print a bell character when the frame is displayed
- `widgets::bell`
## v0.3.3 - 2025-02-28
### Fixed
- Rendering glitches in unicode-based with estimation
## v0.3.2 - 2025-02-23 ## v0.3.2 - 2025-02-23
### Added ### Added

View file

@ -1,6 +1,6 @@
[package] [package]
name = "toss" name = "toss"
version = "0.3.2" version = "0.3.4"
edition = "2021" edition = "2021"
[dependencies] [dependencies]

View file

@ -8,6 +8,7 @@ pub struct Frame {
pub(crate) widthdb: WidthDb, pub(crate) widthdb: WidthDb,
pub(crate) buffer: Buffer, pub(crate) buffer: Buffer,
pub(crate) title: Option<String>, pub(crate) title: Option<String>,
pub(crate) bell: bool,
} }
impl Frame { impl Frame {
@ -48,6 +49,10 @@ impl Frame {
self.title = title; self.title = title;
} }
pub fn set_bell(&mut self, bell: bool) {
self.bell = bell;
}
pub fn widthdb(&mut self) -> &mut WidthDb { pub fn widthdb(&mut self) -> &mut WidthDb {
&mut self.widthdb &mut self.widthdb
} }

View file

@ -8,7 +8,7 @@ use crossterm::event::{
DisableBracketedPaste, EnableBracketedPaste, KeyboardEnhancementFlags, DisableBracketedPaste, EnableBracketedPaste, KeyboardEnhancementFlags,
PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags,
}; };
use crossterm::style::{PrintStyledContent, StyledContent}; use crossterm::style::{Print, PrintStyledContent, StyledContent};
use crossterm::terminal::{ use crossterm::terminal::{
BeginSynchronizedUpdate, Clear, ClearType, EndSynchronizedUpdate, EnterAlternateScreen, BeginSynchronizedUpdate, Clear, ClearType, EndSynchronizedUpdate, EnterAlternateScreen,
LeaveAlternateScreen, SetTitle, LeaveAlternateScreen, SetTitle,
@ -274,6 +274,7 @@ impl Terminal {
self.draw_differences()?; self.draw_differences()?;
self.update_cursor()?; self.update_cursor()?;
self.update_title()?; self.update_title()?;
self.ring_bell()?;
Ok(()) Ok(())
} }
@ -315,4 +316,12 @@ impl Terminal {
} }
Ok(()) Ok(())
} }
fn ring_bell(&mut self) -> io::Result<()> {
if self.frame.bell {
self.out.queue(Print('\x07'))?;
}
self.frame.bell = false;
Ok(())
}
} }

View file

@ -1,4 +1,5 @@
pub mod background; pub mod background;
pub mod bell;
pub mod border; pub mod border;
pub mod boxed; pub mod boxed;
pub mod cursor; pub mod cursor;
@ -16,6 +17,7 @@ pub mod text;
pub mod title; pub mod title;
pub use background::*; pub use background::*;
pub use bell::*;
pub use border::*; pub use border::*;
pub use boxed::*; pub use boxed::*;
pub use cursor::*; pub use cursor::*;

55
src/widgets/bell.rs Normal file
View file

@ -0,0 +1,55 @@
use crate::{Frame, Size, Widget, WidthDb};
///////////
// State //
///////////
#[derive(Debug, Default, Clone)]
pub struct BellState {
// Whether the bell should be rung the next time the widget is displayed.
pub ring: bool,
}
impl BellState {
pub fn new() -> Self {
Self::default()
}
pub fn widget(&mut self) -> Bell<'_> {
Bell { state: self }
}
}
////////////
// Widget //
////////////
#[derive(Debug)]
pub struct Bell<'a> {
state: &'a mut BellState,
}
impl Bell<'_> {
pub fn state(&mut self) -> &mut BellState {
self.state
}
}
impl<E> Widget<E> for Bell<'_> {
fn size(
&self,
_widthdb: &mut WidthDb,
_max_width: Option<u16>,
_max_height: Option<u16>,
) -> Result<Size, E> {
Ok(Size::ZERO)
}
fn draw(self, frame: &mut Frame) -> Result<(), E> {
if self.state.ring {
frame.set_bell(true);
self.state.ring = false
}
Ok(())
}
}

View file

@ -88,10 +88,10 @@ impl WidthDb {
.try_into() .try_into()
.unwrap_or(u8::MAX), .unwrap_or(u8::MAX),
// The unicode width crate considers newlines to have a width of 1 // The unicode width crate considers control chars to have a width
// while the rendering code expects it to have a width of 0. // of 1 even though they usually have a width of 0 when displayed.
WidthEstimationMethod::Unicode => grapheme WidthEstimationMethod::Unicode => grapheme
.split('\n') .split(|c: char| c.is_ascii_control())
.map(|s| s.width()) .map(|s| s.width())
.sum::<usize>() .sum::<usize>()
.try_into() .try_into()