1
0
зеркало из https://github.com/glebtv/tui-textarea.git synced 2026-08-28 11:36:17 +03:00

chore: ratatui 0.30 maintenance + collaboration baseline (#1)

Этот коммит содержится в:
srothgan
2026-02-18 11:46:03 +01:00
коммит произвёл GitHub
родитель 4d18622eea
Коммит 4689076df5
20 изменённых файлов: 289 добавлений и 192 удалений

27
.github/ISSUE_TEMPLATE/bug_report.md поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,27 @@
---
name: Bug report
about: Report a defect or regression
title: "[bug] "
labels: ["bug"]
assignees: []
---
## Summary
Clear and concise description of the bug.
## Reproduction
1. Step one
2. Step two
3. Observe failure
## Expected Behavior
What should happen instead.
## Environment
- OS:
- Rust version:
- tui-textarea version:
- ratatui version:
## Additional Context
Logs, screenshots, and relevant snippets.

19
.github/ISSUE_TEMPLATE/compatibility_request.md поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,19 @@
---
name: Compatibility request
about: Request compatibility with ratatui/crossterm/etc.
title: "[compat] "
labels: ["compat-ratatui"]
assignees: []
---
## Compatibility Target
Library and target version (for example ratatui 0.31).
## Current Behavior
What fails today?
## Expected Outcome
What should work after this request is addressed?
## Risks
Any known API or behavior breakage concerns.

5
.github/ISSUE_TEMPLATE/config.yml поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Security report
url: https://github.com/srothgan/tui-textarea/security/advisories/new
about: Please report security vulnerabilities privately.

19
.github/ISSUE_TEMPLATE/feature_request.md поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,19 @@
---
name: Feature request
about: Propose an enhancement
title: "[feature] "
labels: ["enhancement"]
assignees: []
---
## Problem
What problem are you trying to solve?
## Proposed Change
Describe the API or behavior you want.
## Alternatives
What alternatives did you consider?
## Additional Context
Any examples, references, or prior art.

25
.github/branch-protection-main.json поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,25 @@
{
"required_status_checks": {
"strict": true,
"contexts": [
"cargo fmt --check",
"cargo clippy -- -D warnings",
"cargo check",
"cargo test"
]
},
"enforce_admins": true,
"required_pull_request_reviews": {
"dismiss_stale_reviews": true,
"required_approving_review_count": 1,
"require_code_owner_reviews": false
},
"restrictions": null,
"required_conversation_resolution": true,
"allow_force_pushes": false,
"allow_deletions": false,
"block_creations": false,
"required_linear_history": false,
"lock_branch": false,
"allow_fork_syncing": true
}

16
.github/dependabot.yml поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,16 @@
version: 2
updates:
- package-ecosystem: cargo
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
groups:
patch-and-minor:
update-types:
- patch
- minor
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly

14
.github/pull_request_template.md поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,14 @@
## Problem
Describe the user-visible problem this PR solves.
## Change Summary
List the key code and behavior changes.
## Test Evidence
- [ ] `cargo fmt --check`
- [ ] `cargo clippy --all-targets -- -D warnings`
- [ ] `cargo check`
- [ ] `cargo test`
## Breaking Changes
Describe any API or behavior changes that may break existing users.

121
.github/workflows/ci.yml поставляемый
Просмотреть файл

@@ -1,79 +1,62 @@
name: CI
on: [push, pull_request]
env:
CARGO_TERM_COLOR: always
on:
pull_request:
push:
branches:
- main
jobs:
unit-test:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
fail-fast: true
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Run tests on Linux or macOS
run: |
cargo llvm-cov --color always --lcov --output-path lcov.info --features=search,termwiz,termion,serde,arbitrary
cargo llvm-cov --color always --no-run
if: ${{ matrix.os != 'windows-latest' }}
- name: Run tests on Windows
run: |
cargo llvm-cov --color always --lcov --output-path lcov.info --features=search,termwiz,serde,arbitrary
cargo llvm-cov --color always --no-run
if: ${{ matrix.os == 'windows-latest' }}
- run: cargo test --no-default-features --features=tuirs-crossterm,search -- --skip .rs
- run: cargo test --no-default-features --features=tuirs-termion,search -- --skip .rs
if: ${{ matrix.os != 'windows-latest' }}
- run: cargo test --no-default-features --features=no-backend,search -- --skip .rs
- run: cargo test --no-default-features --features=tuirs-no-backend,search -- --skip .rs
- uses: codecov/codecov-action@v4
with:
files: lcov.info
token: ${{ secrets.CODECOV_TOKEN }}
lint:
cargo-fmt:
name: cargo fmt --check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy,rustfmt
components: rustfmt
- uses: Swatinem/rust-cache@v2
- run: cargo fmt -- --check
- run: cargo clippy --examples --tests -- -D warnings
- run: cargo clippy --examples --tests --features search,serde -- -D warnings
- run: cargo clippy --examples --tests --no-default-features --features termion -- -D warnings
- run: cargo clippy --examples --tests --no-default-features --features termion,search -- -D warnings
- run: cargo clippy --examples --tests --no-default-features --features termwiz -- -D warnings
- run: cargo clippy --examples --tests --no-default-features --features termwiz,search -- -D warnings
- run: cargo clippy --examples --tests --no-default-features --features no-backend -- -D warnings
- run: cargo clippy --examples --tests --no-default-features --features no-backend,search -- -D warnings
- run: cargo clippy --examples --tests --no-default-features --features tuirs-crossterm -- -D warnings
- run: cargo clippy --examples --tests --no-default-features --features tuirs-crossterm,search -- -D warnings
- run: cargo clippy --examples --tests --no-default-features --features tuirs-termion -- -D warnings
- run: cargo clippy --examples --tests --no-default-features --features tuirs-termion,search -- -D warnings
- run: cargo clippy --examples --tests --no-default-features --features tuirs-no-backend -- -D warnings
- run: cargo clippy --examples --tests --no-default-features --features tuirs-no-backend,search -- -D warnings
- run: cargo rustdoc --features=search,termwiz,termion,serde -p tui-textarea -- -D warnings
cargo-doc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- name: Run `cargo rustdoc` with same configuration as docs.rs
run: |
set -e
md="$(cargo metadata --format-version=1 | jq '.packages[] | select(.name=="tui-textarea") | .metadata.docs.rs')"
rustdoc_args="$(echo "$md" | jq -r '.["rustdoc-args"] | join(" ")') -D warnings"
features="$(echo "$md" | jq -r '.features | join(",")')"
- run: cargo fmt --check
set -x
for target in $(echo "$md" | jq -r '.targets | join(" ")')
do
rustup target add "$target"
cargo rustdoc -p tui-textarea "--features=$features" "--target=$target" -- $rustdoc_args
done
cargo-clippy:
name: cargo clippy -- -D warnings
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --all-targets -- -D warnings
cargo-check:
name: cargo check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo check
cargo-test:
name: cargo test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo test
cross-platform:
name: cross-platform default (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo check
- run: cargo test

47
.github/workflows/release.yml поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,47 @@
name: Release
on:
workflow_dispatch:
inputs:
version:
description: "Cargo.toml version to release (for example 0.7.0)"
required: true
type: string
publish:
description: "Publish to crates.io (false runs dry validation only)"
required: true
default: false
type: boolean
permissions:
contents: read
jobs:
release:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Verify requested version matches Cargo.toml
shell: bash
run: |
actual="$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n1)"
if [[ -z "$actual" ]]; then
echo "Could not parse version from Cargo.toml"
exit 1
fi
if [[ "$actual" != "${{ inputs.version }}" ]]; then
echo "Requested version ${{ inputs.version }} does not match Cargo.toml version $actual"
exit 1
fi
- name: Validate package
run: cargo package
- name: Run full test suite
run: cargo test
- name: Publish to crates.io
if: ${{ inputs.publish }}
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish --locked --token "$CARGO_REGISTRY_TOKEN"

Просмотреть файл

@@ -1,110 +1,24 @@
## Reporting an issue
# Contributing
For reporting a bug, please make sure your report includes the following points.
## Workflow
- Work from short-lived branches (`feature/*`, `fix/*`, `chore/*`).
- Open a pull request into `main`.
- Keep each PR focused and reviewable.
- How to reproduce it
- What text the textarea contained as pre-condition
- What operations you did
- What was the expected behavior
- What was the actual behavior
- Environment
- Your terminal
- Rust version
- `ratatui` or `tui` crate version
- Enabled features of `tui-textarea` crate
## Quality Bar
- `cargo fmt --check` must pass.
- `cargo clippy --all-targets -- -D warnings` must pass.
- `cargo check` and `cargo test` must pass.
- Do not use `--all-features` for this crate because backend feature sets are mutually exclusive.
An example of bug report: https://github.com/rhysd/tui-textarea/issues/1
## Reviews
- At least one approval is required before merge.
- Keep PR descriptions explicit about behavior changes and compatibility impact.
## Submitting a pull request
## Dependency Changes
- Prefer patch/minor updates in batches.
- Handle major updates one crate at a time with tests after each update.
Please ensure that all tests and linter checks passed on your branch before creating a PR which modifies some source files.
To run tests:
```sh
cargo test --features=search
```
To run linters:
```sh
cargo clippy --features=search,termwiz,termion --tests --examples
cargo clippy --features=tuirs-crossterm,tuirs-termion,search --no-default-features --tests --examples
cargo fmt -- --check
```
Note: On Windows, remove `termion` and `tuirs-termion` features from `--features` argument since termion doesn't support Windows.
If you use [cargo-watch][], `cargo watch-check` and `cargo watch-test` aliases are useful to run checks/tests automatically
on files being changed.
### Code coverage
Code coverage is monitored on [codecov][].
https://app.codecov.io/gh/rhysd/tui-textarea
When you implement some new feature, consider to add new unit tests which cover your implementation.
## Print debugging
Since this crate uses stdout, `println!` is not available for debugging. Instead, stderr through [`eprintln!`][eprintln]
or [`dbg!`][dbg] are useful.
At first, add prints where you want to debug:
```rust
eprintln!("some value is {:?}", some_value);
dbg!(&some_value);
```
Then redirect stderr to some file:
```sh
cargo run --example minimal 2>debug.txt
```
Then the debug prints are output to the `debug.txt` file. If timing is important or you want to see the output in real-time,
it would be useful to monitor the file content with `tail` command in another terminal window.
```sh
# In a terminal, reproduce the issue
cargo run --example minimal 2>debug.txt
# In another terminal, run `tail` command to monitor the content
tail -F debug.txt
```
## Running a fuzzer
To run fuzzing tests, [cargo-fuzz][] and Rust nightly toolchain are necessary.
```sh
# Show list of fuzzing targets
cargo +nightly fuzz list
# Run 'edit' fuzzing test case
cargo +nightly fuzz run edit
```
## Running benchmark suites
Benchmarks are available using [Criterion.rs][criterion].
To separate `criterion` crate dependency, benchmark suites are separated as another crate in [bench/](./bench).
To run benchmarks:
```sh
cd ./bench
cargo bench --benches
```
See [README in bench/](./bench/README.md) for more details.
[cargo-watch]: https://crates.io/crates/cargo-watch
[cargo-fuzz]: https://github.com/rust-fuzz/cargo-fuzz
[criterion]: https://github.com/bheisler/criterion.rs
[eprintln]: https://doc.rust-lang.org/std/macro.eprintln.html
[dbg]: https://doc.rust-lang.org/std/macro.dbg.html
[codecov]: https://about.codecov.io/
## Commit Messages
- Use clear, imperative commit messages.
- Mention external references where relevant (for example `upstream PR #118`).

Просмотреть файл

@@ -19,10 +19,11 @@ include = ["/src", "/examples", "/tests", "/README.md", "/LICENSE.txt"]
[features]
default = ["crossterm"]
# Features to use ratatui
ratatui = ["dep:ratatui"]
crossterm = ["ratatui", "dep:crossterm", "ratatui/crossterm"]
termion = ["ratatui", "dep:termion", "ratatui/termion"]
termwiz = ["ratatui", "dep:termwiz", "ratatui/termwiz"]
ratatui = ["dep:ratatui-core", "dep:ratatui-widgets"]
crossterm = ["ratatui", "dep:crossterm"]
crossterm_0_28 = ["ratatui", "dep:crossterm-028"]
termion = ["ratatui", "dep:termion"]
termwiz = ["ratatui", "dep:termwiz"]
no-backend = ["ratatui"]
# Features to use tui-rs
tuirs = ["dep:tui"]
@@ -36,13 +37,15 @@ arbitrary = ["dep:arbitrary"]
[dependencies]
arbitrary = { version = "1", features = ["derive"], optional = true }
crossterm = { package = "crossterm", version = "0.28", optional = true }
crossterm = { package = "crossterm", version = "0.29", optional = true }
crossterm-028 = { package = "crossterm", version = "0.28", optional = true }
crossterm-025 = { package = "crossterm", version = "0.25", optional = true }
ratatui = { version = "0.29.0", default-features = false, optional = true }
ratatui-core = { version = "0.1.0", default-features = false, optional = true }
ratatui-widgets = { version = "0.3.0", default-features = false, optional = true }
regex = { version = "1", optional = true }
termion = { version = "4.0", optional = true }
termion-15 = { package = "termion", version = "1.5", optional = true }
termwiz = { version = "0.22.0", optional = true }
termwiz = { version = "0.23.0", optional = true }
tui = { version = "0.19", default-features = false, optional = true }
unicode-width = "0.2.0"
serde = { version = "1", optional = true , features = ["derive"] }
@@ -107,6 +110,8 @@ lto = "thin"
[dev-dependencies]
serde_json = "1.0.120"
# Ratatui with all backends enabled for tests and examples
ratatui = {version = "0.30.0", features=["crossterm", "termion", "termwiz"]} # Used by examples
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

Просмотреть файл

@@ -729,3 +729,4 @@ tui-textarea is distributed under [The MIT License](./LICENSE.txt).
[regex]: https://docs.rs/regex/latest/regex/
[serde]: https://crates.io/crates/serde
[serde_json]: https://crates.io/crates/serde_json
> Maintained fork notice: this repository is maintained under `srothgan/tui-textarea` to keep compatibility updates moving (including ratatui 0.30+ support and maintenance fixes).

Просмотреть файл

@@ -10,7 +10,7 @@ bench = false
[dependencies]
tui-textarea = { path = "..", features = ["no-backend", "search"] }
ratatui = { version = "0.29.0", default-features = false }
ratatui = { version = "0.30.0", default-features = false }
[dev-dependencies]
criterion = "0.5"

Просмотреть файл

@@ -4,6 +4,7 @@
use ratatui::backend::{Backend, WindowSize};
use ratatui::buffer::Cell;
use ratatui::layout::{Position, Size};
use ratatui::prelude::backend::ClearType;
use ratatui::Terminal;
use std::io;
use tui_textarea::TextArea;
@@ -40,6 +41,8 @@ impl Default for DummyBackend {
}
impl Backend for DummyBackend {
type Error = io::Error;
#[inline]
fn draw<'a, I>(&mut self, _content: I) -> io::Result<()>
where
@@ -74,6 +77,11 @@ impl Backend for DummyBackend {
Ok(())
}
#[inline]
fn clear_region(&mut self, _clear_type: ClearType) -> io::Result<()> {
Ok(())
}
#[inline]
fn size(&self) -> io::Result<Size> {
Ok(Size {

Просмотреть файл

@@ -2,7 +2,7 @@ use crate::ratatui::style::Style;
use crate::ratatui::text::Span;
use crate::util::{num_digits, spaces};
#[cfg(feature = "ratatui")]
use ratatui::text::Line;
use ratatui_core::text::Line;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::iter;

Просмотреть файл

@@ -61,7 +61,7 @@ impl EditKind {
// Remove middle lines of chunk
let mut last_line = lines
.drain(after.row + 1..after.row + c.len())
.last()
.next_back()
.unwrap();
// Remove last line of chunk
last_line.drain(..c[c.len() - 1].len());

Просмотреть файл

@@ -1,4 +1,8 @@
#[cfg(any(feature = "crossterm", feature = "tuirs-crossterm"))]
#[cfg(any(
feature = "crossterm",
feature = "crossterm_0_28",
feature = "tuirs-crossterm"
))]
mod crossterm;
#[cfg(any(feature = "termion", feature = "tuirs-termion"))]
mod termion;

Просмотреть файл

@@ -21,15 +21,25 @@ mod word;
#[cfg(feature = "ratatui")]
#[allow(clippy::single_component_path_imports)]
use ratatui;
mod ratatui {
// Best effort to reproduce ratatui 0.29 module layout to keep compatibility with tui module layout
pub use ratatui_core::{buffer, layout, style, text};
pub mod widgets {
pub use ratatui_core::widgets::*;
pub use ratatui_widgets::{block::Block, paragraph::Paragraph};
}
}
#[cfg(feature = "tuirs")]
use tui as ratatui;
#[cfg(feature = "crossterm")]
#[cfg(all(feature = "crossterm", not(feature = "crossterm_0_28")))]
#[allow(clippy::single_component_path_imports)]
use crossterm;
#[cfg(feature = "tuirs-crossterm")]
use crossterm_025 as crossterm;
#[cfg(feature = "crossterm_0_28")]
#[allow(clippy::single_component_path_imports)]
use crossterm_028 as crossterm;
#[cfg(feature = "termion")]
#[allow(clippy::single_component_path_imports)]

Просмотреть файл

@@ -12,7 +12,7 @@ use crate::util::{spaces, Pos};
use crate::widget::Viewport;
use crate::word::{find_word_exclusive_end_forward, find_word_start_backward};
#[cfg(feature = "ratatui")]
use ratatui::text::Line;
use ratatui_core::text::Line;
use std::cmp::Ordering;
use std::fmt;
#[cfg(feature = "tuirs")]
@@ -78,8 +78,8 @@ impl fmt::Display for YankText {
/// println!("Lines: {:?}", textarea.lines());
/// ```
///
/// It implements [`ratatui::widgets::Widget`] trait so it can be rendered to a terminal screen via
/// [`ratatui::Frame::render_widget`] method.
/// It implements [`ratatui_core::widgets::Widget`] trait so it can be rendered to a terminal screen via
/// [`ratatui_core::terminal::Frame::render_widget`] method.
/// ```no_run
/// use ratatui::backend::CrosstermBackend;
/// use ratatui::layout::{Constraint, Direction, Layout};
@@ -1616,7 +1616,7 @@ impl<'a> TextArea<'a> {
}
/// Build a ratatui (or tui-rs) widget to render the current state of the textarea. The widget instance returned
/// from this method can be rendered with [`ratatui::Frame::render_widget`].
/// from this method can be rendered with [`ratatui_core::terminal::Frame::render_widget`].
///
/// This method was deprecated at v0.5.3 and is no longer necessary. Instead you can directly pass `&TextArea`
/// reference to the `Frame::render_widget` method call.

Просмотреть файл

@@ -5,7 +5,7 @@ use crate::ratatui::widgets::{Paragraph, Widget};
use crate::textarea::TextArea;
use crate::util::num_digits;
#[cfg(feature = "ratatui")]
use ratatui::text::Line;
use ratatui_core::text::Line;
use std::cmp;
use std::sync::atomic::{AtomicU64, Ordering};
#[cfg(feature = "tuirs")]