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)
}