From 56f531a73f09be31c27866ab13225129097b00c4 Mon Sep 17 00:00:00 2001 From: srothgan <141313976+srothgan@users.noreply.github.com> Date: Thu, 19 Feb 2026 18:38:50 +0100 Subject: [PATCH] chore: migrate to Rust 2024 edition and bump to v0.9.2 (#12) * chore: migrate to Rust 2024 edition and bump to v0.9.2 - Bump edition to 2024 and rust-version to 1.85.0 - Replace f64::log10 with usize::ilog10 in num_digits - Fix clippy lints surfaced by edition bump: repeat_n, derived Default, then_some - Expand watch-check and watch-test aliases to cover all feature paths (crossterm_0_28, no-backend, tuirs variants, serde, arbitrary) - Expand CI test and clippy workflows to full 6/8-entry feature matrices including termion on Ubuntu - Apply rustfmt import reordering from edition 2024 rules * fix: revert turis linux checks --- .cargo/config.toml | 4 ++-- .rustfmt.toml | 2 +- CHANGELOG.md | 11 +++++++++++ Cargo.toml | 6 +++--- examples/editor.rs | 10 +++------- examples/minimal.rs | 4 ++-- examples/password.rs | 4 ++-- examples/popup_placeholder.rs | 4 ++-- examples/single_line.rs | 4 ++-- examples/split.rs | 4 ++-- examples/termion.rs | 10 ++++++---- examples/termwiz.rs | 2 +- examples/tuirs_editor.rs | 10 +++------- examples/tuirs_minimal.rs | 4 ++-- examples/tuirs_termion.rs | 10 ++++++---- examples/variable.rs | 4 ++-- examples/vim.rs | 4 ++-- src/highlight.rs | 5 ++--- src/input/mod.rs | 9 ++------- src/lib.rs | 4 +++- src/scroll.rs | 2 +- src/textarea.rs | 16 +++++++++------- src/util.rs | 2 +- src/widget.rs | 2 +- src/word.rs | 2 +- 25 files changed, 72 insertions(+), 67 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 0a70d3d..094e135 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,3 +1,3 @@ [alias] -watch-check = ["watch", "--why", "-x", "clippy --features=search,termwiz --examples --tests", "-x", "clippy --features tuirs-crossterm,search --no-default-features --examples --tests"] -watch-test = ["watch", "--why", "-x", "test --features=search,termwiz", "-w", "src", "-w", "tests"] +watch-check = ["watch", "--why", "-x", "clippy --features=search,termwiz,serde,arbitrary --examples --tests", "-x", "clippy --no-default-features --features=crossterm_0_28,search,serde,arbitrary --examples --tests", "-x", "clippy --no-default-features --features=no-backend,search,serde,arbitrary --examples --tests", "-x", "clippy --no-default-features --features=tuirs-crossterm,search,serde,arbitrary --examples --tests", "-x", "clippy --no-default-features --features=tuirs-no-backend,search,serde,arbitrary --examples --tests"] +watch-test = ["watch", "--why", "-x", "test --features=search,termwiz,serde,arbitrary", "-x", "test --no-default-features --features=crossterm_0_28,search,serde,arbitrary", "-x", "test --no-default-features --features=tuirs-crossterm,search,serde,arbitrary", "-w", "src", "-w", "tests"] diff --git a/.rustfmt.toml b/.rustfmt.toml index 3a26366..f216078 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1 +1 @@ -edition = "2021" +edition = "2024" diff --git a/CHANGELOG.md b/CHANGELOG.md index 77234c9..9e460ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ + +# [v0.9.2](https://github.com/srothgan/tui-textarea/releases/tag/v0.9.2) - 2026-02-19 + +- Migrate to Rust 2024 edition; bump `rust-version` to `1.85.0`. +- Replace floating-point `num_digits` with `usize::ilog10` for correctness on large values. +- Expand `watch-check` alias to cover `crossterm_0_28`, `no-backend`, `tuirs-crossterm`, `tuirs-no-backend`, `serde`, and `arbitrary` feature paths. +- Expand `watch-test` alias to cover `crossterm_0_28`, `tuirs-crossterm`, `serde`, and `arbitrary` features. +- Expand CI test and clippy workflows to full feature matrix including `termion` and `tuirs-termion` on Ubuntu. + +[Changes][v0.9.2] + # [v0.9.1](https://github.com/srothgan/tui-textarea/releases/tag/v0.9.1) - 2026-02-18 diff --git a/Cargo.toml b/Cargo.toml index d801607..0c7405f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,9 @@ name = "tui-textarea-2" homepage = "https://github.com/srothgan/tui-textarea#readme" repository = "https://github.com/srothgan/tui-textarea" documentation = "https://docs.rs/tui-textarea-2/latest/tui_textarea/" -version = "0.9.1" -edition = "2021" -rust-version = "1.56.1" # for `tui` crate support +version = "0.9.2" +edition = "2024" +rust-version = "1.85.0" # for Rust 2024 edition support authors = ["Simon Peter Rothgang ", "rhysd "] description = """ tui-textarea is a simple yet powerful text editor widget for ratatui and tui-rs. Multi-line diff --git a/examples/editor.rs b/examples/editor.rs index c3f4c4c..ec6bbfb 100644 --- a/examples/editor.rs +++ b/examples/editor.rs @@ -1,13 +1,13 @@ use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; use crossterm::terminal::{ - disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, + EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, }; +use ratatui::Terminal; use ratatui::backend::CrosstermBackend; use ratatui::layout::{Constraint, Direction, Layout}; use ratatui::style::{Color, Modifier, Style}; use ratatui::text::{Line, Span}; use ratatui::widgets::{Block, Borders, Paragraph}; -use ratatui::Terminal; use std::borrow::Cow; use std::env; use std::fmt::Display; @@ -53,11 +53,7 @@ impl SearchBox<'_> { } fn height(&self) -> u16 { - if self.open { - 3 - } else { - 0 - } + if self.open { 3 } else { 0 } } fn input(&mut self, input: Input) -> Option<&'_ str> { diff --git a/examples/minimal.rs b/examples/minimal.rs index dfbe92e..82067a5 100644 --- a/examples/minimal.rs +++ b/examples/minimal.rs @@ -1,10 +1,10 @@ use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; use crossterm::terminal::{ - disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, + EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, }; +use ratatui::Terminal; use ratatui::backend::CrosstermBackend; use ratatui::widgets::{Block, Borders}; -use ratatui::Terminal; use std::io; use tui_textarea::{Input, Key, TextArea}; diff --git a/examples/password.rs b/examples/password.rs index 1d182b8..7f621d9 100644 --- a/examples/password.rs +++ b/examples/password.rs @@ -1,12 +1,12 @@ use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; use crossterm::terminal::{ - disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, + EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, }; +use ratatui::Terminal; use ratatui::backend::CrosstermBackend; use ratatui::layout::{Constraint, Layout}; use ratatui::style::{Color, Style}; use ratatui::widgets::{Block, Borders}; -use ratatui::Terminal; use std::io; use tui_textarea::{Input, Key, TextArea}; diff --git a/examples/popup_placeholder.rs b/examples/popup_placeholder.rs index 136de5c..3099bbc 100644 --- a/examples/popup_placeholder.rs +++ b/examples/popup_placeholder.rs @@ -1,12 +1,12 @@ use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; use crossterm::terminal::{ - disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, + EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, }; +use ratatui::Terminal; use ratatui::backend::CrosstermBackend; use ratatui::layout::Rect; use ratatui::style::{Color, Style}; use ratatui::widgets::{Block, Borders}; -use ratatui::Terminal; use std::io; use tui_textarea::{Input, Key, TextArea}; diff --git a/examples/single_line.rs b/examples/single_line.rs index d5f36ef..40d0e6c 100644 --- a/examples/single_line.rs +++ b/examples/single_line.rs @@ -1,12 +1,12 @@ use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; use crossterm::terminal::{ - disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, + EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, }; +use ratatui::Terminal; use ratatui::backend::CrosstermBackend; use ratatui::layout::{Constraint, Layout}; use ratatui::style::{Color, Style}; use ratatui::widgets::{Block, Borders}; -use ratatui::Terminal; use std::io; use tui_textarea::{Input, Key, TextArea}; diff --git a/examples/split.rs b/examples/split.rs index 78ebb23..98db439 100644 --- a/examples/split.rs +++ b/examples/split.rs @@ -1,12 +1,12 @@ use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; use crossterm::terminal::{ - disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, + EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, }; +use ratatui::Terminal; use ratatui::backend::CrosstermBackend; use ratatui::layout::{Constraint, Direction, Layout}; use ratatui::style::{Color, Modifier, Style}; use ratatui::widgets::{Block, Borders}; -use ratatui::Terminal; use std::io; use tui_textarea::{Input, Key, TextArea}; diff --git a/examples/termion.rs b/examples/termion.rs index cc8296b..0ef3dc8 100644 --- a/examples/termion.rs +++ b/examples/termion.rs @@ -1,6 +1,6 @@ +use ratatui::Terminal; use ratatui::backend::TermionBackend; use ratatui::widgets::{Block, Borders}; -use ratatui::Terminal; use std::error::Error; use std::io; use std::sync::mpsc; @@ -32,9 +32,11 @@ fn main() -> Result<(), Box> { keys_tx.send(Event::Term(event)).unwrap(); } }); - thread::spawn(move || loop { - tx.send(Event::Tick).unwrap(); - thread::sleep(Duration::from_millis(100)); + thread::spawn(move || { + loop { + tx.send(Event::Tick).unwrap(); + thread::sleep(Duration::from_millis(100)); + } }); rx }; diff --git a/examples/termwiz.rs b/examples/termwiz.rs index 79355d3..d4d4ec5 100644 --- a/examples/termwiz.rs +++ b/examples/termwiz.rs @@ -1,6 +1,6 @@ +use ratatui::Terminal; use ratatui::backend::TermwizBackend; use ratatui::widgets::{Block, Borders}; -use ratatui::Terminal; use std::error::Error; use std::time::Duration; use termwiz::input::InputEvent; diff --git a/examples/tuirs_editor.rs b/examples/tuirs_editor.rs index 792c2c0..9c2c96a 100644 --- a/examples/tuirs_editor.rs +++ b/examples/tuirs_editor.rs @@ -3,7 +3,7 @@ use crossterm_025 as crossterm; use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; use crossterm::terminal::{ - disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, + EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, }; use std::borrow::Cow; use std::env; @@ -12,12 +12,12 @@ use std::fs; use std::io; use std::io::{BufRead, Write}; use std::path::PathBuf; +use tui::Terminal; use tui::backend::CrosstermBackend; use tui::layout::{Constraint, Direction, Layout}; use tui::style::{Color, Modifier, Style}; use tui::text::{Span, Spans}; use tui::widgets::{Block, Borders, Paragraph}; -use tui::Terminal; use tui_textarea::{CursorMove, Input, Key, TextArea}; macro_rules! error { @@ -56,11 +56,7 @@ impl SearchBox<'_> { } fn height(&self) -> u16 { - if self.open { - 3 - } else { - 0 - } + if self.open { 3 } else { 0 } } fn input(&mut self, input: Input) -> Option<&'_ str> { diff --git a/examples/tuirs_minimal.rs b/examples/tuirs_minimal.rs index 5e5cc27..245e8b5 100644 --- a/examples/tuirs_minimal.rs +++ b/examples/tuirs_minimal.rs @@ -3,12 +3,12 @@ use crossterm_025 as crossterm; use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; use crossterm::terminal::{ - disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, + EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, }; use std::io; +use tui::Terminal; use tui::backend::CrosstermBackend; use tui::widgets::{Block, Borders}; -use tui::Terminal; use tui_textarea::{Input, Key, TextArea}; fn main() -> io::Result<()> { diff --git a/examples/tuirs_termion.rs b/examples/tuirs_termion.rs index e398e3d..ea50bf5 100644 --- a/examples/tuirs_termion.rs +++ b/examples/tuirs_termion.rs @@ -10,9 +10,9 @@ use termion::event::Event as TermEvent; use termion::input::{MouseTerminal, TermRead}; use termion::raw::IntoRawMode; use termion::screen::AlternateScreen; +use tui::Terminal; use tui::backend::TermionBackend; use tui::widgets::{Block, Borders}; -use tui::Terminal; use tui_textarea::{Input, Key, TextArea}; enum Event { @@ -36,9 +36,11 @@ fn main() -> Result<(), Box> { keys_tx.send(Event::Term(event)).unwrap(); } }); - thread::spawn(move || loop { - tx.send(Event::Tick).unwrap(); - thread::sleep(Duration::from_millis(100)); + thread::spawn(move || { + loop { + tx.send(Event::Tick).unwrap(); + thread::sleep(Duration::from_millis(100)); + } }); rx }; diff --git a/examples/variable.rs b/examples/variable.rs index 42fb93a..e112b63 100644 --- a/examples/variable.rs +++ b/examples/variable.rs @@ -1,11 +1,11 @@ use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; use crossterm::terminal::{ - disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, + EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, }; +use ratatui::Terminal; use ratatui::backend::CrosstermBackend; use ratatui::layout::{Constraint, Direction, Layout}; use ratatui::widgets::{Block, Borders}; -use ratatui::Terminal; use std::cmp; use std::io; use tui_textarea::{Input, Key, TextArea}; diff --git a/examples/vim.rs b/examples/vim.rs index 42da7ed..861331e 100644 --- a/examples/vim.rs +++ b/examples/vim.rs @@ -1,11 +1,11 @@ use crossterm::event::{DisableMouseCapture, EnableMouseCapture}; use crossterm::terminal::{ - disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, + EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, }; +use ratatui::Terminal; use ratatui::backend::CrosstermBackend; use ratatui::style::{Color, Modifier, Style}; use ratatui::widgets::{Block, Borders}; -use ratatui::Terminal; use std::env; use std::fmt; use std::fs; diff --git a/src/highlight.rs b/src/highlight.rs index ad8c686..7cd6b0a 100644 --- a/src/highlight.rs +++ b/src/highlight.rs @@ -5,7 +5,6 @@ use crate::util::{num_digits, spaces}; use ratatui_core::text::Line; use std::borrow::Cow; use std::cmp::Ordering; -use std::iter; #[cfg(feature = "tuirs")] use tui::text::Spans as Line; use unicode_width::UnicodeWidthChar as _; @@ -64,7 +63,7 @@ impl DisplayTextBuilder { fn build<'s>(&mut self, s: &'s str) -> Cow<'s, str> { if let Some(ch) = self.mask { // Note: We don't need to track width on masking text since width of tab character is fixed - let masked = iter::repeat(ch).take(s.chars().count()).collect(); + let masked = std::iter::repeat_n(ch, s.chars().count()).collect(); return Cow::Owned(masked); } @@ -100,7 +99,7 @@ impl DisplayTextBuilder { pub struct LineHighlighter<'a> { line: &'a str, spans: Vec>, - boundaries: Vec<(Boundary, usize)>, // TODO: Consider smallvec + boundaries: Vec<(Boundary, usize)>, style_begin: Style, cursor_at_end: bool, cursor_style: Style, diff --git a/src/input/mod.rs b/src/input/mod.rs index 77dc296..815b44e 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -18,7 +18,7 @@ use serde::{Deserialize, Serialize}; /// /// This type is marked as `#[non_exhaustive]` since more keys may be supported in the future. #[non_exhaustive] -#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Hash, Eq)] #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Key { @@ -63,15 +63,10 @@ pub enum Key { /// Virtual key to scroll up by mouse MouseScrollUp, /// An invalid key input (this key is always ignored by [`TextArea`](crate::TextArea)) + #[default] Null, } -impl Default for Key { - fn default() -> Self { - Key::Null - } -} - /// Backend-agnostic key input type. /// /// When `crossterm`, `termion`, `termwiz` features are enabled, converting respective key input types into this diff --git a/src/lib.rs b/src/lib.rs index 2c6172f..b993075 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,9 @@ #![doc = include_str!("../README.md")] #[cfg(all(feature = "ratatui", feature = "tuirs"))] -compile_error!("ratatui support and tui-rs support are exclusive. only one of them can be enabled at the same time. see https://github.com/rhysd/tui-textarea#installation"); +compile_error!( + "ratatui support and tui-rs support are exclusive. only one of them can be enabled at the same time. see https://github.com/rhysd/tui-textarea#installation" +); mod cursor; mod highlight; diff --git a/src/scroll.rs b/src/scroll.rs index 6dc7ce5..2c46e5c 100644 --- a/src/scroll.rs +++ b/src/scroll.rs @@ -192,10 +192,10 @@ mod tests { // Separate tests for tui-rs support #[test] fn delta() { + use crate::TextArea; use crate::ratatui::buffer::Buffer; use crate::ratatui::layout::Rect; use crate::ratatui::widgets::Widget as _; - use crate::TextArea; let mut textarea: TextArea = (0..20).map(|i| i.to_string()).collect(); let r = Rect { diff --git a/src/textarea.rs b/src/textarea.rs index 8892ef3..1ac10fb 100644 --- a/src/textarea.rs +++ b/src/textarea.rs @@ -8,12 +8,12 @@ use crate::ratatui::widgets::{Block, Widget}; use crate::scroll::Scrolling; #[cfg(feature = "search")] use crate::search::Search; -use crate::util::{num_digits, spaces, Pos}; +use crate::util::{Pos, num_digits, spaces}; use crate::widget::Viewport; use crate::word::{find_word_exclusive_end_forward, find_word_start_backward}; use crate::wrap::{ - cursor_at_visual_row, cursor_visual_row, effective_wrap_width, wrapped_rows, WrapMode, - WrappedLine, + WrapMode, WrappedLine, cursor_at_visual_row, cursor_visual_row, effective_wrap_width, + wrapped_rows, }; #[cfg(feature = "ratatui")] use ratatui_core::text::Line; @@ -889,10 +889,12 @@ impl<'a> TextArea<'a> { return; } - let mut deleted = vec![self.lines[start.row] - .drain(start.offset..) - .as_str() - .to_string()]; + let mut deleted = vec![ + self.lines[start.row] + .drain(start.offset..) + .as_str() + .to_string(), + ]; deleted.extend(self.lines.drain(start.row + 1..end.row)); if start.row + 1 < self.lines.len() { let mut last_line = self.lines.remove(start.row + 1); diff --git a/src/util.rs b/src/util.rs index f001290..4072f1a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -4,7 +4,7 @@ pub fn spaces(size: u8) -> &'static str { } pub fn num_digits(i: usize) -> u8 { - f64::log10(i as f64) as u8 + 1 + if i == 0 { 1 } else { i.ilog10() as u8 + 1 } } #[derive(Debug, Clone)] diff --git a/src/widget.rs b/src/widget.rs index cd9f492..b8cd552 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -4,7 +4,7 @@ use crate::ratatui::text::{Span, Text}; use crate::ratatui::widgets::{Paragraph, Widget}; use crate::textarea::TextArea; use crate::util::num_digits; -use crate::wrap::{cursor_visual_row, effective_wrap_width, wrapped_rows, WrapMode}; +use crate::wrap::{WrapMode, cursor_visual_row, effective_wrap_width, wrapped_rows}; use portable_atomic::{AtomicU64, Ordering}; #[cfg(feature = "ratatui")] use ratatui_core::text::Line; diff --git a/src/word.rs b/src/word.rs index e0d7b36..c70a56f 100644 --- a/src/word.rs +++ b/src/word.rs @@ -79,5 +79,5 @@ pub fn find_word_start_backward(line: &str, start_col: usize) -> Option { } cur = next; } - (cur != CharKind::Space).then(|| 0) + (cur != CharKind::Space).then_some(0) }