Compare commits
37 Commits
ratatui-te
...
js/fix-lay
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e602369afe | ||
|
|
bce6604379 | ||
|
|
c8d5d385b3 | ||
|
|
3fe3fe316e | ||
|
|
0f10944ca0 | ||
|
|
1bd3181d8e | ||
|
|
e04fef7354 | ||
|
|
bbca3870d5 | ||
|
|
1fe64de09a | ||
|
|
72334ed61c | ||
|
|
c1b8528b69 | ||
|
|
cfebd68e18 | ||
|
|
572749f388 | ||
|
|
cdf189e15a | ||
|
|
98f85b8650 | ||
|
|
0148b62f0c | ||
|
|
9bc573931c | ||
|
|
64e6d1953c | ||
|
|
c0148a00fe | ||
|
|
44727c7b4a | ||
|
|
1e9d1253f9 | ||
|
|
aae46032bc | ||
|
|
0e10170e19 | ||
|
|
40e96a2a04 | ||
|
|
02ca5870c5 | ||
|
|
8e3bd11d60 | ||
|
|
017af11b2b | ||
|
|
821611f76f | ||
|
|
ae43ea796a | ||
|
|
5fa342cc52 | ||
|
|
08b21fa55c | ||
|
|
32ccf38606 | ||
|
|
04428f6f74 | ||
|
|
84427c2857 | ||
|
|
ca5a9bb019 | ||
|
|
1f0c2ee18e | ||
|
|
6b3323fb10 |
81
.github/copilot-instructions.md
vendored
Normal file
81
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
# GitHub Copilot Code Review Instructions
|
||||
|
||||
## General Review Principles
|
||||
|
||||
### Pull Request Size and Scope
|
||||
- **Flag large PRs**: Comment if a PR changes more than 500 lines or touches many unrelated areas
|
||||
- **Suggest splitting**: Recommend breaking large changes into smaller, focused PRs
|
||||
- **Question scope creep**: Ask about unrelated changes that seem outside the PR's stated purpose
|
||||
|
||||
### Code Quality and Style
|
||||
- **Check adherence to style guidelines**: Verify changes follow the project's Rust conventions in [CONTRIBUTING.md](https://github.com/ratatui/ratatui/blob/main/CONTRIBUTING.md#code-formatting)
|
||||
- **Verify xtask compliance**: Ensure `cargo xtask format` and `cargo xtask lint` would pass
|
||||
- **Look for AI-generated patterns**: Be suspicious of verbose, overly-commented, or non-idiomatic code
|
||||
|
||||
### Architectural Considerations
|
||||
- **Reference ARCHITECTURE.md**: Point to [ARCHITECTURE.md](https://github.com/ratatui/ratatui/blob/main/ARCHITECTURE.md) for changes affecting crate boundaries
|
||||
- **Question fundamental changes**: Flag modifications to core configuration, linting rules, or build setup without clear justification
|
||||
- **Verify appropriate crate placement**: Ensure changes are in the correct crate per the modular structure
|
||||
|
||||
### Breaking Changes and Deprecation
|
||||
- **Require deprecation**: Insist on deprecation warnings rather than immediate removal of public APIs
|
||||
- **Ask for migration path**: Request clear upgrade instructions for breaking changes
|
||||
- **Suggest feature flags**: Recommend feature flags for experimental or potentially disruptive changes
|
||||
- **Reference versioning policy**: Point to the requirement of at least one version notice before removal
|
||||
|
||||
### Testing and Documentation
|
||||
- **Verify test coverage**: Ensure new functionality includes appropriate tests
|
||||
- **Check for test removal**: Question any removal of existing tests without clear justification
|
||||
- **Require documentation**: Ensure public APIs are documented with examples
|
||||
- **Validate examples**: Check that code examples are minimal and follow project style
|
||||
|
||||
### Specific Areas of Concern
|
||||
|
||||
#### Configuration Changes
|
||||
- **Lint configuration**: Question changes to `.clippy.toml`, `rustfmt.toml`, or CI configuration
|
||||
- **Cargo.toml modifications**: Scrutinize dependency changes or workspace modifications
|
||||
- **Build system changes**: Require justification for xtask or build process modifications
|
||||
|
||||
#### Large Code Additions
|
||||
- **Question necessity**: Ask if large code additions could be implemented more simply
|
||||
- **Check for duplication**: Look for code that duplicates existing functionality
|
||||
- **Verify integration**: Ensure new code integrates well with existing patterns
|
||||
|
||||
#### File Organization
|
||||
- **Validate module structure**: Ensure new modules follow the project's organization
|
||||
- **Check import organization**: Verify imports follow the std/external/local grouping pattern
|
||||
- **Review file placement**: Confirm files are in appropriate locations per ARCHITECTURE.md
|
||||
|
||||
## Comment Templates
|
||||
|
||||
### For Large PRs
|
||||
```
|
||||
This PR seems quite large with changes across multiple areas. Consider splitting it into smaller, focused PRs:
|
||||
- Core functionality changes
|
||||
- Documentation updates
|
||||
- Test additions
|
||||
- Configuration changes
|
||||
|
||||
See our [contribution guidelines](https://github.com/ratatui/ratatui/blob/main/CONTRIBUTING.md#keep-prs-small-intentional-and-focused) for more details.
|
||||
```
|
||||
|
||||
### For Breaking Changes
|
||||
```
|
||||
This appears to introduce breaking changes. Please consider:
|
||||
- Adding deprecation warnings instead of immediate removal
|
||||
- Providing a clear migration path in the PR description
|
||||
- Following our [deprecation policy](https://github.com/ratatui/ratatui/blob/main/CONTRIBUTING.md#deprecation-notice)
|
||||
```
|
||||
|
||||
### For Configuration Changes
|
||||
```
|
||||
Changes to project configuration (linting, formatting, build) should be discussed first. Please explain:
|
||||
- Why this change is necessary
|
||||
- What problem it solves
|
||||
- Whether it affects contributor workflow
|
||||
```
|
||||
|
||||
### For Style Issues
|
||||
```
|
||||
Please run `cargo xtask format` and `cargo xtask lint` to ensure code follows our style guidelines. See [CONTRIBUTING.md](https://github.com/ratatui/ratatui/blob/main/CONTRIBUTING.md#code-formatting) for details.
|
||||
```
|
||||
65
.github/workflows/check-pr.yml
vendored
65
.github/workflows/check-pr.yml
vendored
@@ -1,6 +1,13 @@
|
||||
name: Check Pull Requests
|
||||
|
||||
# Set the permissions of the github token to the minimum and only enable what is needed
|
||||
# See https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions
|
||||
permissions: {}
|
||||
|
||||
on:
|
||||
# this workflow is required to be run on pull_request_target as it modifies the PR comments
|
||||
# care should be taken that the jobs do not run any untrusted input
|
||||
# zizmor: ignore[dangerous-triggers]
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
@@ -8,23 +15,21 @@ on:
|
||||
- synchronize
|
||||
- labeled
|
||||
- unlabeled
|
||||
merge_group:
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
check-title:
|
||||
permissions:
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check PR title
|
||||
if: github.event_name == 'pull_request_target'
|
||||
uses: amannn/action-semantic-pull-request@v5
|
||||
uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5
|
||||
id: check_pr_title
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Add comment indicating we require pull request titles to follow conventional commits specification
|
||||
- uses: marocchino/sticky-pull-request-comment@v2
|
||||
- uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2
|
||||
if: always() && (steps.check_pr_title.outputs.error_message != null)
|
||||
with:
|
||||
header: pr-title-lint-error
|
||||
@@ -39,40 +44,42 @@ jobs:
|
||||
|
||||
# Delete a previous comment when the issue has been resolved
|
||||
- if: ${{ steps.check_pr_title.outputs.error_message == null }}
|
||||
uses: marocchino/sticky-pull-request-comment@v2
|
||||
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2
|
||||
with:
|
||||
header: pr-title-lint-error
|
||||
delete: true
|
||||
|
||||
check-breaking-change-label:
|
||||
permissions:
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
# use an environment variable to pass untrusted input to the script
|
||||
# see https://securitylab.github.com/research/github-actions-untrusted-input/
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
steps:
|
||||
- name: Check breaking change label
|
||||
id: check_breaking_change
|
||||
run: |
|
||||
pattern='^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\(\w+\))?!:'
|
||||
# Check if pattern matches
|
||||
if echo "${PR_TITLE}" | grep -qE "$pattern"; then
|
||||
echo "breaking_change=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "breaking_change=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Add label
|
||||
if: steps.check_breaking_change.outputs.breaking_change == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
github.rest.issues.addLabels({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: ['Type: Breaking Change']
|
||||
})
|
||||
- name: Check breaking change label
|
||||
id: check_breaking_change
|
||||
run: |
|
||||
pattern='^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\(\w+\))?!:'
|
||||
# Check if pattern matches
|
||||
if echo "${PR_TITLE}" | grep -qE "$pattern"; then
|
||||
echo "breaking_change=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "breaking_change=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Add label
|
||||
if: steps.check_breaking_change.outputs.breaking_change == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
github.rest.issues.addLabels({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: ['Type: Breaking Change']
|
||||
})
|
||||
|
||||
do-not-merge:
|
||||
if: ${{ contains(github.event.*.labels.*.name, 'do not merge') }}
|
||||
|
||||
10
.github/workflows/check-semver.yml
vendored
10
.github/workflows/check-semver.yml
vendored
@@ -1,5 +1,9 @@
|
||||
name: Check Semver
|
||||
|
||||
# Set the permissions of the github token to the minimum and only enable what is needed
|
||||
# See https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions
|
||||
permissions: {}
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
@@ -11,6 +15,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check semver
|
||||
uses: obi1kenobi/cargo-semver-checks-action@v2
|
||||
uses: obi1kenobi/cargo-semver-checks-action@5b298c9520f7096a4683c0bd981a7ac5a7e249ae # v2
|
||||
|
||||
145
.github/workflows/ci.yml
vendored
145
.github/workflows/ci.yml
vendored
@@ -1,5 +1,9 @@
|
||||
name: Continuous Integration
|
||||
|
||||
# Set the permissions of the github token to the minimum and only enable what is needed
|
||||
# See https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions
|
||||
permissions: {}
|
||||
|
||||
on:
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
@@ -25,11 +29,15 @@ jobs:
|
||||
name: Check Formatting
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with: { components: rustfmt }
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: taiki-e/install-action@v2
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: nightly
|
||||
components: rustfmt
|
||||
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2
|
||||
- uses: taiki-e/install-action@c99cc51b309eee71a866715cfa08c922f11cf898 # v2
|
||||
with:
|
||||
tool: taplo-cli
|
||||
- run: cargo xtask format --check
|
||||
@@ -40,8 +48,10 @@ jobs:
|
||||
name: Check Typos
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: crate-ci/typos@master
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: crate-ci/typos@392b78fe18a52790c53f42456e46124f77346842 # master
|
||||
|
||||
# Check for any disallowed dependencies in the codebase due to license / security issues.
|
||||
# See <https://github.com/EmbarkStudios/cargo-deny>
|
||||
@@ -49,9 +59,15 @@ jobs:
|
||||
name: Check Dependencies
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: taiki-e/install-action@cargo-deny
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: stable
|
||||
- uses: taiki-e/install-action@c99cc51b309eee71a866715cfa08c922f11cf898 # v2
|
||||
with:
|
||||
tool: cargo-deny
|
||||
- run: cargo deny --log-level info --all-features check
|
||||
|
||||
# Check for any unused dependencies in the codebase.
|
||||
@@ -60,8 +76,10 @@ jobs:
|
||||
name: Check Unused Dependencies
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: bnjbvr/cargo-machete@v0.8.0
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: bnjbvr/cargo-machete@b54422fa3319b3cac180f6030b663fe57af51635 # v0.8.0
|
||||
|
||||
# Run cargo clippy.
|
||||
#
|
||||
@@ -77,12 +95,14 @@ jobs:
|
||||
toolchain: ["stable", "beta"]
|
||||
continue-on-error: ${{ matrix.toolchain == 'beta' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
components: clippy
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2
|
||||
- run: cargo xtask clippy
|
||||
|
||||
# Run markdownlint on all markdown files in the repository.
|
||||
@@ -90,8 +110,10 @@ jobs:
|
||||
name: Check Markdown
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: DavidAnson/markdownlint-cli2-action@v20
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: DavidAnson/markdownlint-cli2-action@992badcdf24e3b8eb7e87ff9287fe931bcb00c6e # v20
|
||||
with:
|
||||
globs: |
|
||||
'**/*.md'
|
||||
@@ -103,14 +125,19 @@ jobs:
|
||||
name: Coverage Report
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: stable
|
||||
components: llvm-tools
|
||||
- uses: taiki-e/install-action@cargo-llvm-cov
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: taiki-e/install-action@c99cc51b309eee71a866715cfa08c922f11cf898 # v2
|
||||
with:
|
||||
tool: cargo-llvm-cov
|
||||
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2
|
||||
- run: cargo xtask coverage
|
||||
- uses: codecov/codecov-action@v5
|
||||
- uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
fail_ci_if_error: true
|
||||
@@ -125,22 +152,27 @@ jobs:
|
||||
toolchain: ["1.85.0", "stable"]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2
|
||||
- run: cargo xtask check --all-features
|
||||
|
||||
build-no-std:
|
||||
name: Build No-Std
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: stable
|
||||
targets: x86_64-unknown-none
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2
|
||||
# This makes it easier to debug the exact versions of the dependencies
|
||||
- run: cargo tree --target x86_64-unknown-none -p ratatui-core
|
||||
- run: cargo tree --target x86_64-unknown-none -p ratatui-widgets
|
||||
@@ -156,9 +188,13 @@ jobs:
|
||||
name: Check README
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: taiki-e/install-action@cargo-rdme
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2
|
||||
- uses: taiki-e/install-action@c99cc51b309eee71a866715cfa08c922f11cf898 # v2
|
||||
with:
|
||||
tool: cargo-rdme
|
||||
- run: cargo xtask readme --check
|
||||
|
||||
# Run cargo rustdoc with the same options that would be used by docs.rs, taking into account the
|
||||
@@ -169,10 +205,19 @@ jobs:
|
||||
env:
|
||||
RUSTDOCFLAGS: -Dwarnings
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- uses: dtolnay/install@cargo-docs-rs
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: nightly
|
||||
- uses: dtolnay/install@74f735cdf643820234e37ae1c4089a08fd266d8a # master
|
||||
with:
|
||||
crate: cargo-docs-rs
|
||||
- uses: taiki-e/install-action@c99cc51b309eee71a866715cfa08c922f11cf898 # v2
|
||||
with:
|
||||
tool: cargo-hack
|
||||
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2
|
||||
- run: cargo xtask docs
|
||||
|
||||
# Run cargo test on the documentation of the crate. This will catch any code examples that don't
|
||||
@@ -181,9 +226,13 @@ jobs:
|
||||
name: Test Docs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: stable
|
||||
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2
|
||||
- run: cargo xtask test-docs
|
||||
|
||||
# Run cargo test on the libraries of the crate.
|
||||
@@ -195,9 +244,13 @@ jobs:
|
||||
matrix:
|
||||
toolchain: ["1.85.0", "stable"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: stable
|
||||
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2
|
||||
- run: cargo xtask test-libs
|
||||
|
||||
# Run cargo test on all the backends.
|
||||
@@ -214,7 +267,11 @@ jobs:
|
||||
- os: windows-latest
|
||||
backend: termion
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: stable
|
||||
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2
|
||||
- run: cargo xtask test-backend ${{ matrix.backend }}
|
||||
|
||||
16
.github/workflows/release-alpha.yml
vendored
16
.github/workflows/release-alpha.yml
vendored
@@ -1,5 +1,9 @@
|
||||
name: Release alpha version
|
||||
|
||||
# Set the permissions of the github token to the minimum and only enable what is needed
|
||||
# See https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions
|
||||
permissions: {}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
@@ -20,21 +24,25 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
# probably needs to be set to true for git-cliff to work - check build
|
||||
persist-credentials: false
|
||||
|
||||
- name: Calculate the next release
|
||||
run: .github/workflows/calculate-alpha-release.bash
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Publish
|
||||
run: cargo publish --allow-dirty --token ${{ secrets.CARGO_TOKEN }}
|
||||
|
||||
- name: Generate a changelog
|
||||
uses: orhun/git-cliff-action@v4
|
||||
uses: orhun/git-cliff-action@4a4a951bc43fafe41cd2348d181853f52356bee7 # v4
|
||||
with:
|
||||
config: cliff.toml
|
||||
args: --unreleased --tag ${{ env.NEXT_TAG }} --strip header
|
||||
@@ -42,7 +50,7 @@ jobs:
|
||||
OUTPUT: BODY.md
|
||||
|
||||
- name: Publish on GitHub
|
||||
uses: ncipollo/release-action@v1
|
||||
uses: ncipollo/release-action@bcfe5470707e8832e12347755757cec0eb3c22af # v1
|
||||
with:
|
||||
tag: ${{ env.NEXT_TAG }}
|
||||
prerelease: true
|
||||
|
||||
35
.github/workflows/release-plz.yml
vendored
35
.github/workflows/release-plz.yml
vendored
@@ -1,8 +1,8 @@
|
||||
name: Release-plz
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
# Set the permissions of the github token to the minimum and only enable what is needed
|
||||
# See https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions
|
||||
permissions: {}
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -14,26 +14,38 @@ jobs:
|
||||
# Release unpublished packages.
|
||||
release-plz-release:
|
||||
name: Release-plz release
|
||||
environment: release
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
id-token: write
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository_owner == 'ratatui' }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: stable
|
||||
- uses: rust-lang/crates-io-auth-action@e919bc7605cde86df457cf5b93c5e103838bd879 # v1
|
||||
id: auth
|
||||
- name: Run release-plz
|
||||
uses: release-plz/action@v0.5
|
||||
uses: release-plz/action@068d76d2aa32d3c9cd0b1ccdd9ac921e28ba2be9 # v0.5
|
||||
with:
|
||||
command: release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_TOKEN }}
|
||||
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
|
||||
|
||||
# Create a PR with the new versions and changelog, preparing the next release.
|
||||
release-plz-pr:
|
||||
name: Release-plz PR
|
||||
permissions:
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository_owner == 'ratatui' }}
|
||||
concurrency:
|
||||
@@ -41,13 +53,16 @@ jobs:
|
||||
cancel-in-progress: false
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Run release-plz
|
||||
uses: release-plz/action@v0.5
|
||||
uses: release-plz/action@068d76d2aa32d3c9cd0b1ccdd9ac921e28ba2be9 # v0.5
|
||||
with:
|
||||
command: release-pr
|
||||
env:
|
||||
|
||||
20
.github/workflows/release-stable.yml
vendored
20
.github/workflows/release-stable.yml
vendored
@@ -1,5 +1,9 @@
|
||||
name: Release stable version
|
||||
|
||||
# Set the permissions of the github token to the minimum and only enable what is needed
|
||||
# See https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions
|
||||
permissions: {}
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
@@ -13,12 +17,14 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
# this possibly needs to be set to true for git-cliff to work - check build results
|
||||
persist-credentials: false
|
||||
|
||||
- name: Generate a changelog
|
||||
uses: orhun/git-cliff-action@v4
|
||||
uses: orhun/git-cliff-action@4a4a951bc43fafe41cd2348d181853f52356bee7 # v4
|
||||
with:
|
||||
config: cliff.toml
|
||||
args: --latest --strip header
|
||||
@@ -26,7 +32,7 @@ jobs:
|
||||
OUTPUT: BODY.md
|
||||
|
||||
- name: Publish on GitHub
|
||||
uses: ncipollo/release-action@v1
|
||||
uses: ncipollo/release-action@bcfe5470707e8832e12347755757cec0eb3c22af # v1
|
||||
with:
|
||||
prerelease: false
|
||||
bodyFile: BODY.md
|
||||
@@ -36,10 +42,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Publish
|
||||
run: cargo publish --token ${{ secrets.CARGO_TOKEN }}
|
||||
|
||||
26
.github/workflows/zizmor.yml
vendored
Normal file
26
.github/workflows/zizmor.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: GitHub Actions Security Analysis with zizmor 🌈
|
||||
|
||||
# docs https://docs.zizmor.sh/integrations/#github-actions
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
branches: ["**"]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
zizmor:
|
||||
name: Run zizmor 🌈
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Run zizmor 🌈
|
||||
uses: zizmorcore/zizmor-action@f52a838cfabf134edcbaa7c8b3677dde20045018 # v0.1.1
|
||||
@@ -26,6 +26,7 @@ This is a quick summary of the sections below:
|
||||
feature is enabled
|
||||
- Disabling `default-features` suppresses the error message if `show_cursor()` fails when dropping
|
||||
`Terminal`
|
||||
- Support a broader range for `unicode-width` version
|
||||
- [v0.29.0](#v0290)
|
||||
- `Sparkline::data` takes `IntoIterator<Item = SparklineBar>` instead of `&[u64]` and is no longer
|
||||
const
|
||||
@@ -377,6 +378,17 @@ The `termwiz` backend is upgraded from 0.22.0 to 0.23.0.
|
||||
This release has a few fixes for hyperlinks and input handling, plus some dependency updates.
|
||||
See the [commits](https://github.com/wezterm/wezterm/commits/main/termwiz) for more details.
|
||||
|
||||
### Support a broader range for `unicode-width` version ([#1999])
|
||||
|
||||
[#1999]: https://github.com/ratatui/ratatui/pull/1999
|
||||
|
||||
Ratatui's dependency on `unicode-width`, previously pinned to 0.2.0, has
|
||||
expanded to allow version 0.2.1. This comes with 2 behavior changes described in
|
||||
[unicode-width#61] and [unicode-width#74].
|
||||
|
||||
[unicode-width#61]: https://github.com/unicode-rs/unicode-width/pull/61
|
||||
[unicode-width#74]: https://github.com/unicode-rs/unicode-width/pull/74
|
||||
|
||||
## [v0.29.0](https://github.com/ratatui/ratatui/releases/tag/v0.29.0)
|
||||
|
||||
### `Sparkline::data` takes `IntoIterator<Item = SparklineBar>` instead of `&[u64]` and is no longer const ([#1326])
|
||||
|
||||
935
CHANGELOG.md
935
CHANGELOG.md
@@ -1094,913 +1094,8 @@ All notable changes to this project will be documented in this file.
|
||||
>
|
||||
> BREAKING CHANGE:MSRV is now 1.81
|
||||
|
||||
### Security
|
||||
|
||||
- [3745a67](https://github.com/ratatui/ratatui/commit/3745a67ba071d5a52e378af34f8409cd90912eb0) *(deps)* Bump rand from 0.9.0 to 0.9.1 by @dependabot[bot] in [#1804](https://github.com/ratatui/ratatui/pull/1804)
|
||||
|
||||
> Bumps [rand](https://github.com/rust-random/rand) from 0.9.0 to 0.9.1.
|
||||
> <details>
|
||||
> <summary>Changelog</summary>
|
||||
> <p><em>Sourced from <a
|
||||
> href="https://github.com/rust-random/rand/blob/master/CHANGELOG.md">rand's
|
||||
> changelog</a>.</em></p>
|
||||
> <blockquote>
|
||||
> <h2>[0.9.1] - 2025-04-17</h2>
|
||||
> <h3>Security and unsafe</h3>
|
||||
> <ul>
|
||||
> <li>Revise "not a crypto library" policy again (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1565">#1565</a>)</li>
|
||||
> <li>Remove <code>zerocopy</code> dependency from <code>rand</code> (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1579">#1579</a>)</li>
|
||||
> </ul>
|
||||
> <h3>Fixes</h3>
|
||||
> <ul>
|
||||
> <li>Fix feature <code>simd_support</code> for recent nightly rust (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1586">#1586</a>)</li>
|
||||
> </ul>
|
||||
> <h3>Changes</h3>
|
||||
> <ul>
|
||||
> <li>Allow <code>fn rand::seq::index::sample_weighted</code> and <code>fn
|
||||
> IndexedRandom::choose_multiple_weighted</code> to return fewer than
|
||||
> <code>amount</code> results (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1623">#1623</a>),
|
||||
> reverting an undocumented change (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1382">#1382</a>)
|
||||
> to the previous release.</li>
|
||||
> </ul>
|
||||
> <h3>Additions</h3>
|
||||
> <ul>
|
||||
> <li>Add <code>rand::distr::Alphabetic</code> distribution. (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1587">#1587</a>)</li>
|
||||
> <li>Re-export <code>rand_core</code> (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1604">#1604</a>)</li>
|
||||
> </ul>
|
||||
> </blockquote>
|
||||
> </details>
|
||||
> <details>
|
||||
> <summary>Commits</summary>
|
||||
> <ul>
|
||||
> <li><a
|
||||
> href="https://github.com/rust-random/rand/commit/ec6d5c06a5384c14563a2164bb4a038100a5bb78"><code>ec6d5c0</code></a>
|
||||
> Prepare rand_core v0.9.1 (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1591">#1591</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/rust-random/rand/commit/6a06056e8a892bfa181ec24a8ea16aa9f2fe97d3"><code>6a06056</code></a>
|
||||
> rand_core: introduce an UnwrapMut wrapper (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1589">#1589</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/rust-random/rand/commit/8929123b4d5abb7cae349c5f8213bf2fa8583821"><code>8929123</code></a>
|
||||
> Add <code>Alphabetic</code> distribution (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1587">#1587</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/rust-random/rand/commit/06b16426bd1431e164247c8bdf109cedb67213f7"><code>06b1642</code></a>
|
||||
> Remove unnecessary underscore from `impl<T, const N: usize>
|
||||
> Distribution<[T; ...</li>
|
||||
> <li><a
|
||||
> href="https://github.com/rust-random/rand/commit/49d76cd7b4a318114cff22494997c73a56ffd95c"><code>49d76cd</code></a>
|
||||
> rename extract to extract_lane (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1586">#1586</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/rust-random/rand/commit/e0a70fd8be09196bcaf4a86e732bce501b42ef86"><code>e0a70fd</code></a>
|
||||
> Change to use <code>array::from_fn</code> in <code>Distribution\<[T;
|
||||
> N]> for StandardUniform</code> ...</li>
|
||||
> <li><a
|
||||
> href="https://github.com/rust-random/rand/commit/0bc3f652c4500406b343a517e058caedd1f095a9"><code>0bc3f65</code></a>
|
||||
> Move rand distr (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1577">#1577</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/rust-random/rand/commit/2677c49960e3a3fc2f1a8df90c1d7104089903f2"><code>2677c49</code></a>
|
||||
> Revise "not a crypto library" policy and SECURITY.md (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1565">#1565</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/rust-random/rand/commit/bfd1826c36c441236f218af478edd794bca7f23a"><code>bfd1826</code></a>
|
||||
> SeedableRng docs: add note on (lack of) reproducibility (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1572">#1572</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/rust-random/rand/commit/c01aee7a138ff77657782069771bb11f120318d7"><code>c01aee7</code></a>
|
||||
> Fix some links (<a
|
||||
> href="https://redirect.github.com/rust-random/rand/issues/1571">#1571</a>)</li>
|
||||
> <li>Additional commits viewable in <a
|
||||
> href="https://github.com/rust-random/rand/compare/0.9.0...rand_core-0.9.1">compare
|
||||
> view</a></li>
|
||||
> </ul>
|
||||
> </details>
|
||||
> <br />
|
||||
>
|
||||
>
|
||||
> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
|
||||
>
|
||||
> Dependabot will resolve any conflicts with this PR as long as you don't
|
||||
> alter it yourself. You can also trigger a rebase manually by commenting
|
||||
> `@dependabot rebase`.
|
||||
>
|
||||
> [//]:# (dependabot-automerge-start)
|
||||
>
|
||||
> [//]:# (dependabot-automerge-end)
|
||||
>
|
||||
> ---
|
||||
>
|
||||
> <details>
|
||||
> <summary>Dependabot commands and options</summary>
|
||||
> <br />
|
||||
>
|
||||
> You can trigger Dependabot actions by commenting on this PR:
|
||||
> - `@dependabot rebase` will rebase this PR
|
||||
> - `@dependabot recreate` will recreate this PR, overwriting any edits
|
||||
> that have been made to it
|
||||
> - `@dependabot merge` will merge this PR after your CI passes on it
|
||||
> - `@dependabot squash and merge` will squash and merge this PR after
|
||||
> your CI passes on it
|
||||
> - `@dependabot cancel merge` will cancel a previously requested merge
|
||||
> and block automerging
|
||||
> - `@dependabot reopen` will reopen this PR if it is closed
|
||||
> - `@dependabot close` will close this PR and stop Dependabot recreating
|
||||
> it. You can achieve the same result by closing it manually
|
||||
> - `@dependabot show <dependency name> ignore conditions` will show all
|
||||
> of the ignore conditions of the specified dependency
|
||||
> - `@dependabot ignore this major version` will close this PR and stop
|
||||
> Dependabot creating any more for this major version (unless you reopen
|
||||
> the PR or upgrade to it yourself)
|
||||
> - `@dependabot ignore this minor version` will close this PR and stop
|
||||
> Dependabot creating any more for this minor version (unless you reopen
|
||||
> the PR or upgrade to it yourself)
|
||||
> - `@dependabot ignore this dependency` will close this PR and stop
|
||||
> Dependabot creating any more for this dependency (unless you reopen the
|
||||
> PR or upgrade to it yourself)
|
||||
>
|
||||
>
|
||||
> </details>
|
||||
|
||||
- [a03ba0d](https://github.com/ratatui/ratatui/commit/a03ba0de5c02a51726285b359a512e6de8b84622) *(deps)* Bump crossterm from 0.28.1 to 0.29.0 by @dependabot[bot] in [#1771](https://github.com/ratatui/ratatui/pull/1771)
|
||||
|
||||
> Bumps [crossterm](https://github.com/crossterm-rs/crossterm) from 0.28.1
|
||||
> to 0.29.0.
|
||||
> <details>
|
||||
> <summary>Release notes</summary>
|
||||
> <p><em>Sourced from <a
|
||||
> href="https://github.com/crossterm-rs/crossterm/releases">crossterm's
|
||||
> releases</a>.</em></p>
|
||||
> <blockquote>
|
||||
> <h2>0.29</h2>
|
||||
> <h1>Version 0.29</h1>
|
||||
> <h2>Added ⭐</h2>
|
||||
> <ul>
|
||||
> <li>Copy to clipboard using OSC52 (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/974">#974</a>)</li>
|
||||
> <li>Derive standard traits for "SetCursorStyle" (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/909">#909</a>)</li>
|
||||
> <li>Add query_keyboard_enhancement_flags to read enabled flags (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/958">#958</a>)</li>
|
||||
> <li>Add is_* and as_* methods to the event enums (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/949">#949</a>)</li>
|
||||
> <li>Add a feature flag for derive_more impls (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/970">#970</a>)</li>
|
||||
> <li>Update rustix to 1.0 (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/982">#982</a>)</li>
|
||||
> <li>Upgrade various dependencies</li>
|
||||
> </ul>
|
||||
> <h2>Breaking ⚠️</h2>
|
||||
> <ul>
|
||||
> <li>Correctly fix KeyModifiers Display impl Properly adding + in between
|
||||
> modifiers (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/979">#979</a>)</li>
|
||||
> </ul>
|
||||
> <p><a href="https://github.com/joshka"><code>@joshka</code></a> <a
|
||||
> href="https://github.com/linrongbin16"><code>@linrongbin16</code></a>
|
||||
> <a href="https://github.com/kmicklas"><code>@kmicklas</code></a> <a
|
||||
> href="https://github.com/maciek50322"><code>@maciek50322</code></a> <a
|
||||
> href="https://github.com/rosew0od"><code>@rosew0od</code></a> <a
|
||||
> href="https://github.com/sxyazi"><code>@sxyazi</code></a> <a
|
||||
> href="https://github.com/the-mikedavis"><code>@the-mikedavis</code></a>
|
||||
> <a href="https://github.com/hthuz"><code>@hthuz</code></a> <a
|
||||
> href="https://github.com/aschey"><code>@aschey</code></a> <a
|
||||
> href="https://github.com/naseschwarz"><code>@naseschwarz</code></a> <a
|
||||
> href="https://github.com/Flokkq"><code>@Flokkq</code></a> <a
|
||||
> href="https://github.com/gaesa"><code>@gaesa</code></a> <a
|
||||
> href="https://github.com/WindSoilder"><code>@WindSoilder</code></a></p>
|
||||
> </blockquote>
|
||||
> </details>
|
||||
> <details>
|
||||
> <summary>Changelog</summary>
|
||||
> <p><em>Sourced from <a
|
||||
> href="https://github.com/crossterm-rs/crossterm/blob/master/CHANGELOG.md">crossterm's
|
||||
> changelog</a>.</em></p>
|
||||
> <blockquote>
|
||||
> <h1>Unreleased</h1>
|
||||
> <h1>Version 0.29</h1>
|
||||
> <h2>Added ⭐</h2>
|
||||
> <ul>
|
||||
> <li>Copy to clipboard using OSC52 (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/974">#974</a>)</li>
|
||||
> <li>Derive standard traits for "SetCursorStyle" (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/909">#909</a>)</li>
|
||||
> <li>Add query_keyboard_enhancement_flags to read enabled flags (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/958">#958</a>)</li>
|
||||
> <li>Add is_* and as_* methods to the event enums (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/949">#949</a>)</li>
|
||||
> <li>Add a feature flag for derive_more impls (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/970">#970</a>)</li>
|
||||
> <li>Update rustix to 1.0 (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/982">#982</a>)</li>
|
||||
> </ul>
|
||||
> <h2>Breaking ⚠️</h2>
|
||||
> <ul>
|
||||
> <li>Correctly fix KeyModifiers Display impl Properly adding + in between
|
||||
> modifiers (<a
|
||||
> href="https://redirect.github.com/crossterm-rs/crossterm/issues/979">#979</a>)</li>
|
||||
> </ul>
|
||||
> </blockquote>
|
||||
> </details>
|
||||
> <details>
|
||||
> <summary>Commits</summary>
|
||||
> <ul>
|
||||
> <li>See full diff in <a
|
||||
> href="https://github.com/crossterm-rs/crossterm/commits/0.29">compare
|
||||
> view</a></li>
|
||||
> </ul>
|
||||
> </details>
|
||||
> <br />
|
||||
>
|
||||
>
|
||||
> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
|
||||
>
|
||||
> Dependabot will resolve any conflicts with this PR as long as you don't
|
||||
> alter it yourself. You can also trigger a rebase manually by commenting
|
||||
> `@dependabot rebase`.
|
||||
>
|
||||
> [//]:# (dependabot-automerge-start)
|
||||
>
|
||||
> [//]:# (dependabot-automerge-end)
|
||||
>
|
||||
> ---
|
||||
>
|
||||
> <details>
|
||||
> <summary>Dependabot commands and options</summary>
|
||||
> <br />
|
||||
>
|
||||
> You can trigger Dependabot actions by commenting on this PR:
|
||||
> - `@dependabot rebase` will rebase this PR
|
||||
> - `@dependabot recreate` will recreate this PR, overwriting any edits
|
||||
> that have been made to it
|
||||
> - `@dependabot merge` will merge this PR after your CI passes on it
|
||||
> - `@dependabot squash and merge` will squash and merge this PR after
|
||||
> your CI passes on it
|
||||
> - `@dependabot cancel merge` will cancel a previously requested merge
|
||||
> and block automerging
|
||||
> - `@dependabot reopen` will reopen this PR if it is closed
|
||||
> - `@dependabot close` will close this PR and stop Dependabot recreating
|
||||
> it. You can achieve the same result by closing it manually
|
||||
> - `@dependabot show <dependency name> ignore conditions` will show all
|
||||
> of the ignore conditions of the specified dependency
|
||||
> - `@dependabot ignore this major version` will close this PR and stop
|
||||
> Dependabot creating any more for this major version (unless you reopen
|
||||
> the PR or upgrade to it yourself)
|
||||
> - `@dependabot ignore this minor version` will close this PR and stop
|
||||
> Dependabot creating any more for this minor version (unless you reopen
|
||||
> the PR or upgrade to it yourself)
|
||||
> - `@dependabot ignore this dependency` will close this PR and stop
|
||||
> Dependabot creating any more for this dependency (unless you reopen the
|
||||
> PR or upgrade to it yourself)
|
||||
>
|
||||
>
|
||||
> </details>
|
||||
|
||||
- [fdc1746](https://github.com/ratatui/ratatui/commit/fdc1746effadf28392f055345be10074f4117e3e) *(deps)* Bump tokio from 1.44.1 to 1.44.2 by @dependabot[bot] in [#1769](https://github.com/ratatui/ratatui/pull/1769)
|
||||
|
||||
> Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.44.1 to 1.44.2.
|
||||
> <details>
|
||||
> <summary>Release notes</summary>
|
||||
> <p><em>Sourced from <a
|
||||
> href="https://github.com/tokio-rs/tokio/releases">tokio's
|
||||
> releases</a>.</em></p>
|
||||
> <blockquote>
|
||||
> <h2>Tokio v1.44.2</h2>
|
||||
> <p>This release fixes a soundness issue in the broadcast channel. The
|
||||
> channel
|
||||
> accepts values that are <code>Send</code> but <code>!Sync</code>.
|
||||
> Previously, the channel called
|
||||
> <code>clone()</code> on these values without synchronizing. This release
|
||||
> fixes the channel
|
||||
> by synchronizing calls to <code>.clone()</code> (Thanks Austin Bonander
|
||||
> for finding and
|
||||
> reporting the issue).</p>
|
||||
> <h3>Fixed</h3>
|
||||
> <ul>
|
||||
> <li>sync: synchronize <code>clone()</code> call in broadcast channel (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7232">#7232</a>)</li>
|
||||
> </ul>
|
||||
> <p><a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7232">#7232</a>:
|
||||
> <a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/pull/7232">tokio-rs/tokio#7232</a></p>
|
||||
> </blockquote>
|
||||
> </details>
|
||||
> <details>
|
||||
> <summary>Commits</summary>
|
||||
> <ul>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/ec4b1d7215a3e1e91797ad3fb6ba0f7c7f3d2566"><code>ec4b1d7</code></a>
|
||||
> chore: forward port 1.43.x</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/e3c3a56718d201fb7bb430567f05fbb64b2ef082"><code>e3c3a56</code></a>
|
||||
> Merge branch 'tokio-1.43.x' into forward-port-1.43.x</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/a7b658c35bd40f6811e557aeb97cbb361b612c56"><code>a7b658c</code></a>
|
||||
> chore: prepare Tokio v1.43.1 release</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/c1c8d1033d637d7027fdc137ec8008c5801cbc0d"><code>c1c8d10</code></a>
|
||||
> Merge remote-tracking branch 'origin/tokio-1.38.x' into
|
||||
> forward-port-1.38.x</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/aa303bc2051f7c21b48bb7bfcafe8fd4f39afd21"><code>aa303bc</code></a>
|
||||
> chore: prepare Tokio v1.38.2 release</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/7b6ccb515ff067151ed62db835f735e5653f8784"><code>7b6ccb5</code></a>
|
||||
> chore: backport CI fixes</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/4b174ce2c95fe1d1a217917db93fcc935e17e0da"><code>4b174ce</code></a>
|
||||
> sync: fix cloning value when receiving from broadcast channel</li>
|
||||
> <li>See full diff in <a
|
||||
> href="https://github.com/tokio-rs/tokio/compare/tokio-1.44.1...tokio-1.44.2">compare
|
||||
> view</a></li>
|
||||
> </ul>
|
||||
> </details>
|
||||
> <br />
|
||||
>
|
||||
>
|
||||
> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
|
||||
>
|
||||
> Dependabot will resolve any conflicts with this PR as long as you don't
|
||||
> alter it yourself. You can also trigger a rebase manually by commenting
|
||||
> `@dependabot rebase`.
|
||||
>
|
||||
> [//]:# (dependabot-automerge-start)
|
||||
>
|
||||
> [//]:# (dependabot-automerge-end)
|
||||
>
|
||||
> ---
|
||||
>
|
||||
> <details>
|
||||
> <summary>Dependabot commands and options</summary>
|
||||
> <br />
|
||||
>
|
||||
> You can trigger Dependabot actions by commenting on this PR:
|
||||
> - `@dependabot rebase` will rebase this PR
|
||||
> - `@dependabot recreate` will recreate this PR, overwriting any edits
|
||||
> that have been made to it
|
||||
> - `@dependabot merge` will merge this PR after your CI passes on it
|
||||
> - `@dependabot squash and merge` will squash and merge this PR after
|
||||
> your CI passes on it
|
||||
> - `@dependabot cancel merge` will cancel a previously requested merge
|
||||
> and block automerging
|
||||
> - `@dependabot reopen` will reopen this PR if it is closed
|
||||
> - `@dependabot close` will close this PR and stop Dependabot recreating
|
||||
> it. You can achieve the same result by closing it manually
|
||||
> - `@dependabot show <dependency name> ignore conditions` will show all
|
||||
> of the ignore conditions of the specified dependency
|
||||
> - `@dependabot ignore this major version` will close this PR and stop
|
||||
> Dependabot creating any more for this major version (unless you reopen
|
||||
> the PR or upgrade to it yourself)
|
||||
> - `@dependabot ignore this minor version` will close this PR and stop
|
||||
> Dependabot creating any more for this minor version (unless you reopen
|
||||
> the PR or upgrade to it yourself)
|
||||
> - `@dependabot ignore this dependency` will close this PR and stop
|
||||
> Dependabot creating any more for this dependency (unless you reopen the
|
||||
> PR or upgrade to it yourself)
|
||||
>
|
||||
>
|
||||
> </details>
|
||||
|
||||
- [352021b](https://github.com/ratatui/ratatui/commit/352021bc6f802762a7b82fcfbdfd9d248b412e1b) *(deps)* Bump tokio from 1.43.0 to 1.44.1 by @dependabot[bot] in [#1723](https://github.com/ratatui/ratatui/pull/1723)
|
||||
|
||||
> Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.43.0 to 1.44.1.
|
||||
> <details>
|
||||
> <summary>Release notes</summary>
|
||||
> <p><em>Sourced from <a
|
||||
> href="https://github.com/tokio-rs/tokio/releases">tokio's
|
||||
> releases</a>.</em></p>
|
||||
> <blockquote>
|
||||
> <h2>Tokio v1.44.1</h2>
|
||||
> <h1>1.44.1 (March 13th, 2025)</h1>
|
||||
> <h3>Fixed</h3>
|
||||
> <ul>
|
||||
> <li>rt: skip defer queue in <code>block_in_place</code> context (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7216">#7216</a>)</li>
|
||||
> </ul>
|
||||
> <p><a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7216">#7216</a>:
|
||||
> <a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/pull/7216">tokio-rs/tokio#7216</a></p>
|
||||
> <h2>Tokio v1.44.0</h2>
|
||||
> <h1>1.44.0 (March 7th, 2025)</h1>
|
||||
> <p>This release changes the <code>from_std</code> method on sockets to
|
||||
> panic if a blocking socket is provided. We determined this change is not
|
||||
> a breaking change as Tokio is not intended to operate using blocking
|
||||
> sockets. Doing so results in runtime hangs and should be considered a
|
||||
> bug. Accidentally passing a blocking socket to Tokio is one of the most
|
||||
> common user mistakes. If this change causes an issue for you, please
|
||||
> comment on <a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7172">#7172</a>.</p>
|
||||
> <h3>Added</h3>
|
||||
> <ul>
|
||||
> <li>coop: add <code>task::coop</code> module (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7116">#7116</a>)</li>
|
||||
> <li>process: add <code>Command::get_kill_on_drop()</code> (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7086">#7086</a>)</li>
|
||||
> <li>sync: add <code>broadcast::Sender::closed</code> (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/6685">#6685</a>,
|
||||
> <a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7090">#7090</a>)</li>
|
||||
> <li>sync: add <code>broadcast::WeakSender</code> (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7100">#7100</a>)</li>
|
||||
> <li>sync: add <code>oneshot::Receiver::is_empty()</code> (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7153">#7153</a>)</li>
|
||||
> <li>sync: add <code>oneshot::Receiver::is_terminated()</code> (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7152">#7152</a>)</li>
|
||||
> </ul>
|
||||
> <h3>Fixed</h3>
|
||||
> <ul>
|
||||
> <li>fs: empty reads on <code>File</code> should not start a background
|
||||
> read (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7139">#7139</a>)</li>
|
||||
> <li>process: calling <code>start_kill</code> on exited child should not
|
||||
> fail (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7160">#7160</a>)</li>
|
||||
> <li>signal: fix <code>CTRL_CLOSE</code>, <code>CTRL_LOGOFF</code>,
|
||||
> <code>CTRL_SHUTDOWN</code> on windows (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7122">#7122</a>)</li>
|
||||
> <li>sync: properly handle panic during mpsc drop (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7094">#7094</a>)</li>
|
||||
> </ul>
|
||||
> <h3>Changes</h3>
|
||||
> <ul>
|
||||
> <li>runtime: clean up magic number in registration set (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7112">#7112</a>)</li>
|
||||
> <li>coop: make coop yield using waker defer strategy (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7185">#7185</a>)</li>
|
||||
> <li>macros: make <code>select!</code> budget-aware (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7164">#7164</a>)</li>
|
||||
> <li>net: panic when passing a blocking socket to <code>from_std</code>
|
||||
> (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7166">#7166</a>)</li>
|
||||
> <li>io: clean up buffer casts (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7142">#7142</a>)</li>
|
||||
> </ul>
|
||||
> <h3>Changes to unstable APIs</h3>
|
||||
> <ul>
|
||||
> <li>rt: add before and after task poll callbacks (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7120">#7120</a>)</li>
|
||||
> <li>tracing: make the task tracing API unstable public (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/6972">#6972</a>)</li>
|
||||
> </ul>
|
||||
> <h3>Documented</h3>
|
||||
> <ul>
|
||||
> <li>docs: fix nesting of sections in top-level docs (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7159">#7159</a>)</li>
|
||||
> <li>fs: rename symlink and hardlink parameter names (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7143">#7143</a>)</li>
|
||||
> <li>io: swap reader/writer in simplex doc test (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7176">#7176</a>)</li>
|
||||
> <li>macros: docs about <code>select!</code> alternatives (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7110">#7110</a>)</li>
|
||||
> <li>net: rename the argument for <code>send_to</code> (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7146">#7146</a>)</li>
|
||||
> </ul>
|
||||
> <!-- raw HTML omitted -->
|
||||
> </blockquote>
|
||||
> <p>... (truncated)</p>
|
||||
> </details>
|
||||
> <details>
|
||||
> <summary>Commits</summary>
|
||||
> <ul>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/d413c9c02af8f2b4fea14b769b86484b12f46595"><code>d413c9c</code></a>
|
||||
> chore: prepare Tokio v1.44.1 (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7217">#7217</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/addbfb9204be25a8621feb3f20b44a7c1f00edbd"><code>addbfb9</code></a>
|
||||
> rt: skip defer queue in <code>block_in_place</code> context (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7216">#7216</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/8182ecf2628d5e80dac52b8ed1ea466dbb0925b9"><code>8182ecf</code></a>
|
||||
> chore: prepare Tokio v1.44.0 (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7202">#7202</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/a258bff7018940b438e5de3fb846588454df4e4d"><code>a258bff</code></a>
|
||||
> ci: enable printing in multi thread loom tests (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7200">#7200</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/e076d21f679a35ae2697165d46d111285d09e3b4"><code>e076d21</code></a>
|
||||
> process: clarify <code>Child::kill</code> behavior (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7162">#7162</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/042433cdccdf0dd33408c1751a80ddd50a077872"><code>042433c</code></a>
|
||||
> net: debug_assert on creating a tokio socket from a blocking one (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7166">#7166</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/0284d1b5c8ea5aff5b30c254200fb0a46c21d67c"><code>0284d1b</code></a>
|
||||
> macros: make <code>select!</code> budget-aware (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7164">#7164</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/710bc8071ea030f0ad98817414997beab2420ad2"><code>710bc80</code></a>
|
||||
> rt: coop should yield using waker defer strategy (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7185">#7185</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/a2b12bd5799f06e912b32ac05a5ffb5cf1fe31cd"><code>a2b12bd</code></a>
|
||||
> readme: adjust release schedule to once per month (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7191">#7191</a>)</li>
|
||||
> <li><a
|
||||
> href="https://github.com/tokio-rs/tokio/commit/e7b593cbee9541500cef047f3a0ee70be1c55c6f"><code>e7b593c</code></a>
|
||||
> process: fix grammar of the <code>ChildStdin</code> struct doc comment
|
||||
> (<a
|
||||
> href="https://redirect.github.com/tokio-rs/tokio/issues/7192">#7192</a>)</li>
|
||||
> <li>Additional commits viewable in <a
|
||||
> href="https://github.com/tokio-rs/tokio/compare/tokio-1.43.0...tokio-1.44.1">compare
|
||||
> view</a></li>
|
||||
> </ul>
|
||||
> </details>
|
||||
> <br />
|
||||
>
|
||||
>
|
||||
> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
|
||||
>
|
||||
> Dependabot will resolve any conflicts with this PR as long as you don't
|
||||
> alter it yourself. You can also trigger a rebase manually by commenting
|
||||
> `@dependabot rebase`.
|
||||
>
|
||||
> [//]:# (dependabot-automerge-start)
|
||||
>
|
||||
> [//]:# (dependabot-automerge-end)
|
||||
>
|
||||
> ---
|
||||
>
|
||||
> <details>
|
||||
> <summary>Dependabot commands and options</summary>
|
||||
> <br />
|
||||
>
|
||||
> You can trigger Dependabot actions by commenting on this PR:
|
||||
> - `@dependabot rebase` will rebase this PR
|
||||
> - `@dependabot recreate` will recreate this PR, overwriting any edits
|
||||
> that have been made to it
|
||||
> - `@dependabot merge` will merge this PR after your CI passes on it
|
||||
> - `@dependabot squash and merge` will squash and merge this PR after
|
||||
> your CI passes on it
|
||||
> - `@dependabot cancel merge` will cancel a previously requested merge
|
||||
> and block automerging
|
||||
> - `@dependabot reopen` will reopen this PR if it is closed
|
||||
> - `@dependabot close` will close this PR and stop Dependabot recreating
|
||||
> it. You can achieve the same result by closing it manually
|
||||
> - `@dependabot show <dependency name> ignore conditions` will show all
|
||||
> of the ignore conditions of the specified dependency
|
||||
> - `@dependabot ignore this major version` will close this PR and stop
|
||||
> Dependabot creating any more for this major version (unless you reopen
|
||||
> the PR or upgrade to it yourself)
|
||||
> - `@dependabot ignore this minor version` will close this PR and stop
|
||||
> Dependabot creating any more for this minor version (unless you reopen
|
||||
> the PR or upgrade to it yourself)
|
||||
> - `@dependabot ignore this dependency` will close this PR and stop
|
||||
> Dependabot creating any more for this dependency (unless you reopen the
|
||||
> PR or upgrade to it yourself)
|
||||
>
|
||||
>
|
||||
> </details>
|
||||
|
||||
- [83774ee](https://github.com/ratatui/ratatui/commit/83774eecf008e95d8e1c86c92ef6c46090bd6c6e) *(deps)* Bump time from 0.3.37 to 0.3.39 by @dependabot[bot] in [#1708](https://github.com/ratatui/ratatui/pull/1708)
|
||||
|
||||
> Bumps [time](https://github.com/time-rs/time) from 0.3.37 to 0.3.39.
|
||||
> <details>
|
||||
> <summary>Release notes</summary>
|
||||
> <p><em>Sourced from <a
|
||||
> href="https://github.com/time-rs/time/releases">time's
|
||||
> releases</a>.</em></p>
|
||||
> <blockquote>
|
||||
> <h2>v0.3.39</h2>
|
||||
> <p>See the <a
|
||||
> href="https://github.com/time-rs/time/blob/main/CHANGELOG.md">changelog</a>
|
||||
> for details.</p>
|
||||
> <h2>v0.3.38</h2>
|
||||
> <p>See the <a
|
||||
> href="https://github.com/time-rs/time/blob/main/CHANGELOG.md">changelog</a>
|
||||
> for details.</p>
|
||||
> </blockquote>
|
||||
> </details>
|
||||
> <details>
|
||||
> <summary>Changelog</summary>
|
||||
> <p><em>Sourced from <a
|
||||
> href="https://github.com/time-rs/time/blob/main/CHANGELOG.md">time's
|
||||
> changelog</a>.</em></p>
|
||||
> <blockquote>
|
||||
> <h2>0.3.39 [2025-03-06]</h2>
|
||||
> <h3>Fixed</h3>
|
||||
> <ul>
|
||||
> <li>Doc tests run successfully with the default feature set.</li>
|
||||
> <li>wasm builds work again.</li>
|
||||
> </ul>
|
||||
> <p>Both of these were regressions in v0.3.38 and are now checked in
|
||||
> CI.</p>
|
||||
> <h2>0.3.38 [2025-03-05]</h2>
|
||||
> <h3>Added</h3>
|
||||
> <ul>
|
||||
> <li>
|
||||
> <p>The <code>[year]</code> component (in format descriptions) now
|
||||
> supports a <code>range</code> modifier, which can be
|
||||
> either <code>standard</code> or <code>extended</code>. The default is
|
||||
> <code>extended</code> for backwards compatibility. This is
|
||||
> intended as a manner to opt <em>out</em> of the extended range when the
|
||||
> <code>large-dates</code> feature is enabled.
|
||||
> When the <code>large-dates</code> feature is not enabled, the modifier
|
||||
> has no effect.</p>
|
||||
> </li>
|
||||
> <li>
|
||||
> <p><code>UtcDateTime</code>, which is semantically equivalent to an
|
||||
> <code>OffsetDateTime</code> with UTC as its offset. The
|
||||
> advantage is that it is the same size as a
|
||||
> <code>PrimitiveDateTime</code> and has improved operability with
|
||||
> well-known formats.</p>
|
||||
> <p>As part of this, there were some other additions:</p>
|
||||
> <ul>
|
||||
> <li><code>utc_datetime!</code> macro, which is similar to the
|
||||
> <code>datetime!</code> macro but constructs a
|
||||
> <code>UtcDateTime</code>.</li>
|
||||
> <li><code>PrimitiveDateTime::as_utc</code></li>
|
||||
> <li><code>OffsetDateTime::to_utc</code></li>
|
||||
> <li><code>OffsetDateTime::checked_to_utc</code></li>
|
||||
> </ul>
|
||||
> </li>
|
||||
> <li>
|
||||
> <p><code>time::serde::timestamp::milliseconds_i64</code>, which is a
|
||||
> module to serialize/deserialize timestamps
|
||||
> as the Unix timestamp. The pre-existing module does this as an
|
||||
> <code>i128</code> where an <code>i64</code> would
|
||||
> suffice. This new module should be preferred.</p>
|
||||
> </li>
|
||||
> </ul>
|
||||
> <h3>Changed</h3>
|
||||
> <ul>
|
||||
> <li><code>error::Format</code> has had its <code>source()</code>
|
||||
> implementation changed to no longer return a boxed value
|
||||
> from the <code>ComponentRange</code> variant. If you were explicitly
|
||||
> expecting this, you will need to update
|
||||
> your code. The method API remains unchanged.</li>
|
||||
> <li><code>[year repr:century]</code> supports single-digit values.</li>
|
||||
> <li>All <code>format_into</code> methods accept <code>?Sized</code>
|
||||
> references.</li>
|
||||
> </ul>
|
||||
> <h3>Miscellaneous</h3>
|
||||
> <ul>
|
||||
> <li>Some non-exhaustive enum variants that are no longer used have been
|
||||
> modified to be statically
|
||||
> proven as uninhabited. The relevant fields are doc-hidden and not
|
||||
> semver-guaranteed to remain as
|
||||
> such, though it is unlikely to change.</li>
|
||||
> <li>An unnecessary check when parsing RFC 2822 has been removed.</li>
|
||||
> <li>Various methods have had their implementations changed, resulting in
|
||||
> significant performance
|
||||
> gains. Among the methods changed are
|
||||
> <ul>
|
||||
> <li><code>util::is_leap_year</code></li>
|
||||
> <li><code>util::weeks_in_year</code></li>
|
||||
> <li><code>Month::length</code></li>
|
||||
> <li><code>Date::to_calendar_date</code></li>
|
||||
> </ul>
|
||||
> </li>
|
||||
> </ul>
|
||||
> <!-- raw HTML omitted -->
|
||||
> </blockquote>
|
||||
> <p>... (truncated)</p>
|
||||
> </details>
|
||||
> <details>
|
||||
> <summary>Commits</summary>
|
||||
> <ul>
|
||||
> <li><a
|
||||
> href="https://github.com/time-rs/time/commit/7949d2c2e8ee441d39d4acf4b9653739727b6b8b"><code>7949d2c</code></a>
|
||||
> v0.3.39 release</li>
|
||||
> <li><a
|
||||
> href="https://github.com/time-rs/time/commit/f51623b653f31579e230998b23f2e659b6fef46e"><code>f51623b</code></a>
|
||||
> Fix breakage from v0.3.38</li>
|
||||
> <li><a
|
||||
> href="https://github.com/time-rs/time/commit/1a31c0595b232df9f397f4e5e6768c7eb4220c27"><code>1a31c05</code></a>
|
||||
> v0.3.38 release</li>
|
||||
> <li><a
|
||||
> href="https://github.com/time-rs/time/commit/addf231ef500789dae31e715795d8a33cb658bbf"><code>addf231</code></a>
|
||||
> Permit unsized writers for <code>format_into</code></li>
|
||||
> <li><a
|
||||
> href="https://github.com/time-rs/time/commit/338f84f54522441ff3e7d0f5c5877314f0725608"><code>338f84f</code></a>
|
||||
> Allow clippy::ref_option lint for serde::format_description.</li>
|
||||
> <li><a
|
||||
> href="https://github.com/time-rs/time/commit/f8ecd81e8f14e14f5456eef49e7184f365b56949"><code>f8ecd81</code></a>
|
||||
> feat: timestamp::milliseconds_i64 serializer</li>
|
||||
> <li><a
|
||||
> href="https://github.com/time-rs/time/commit/ce03bcab8fc0aaaa6e9a27ad335abf8fab7eeec1"><code>ce03bca</code></a>
|
||||
> Update Unicode license for cargo-audit</li>
|
||||
> <li><a
|
||||
> href="https://github.com/time-rs/time/commit/3d0b981381de87d2be924129af3fdb9626bfe049"><code>3d0b981</code></a>
|
||||
> Add parentheses for clarity</li>
|
||||
> <li><a
|
||||
> href="https://github.com/time-rs/time/commit/3096301eb3fb5f5104d4182d35184551ce064d5a"><code>3096301</code></a>
|
||||
> Remove specific year from license</li>
|
||||
> <li><a
|
||||
> href="https://github.com/time-rs/time/commit/ec327a26dbe8f3e3db612e8c82b9e35a39361f1c"><code>ec327a2</code></a>
|
||||
> Optimize Julian day calculations</li>
|
||||
> <li>Additional commits viewable in <a
|
||||
> href="https://github.com/time-rs/time/compare/v0.3.37...v0.3.39">compare
|
||||
> view</a></li>
|
||||
> </ul>
|
||||
> </details>
|
||||
> <br />
|
||||
>
|
||||
>
|
||||
> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
|
||||
>
|
||||
> Dependabot will resolve any conflicts with this PR as long as you don't
|
||||
> alter it yourself. You can also trigger a rebase manually by commenting
|
||||
> `@dependabot rebase`.
|
||||
>
|
||||
> [//]:# (dependabot-automerge-start)
|
||||
>
|
||||
> [//]:# (dependabot-automerge-end)
|
||||
>
|
||||
> ---
|
||||
>
|
||||
> <details>
|
||||
> <summary>Dependabot commands and options</summary>
|
||||
> <br />
|
||||
>
|
||||
> You can trigger Dependabot actions by commenting on this PR:
|
||||
> - `@dependabot rebase` will rebase this PR
|
||||
> - `@dependabot recreate` will recreate this PR, overwriting any edits
|
||||
> that have been made to it
|
||||
> - `@dependabot merge` will merge this PR after your CI passes on it
|
||||
> - `@dependabot squash and merge` will squash and merge this PR after
|
||||
> your CI passes on it
|
||||
> - `@dependabot cancel merge` will cancel a previously requested merge
|
||||
> and block automerging
|
||||
> - `@dependabot reopen` will reopen this PR if it is closed
|
||||
> - `@dependabot close` will close this PR and stop Dependabot recreating
|
||||
> it. You can achieve the same result by closing it manually
|
||||
> - `@dependabot show <dependency name> ignore conditions` will show all
|
||||
> of the ignore conditions of the specified dependency
|
||||
> - `@dependabot ignore this major version` will close this PR and stop
|
||||
> Dependabot creating any more for this major version (unless you reopen
|
||||
> the PR or upgrade to it yourself)
|
||||
> - `@dependabot ignore this minor version` will close this PR and stop
|
||||
> Dependabot creating any more for this minor version (unless you reopen
|
||||
> the PR or upgrade to it yourself)
|
||||
> - `@dependabot ignore this dependency` will close this PR and stop
|
||||
> Dependabot creating any more for this dependency (unless you reopen the
|
||||
> PR or upgrade to it yourself)
|
||||
>
|
||||
>
|
||||
> </details>
|
||||
|
||||
- [5710b7a](https://github.com/ratatui/ratatui/commit/5710b7a8d9630eb36fe3d87b748bf5cf2c7b1ec3) *(deps)* Bump rstest from 0.24.0 to 0.25.0 by @dependabot[bot] in [#1695](https://github.com/ratatui/ratatui/pull/1695)
|
||||
|
||||
> Bumps [rstest](https://github.com/la10736/rstest) from 0.24.0 to 0.25.0.
|
||||
> <details>
|
||||
> <summary>Release notes</summary>
|
||||
> <p><em>Sourced from <a
|
||||
> href="https://github.com/la10736/rstest/releases">rstest's
|
||||
> releases</a>.</em></p>
|
||||
> <blockquote>
|
||||
> <h2>0.25.0</h2>
|
||||
> <h2>What's Changed</h2>
|
||||
> <ul>
|
||||
> <li>Append generated test macro so next test macros are aware of it by
|
||||
> <a href="https://github.com/kezhuw"><code>@kezhuw</code></a> in <a
|
||||
> href="https://redirect.github.com/la10736/rstest/pull/291">la10736/rstest#291</a></li>
|
||||
> <li>feat: add <code>include_str</code> and <code>include_bytes</code>
|
||||
> file input behaviour by <a
|
||||
> href="https://github.com/lucascool12"><code>@lucascool12</code></a> in
|
||||
> <a
|
||||
> href="https://redirect.github.com/la10736/rstest/pull/297">la10736/rstest#297</a></li>
|
||||
> </ul>
|
||||
> <h2>New Contributors</h2>
|
||||
> <ul>
|
||||
> <li><a href="https://github.com/kezhuw"><code>@kezhuw</code></a> made
|
||||
> their first contribution in <a
|
||||
> href="https://redirect.github.com/la10736/rstest/pull/291">la10736/rstest#291</a></li>
|
||||
> <li><a
|
||||
> href="https://github.com/lucascool12"><code>@lucascool12</code></a>
|
||||
> made their first contribution in <a
|
||||
> href="https://redirect.github.com/la10736/rstest/pull/297">la10736/rstest#297</a></li>
|
||||
> </ul>
|
||||
> <p><strong>Full Changelog</strong>: <a
|
||||
> href="https://github.com/la10736/rstest/compare/v0.24.0...v0.25.0">https://github.com/la10736/rstest/compare/v0.24.0...v0.25.0</a></p>
|
||||
> </blockquote>
|
||||
> </details>
|
||||
> <details>
|
||||
> <summary>Changelog</summary>
|
||||
> <p><em>Sourced from <a
|
||||
> href="https://github.com/la10736/rstest/blob/master/CHANGELOG.md">rstest's
|
||||
> changelog</a>.</em></p>
|
||||
> <blockquote>
|
||||
> <h2>[0.25.0] 2025/3/2</h2>
|
||||
> <h3>Changed</h3>
|
||||
> <ul>
|
||||
> <li>Append generated test macro so next test macros are aware of it
|
||||
> (see <a
|
||||
> href="https://redirect.github.com/la10736/rstest/pull/291">#291</a>
|
||||
> thanks to <a
|
||||
> href="https://github.com/kezhuw"><code>@kezhuw</code></a>).</li>
|
||||
> </ul>
|
||||
> <h3>Add</h3>
|
||||
> <ul>
|
||||
> <li>Added a <code>#[mode = ...]</code> attribute to be used with the
|
||||
> <code>#[files(...)]</code> attribute to change the way
|
||||
> the files get passed to the test.
|
||||
> (see <a
|
||||
> href="https://redirect.github.com/la10736/rstest/issues/295">#295</a>
|
||||
> thanks to <a
|
||||
> href="https://github.com/lucascool12"><code>@lucascool12</code></a>)</li>
|
||||
> </ul>
|
||||
> </blockquote>
|
||||
> </details>
|
||||
> <details>
|
||||
> <summary>Commits</summary>
|
||||
> <ul>
|
||||
> <li><a
|
||||
> href="https://github.com/la10736/rstest/commit/8d80cea3896753c8674ad138ab620e8b17b923d4"><code>8d80cea</code></a>
|
||||
> Prepare release</li>
|
||||
> <li><a
|
||||
> href="https://github.com/la10736/rstest/commit/eb1f228eacde50d589d95509417a2ccb4f8d0c28"><code>eb1f228</code></a>
|
||||
> Make clippy happy</li>
|
||||
> <li><a
|
||||
> href="https://github.com/la10736/rstest/commit/f570b0605b192990f6723a6fc3300585a86b45d1"><code>f570b06</code></a>
|
||||
> Avoid concurrent manifest changes in integration tests</li>
|
||||
> <li><a
|
||||
> href="https://github.com/la10736/rstest/commit/8551eb8e29870d466b0b95a7a64fc676e476aba4"><code>8551eb8</code></a>
|
||||
> feat: add <code>include_str</code> and <code>include_bytes</code> file
|
||||
> input behaviour</li>
|
||||
> <li><a
|
||||
> href="https://github.com/la10736/rstest/commit/e0b735e9c2ee96b55cd3e1c1073235169698ca0b"><code>e0b735e</code></a>
|
||||
> Append generated test macro so next test macros are aware of it</li>
|
||||
> <li><a
|
||||
> href="https://github.com/la10736/rstest/commit/154d0b0d3f4766cf4107441ce26936711559fc75"><code>154d0b0</code></a>
|
||||
> Prepare develop</li>
|
||||
> <li>See full diff in <a
|
||||
> href="https://github.com/la10736/rstest/compare/v0.24.0...v0.25.0">compare
|
||||
> view</a></li>
|
||||
> </ul>
|
||||
> </details>
|
||||
> <br />
|
||||
>
|
||||
>
|
||||
> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
|
||||
>
|
||||
> Dependabot will resolve any conflicts with this PR as long as you don't
|
||||
> alter it yourself. You can also trigger a rebase manually by commenting
|
||||
> `@dependabot rebase`.
|
||||
>
|
||||
> [//]:# (dependabot-automerge-start)
|
||||
>
|
||||
> [//]:# (dependabot-automerge-end)
|
||||
>
|
||||
> ---
|
||||
>
|
||||
> <details>
|
||||
> <summary>Dependabot commands and options</summary>
|
||||
> <br />
|
||||
>
|
||||
> You can trigger Dependabot actions by commenting on this PR:
|
||||
> - `@dependabot rebase` will rebase this PR
|
||||
> - `@dependabot recreate` will recreate this PR, overwriting any edits
|
||||
> that have been made to it
|
||||
> - `@dependabot merge` will merge this PR after your CI passes on it
|
||||
> - `@dependabot squash and merge` will squash and merge this PR after
|
||||
> your CI passes on it
|
||||
> - `@dependabot cancel merge` will cancel a previously requested merge
|
||||
> and block automerging
|
||||
> - `@dependabot reopen` will reopen this PR if it is closed
|
||||
> - `@dependabot close` will close this PR and stop Dependabot recreating
|
||||
> it. You can achieve the same result by closing it manually
|
||||
> - `@dependabot show <dependency name> ignore conditions` will show all
|
||||
> of the ignore conditions of the specified dependency
|
||||
> - `@dependabot ignore this major version` will close this PR and stop
|
||||
> Dependabot creating any more for this major version (unless you reopen
|
||||
> the PR or upgrade to it yourself)
|
||||
> - `@dependabot ignore this minor version` will close this PR and stop
|
||||
> Dependabot creating any more for this minor version (unless you reopen
|
||||
> the PR or upgrade to it yourself)
|
||||
> - `@dependabot ignore this dependency` will close this PR and stop
|
||||
> Dependabot creating any more for this dependency (unless you reopen the
|
||||
> PR or upgrade to it yourself)
|
||||
>
|
||||
>
|
||||
> </details>
|
||||
|
||||
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/ratatui/ratatui/compare/ratatui-v0.30.0-alpha.2...ratatui-v0.30.0-alpha.3
|
||||
|
||||
|
||||
|
||||
## ratatui-termion - [0.1.0-alpha.3](https://github.com/ratatui/ratatui/compare/ratatui-termion-v0.1.0-alpha.2...ratatui-termion-v0.1.0-alpha.3) - 2025-05-13
|
||||
|
||||
### Features
|
||||
@@ -2310,17 +1405,8 @@ All notable changes to this project will be documented in this file.
|
||||
>
|
||||
> BREAKING CHANGE:MSRV is now 1.81
|
||||
|
||||
### Build
|
||||
|
||||
- [daeba85](https://github.com/ratatui/ratatui/commit/daeba85f144ead00803c7540fa39ff6d623321c7) *(deps)* Bump `kasuari` and `line-clipping` by @j-g00da in [#1844](https://github.com/ratatui/ratatui/pull/1844)
|
||||
|
||||
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/ratatui/ratatui/compare/ratatui-widgets-v0.3.0-alpha.2...ratatui-widgets-v0.3.0-alpha.3
|
||||
|
||||
|
||||
|
||||
## ratatui-crossterm - [0.1.0-alpha.3](https://github.com/ratatui/ratatui/compare/ratatui-crossterm-v0.1.0-alpha.2...ratatui-crossterm-v0.1.0-alpha.3) - 2025-05-13
|
||||
|
||||
### Features
|
||||
@@ -2605,29 +1691,8 @@ All notable changes to this project will be documented in this file.
|
||||
>
|
||||
> Fixes:https://github.com/ratatui/ratatui/issues/1712
|
||||
|
||||
### Build
|
||||
|
||||
- [daeba85](https://github.com/ratatui/ratatui/commit/daeba85f144ead00803c7540fa39ff6d623321c7) *(deps)* Bump `kasuari` and `line-clipping` by @j-g00da in [#1844](https://github.com/ratatui/ratatui/pull/1844)
|
||||
|
||||
- [fc4b996](https://github.com/ratatui/ratatui/commit/fc4b996c596aec8316427bc71677fbfcce68caed) *(deps)* Update compact_str requirement from 0.8.1 to 0.9.0 by @musicinmybrain in [#1783](https://github.com/ratatui/ratatui/pull/1783)
|
||||
|
||||
> Looking at
|
||||
> https://github.com/ParkMyCar/compact_str/blob/v0.9.0/CHANGELOG.md#090,
|
||||
> there are a few API changes, but it doesn’t seem like anything there
|
||||
> should be a problem given that `cargo test` still passes in
|
||||
> `ratatui-core/`.
|
||||
|
||||
- [3d5b250](https://github.com/ratatui/ratatui/commit/3d5b250e74fc83fb580f50b617472be7cfb4fd4b) *(deps)* Use kasuari instead of cassowary by @joshka in [#1758](https://github.com/ratatui/ratatui/pull/1758)
|
||||
|
||||
> [Kasuari](https://github.com/ratatui/kasuari) is a maintained fork of Cassowary.
|
||||
|
||||
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/ratatui/ratatui/compare/ratatui-core-v0.1.0-alpha.3...ratatui-core-v0.1.0-alpha.4
|
||||
|
||||
|
||||
|
||||
## ratatui - [0.30.0-alpha.2](https://github.com/ratatui/ratatui/compare/ratatui-v0.30.0-alpha.1...ratatui-v0.30.0-alpha.2) - 2025-03-01
|
||||
|
||||
### Features
|
||||
|
||||
@@ -29,6 +29,26 @@ change becomes a place where a bug may have been introduced. Consider splitting
|
||||
reformatting changes into a separate PR from those that make a behavioral change, as the tests help
|
||||
guarantee that the behavior is unchanged.
|
||||
|
||||
Guidelines for PR size:
|
||||
|
||||
- Aim for PRs under 500 lines of changes when possible.
|
||||
- Split large features into incremental PRs that build on each other.
|
||||
- Separate refactoring, formatting, and functional changes into different PRs.
|
||||
- If a large PR is unavoidable, clearly explain why in the PR description.
|
||||
|
||||
### Breaking changes and backwards compatibility
|
||||
|
||||
We prioritize maintaining backwards compatibility and minimizing disruption to users:
|
||||
|
||||
- **Prefer deprecation over removal**: Add deprecation warnings rather than immediately removing
|
||||
public APIs
|
||||
- **Provide migration paths**: Include clear upgrade instructions for any breaking changes
|
||||
- **Follow our deprecation policy**: Wait at least two versions before removing deprecated items
|
||||
- **Consider feature flags**: Use feature flags for experimental or potentially disruptive changes
|
||||
- **Document breaking changes**: Clearly mark breaking changes in commit messages and PR descriptions
|
||||
|
||||
See our [deprecation notice policy](#deprecation-notice) for more details.
|
||||
|
||||
### Code formatting
|
||||
|
||||
Run `cargo xtask format` before committing to ensure that code is consistently formatted with
|
||||
@@ -41,6 +61,10 @@ to be installed when running rustfmt. You can install the nightly version of Rus
|
||||
rustup install nightly
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Do not modify formatting configuration (`rustfmt.toml`, `.clippy.toml`) without
|
||||
> prior discussion. These changes affect all contributors and should be carefully considered.
|
||||
|
||||
### Search `tui-rs` for similar work
|
||||
|
||||
The original fork of Ratatui, [`tui-rs`](https://github.com/fdehau/tui-rs/), has a large amount of
|
||||
@@ -67,6 +91,15 @@ Running `cargo xtask ci` before pushing will perform the same checks that we do
|
||||
It's not mandatory to do this before pushing, however it may save you time to do so instead of
|
||||
waiting for GitHub to run the checks.
|
||||
|
||||
Available xtask commands:
|
||||
|
||||
- `cargo xtask ci` - Run all CI checks
|
||||
- `cargo xtask format` - Format code
|
||||
- `cargo xtask lint` - Run linting checks
|
||||
- `cargo xtask test` - Run all tests
|
||||
|
||||
Run `cargo xtask --help` to see all available commands.
|
||||
|
||||
### Sign your commits
|
||||
|
||||
We use commit signature verification, which will block commits from being merged via the UI unless
|
||||
@@ -74,6 +107,17 @@ they are signed. To set up your machine to sign commits, see [managing commit si
|
||||
verification](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)
|
||||
in GitHub docs.
|
||||
|
||||
### Configuration and build system changes
|
||||
|
||||
Changes to project configuration files require special consideration:
|
||||
|
||||
- Linting configuration (`.clippy.toml`, `rustfmt.toml`): Affects all contributors.
|
||||
- CI configuration (`.github/workflows/`): Affects build and deployment.
|
||||
- Build system (`xtask/`, `Cargo.toml` workspace config): Affects development workflow.
|
||||
- Dependencies: Consider MSRV compatibility and licensing.
|
||||
|
||||
Please discuss these changes in an issue before implementing them.
|
||||
|
||||
## Implementation Guidelines
|
||||
|
||||
### Setup
|
||||
@@ -97,7 +141,13 @@ For an understanding of the crate organization and design decisions, see [ARCHIT
|
||||
document explains the modular workspace structure introduced in version 0.30.0 and provides
|
||||
guidance on which crate to use for different use cases.
|
||||
|
||||
[ARCHITECTURE.md]: ./ARCHITECTURE.md
|
||||
When making changes, consider:
|
||||
|
||||
- Which crate should contain your changes per the modular structure,
|
||||
- Whether your changes affect the public API of `ratatui-core` (requires extra care),
|
||||
- And how your changes fit into the overall architecture.
|
||||
|
||||
[ARCHITECTURE.md]: https://github.com/ratatui/ratatui/blob/main/ARCHITECTURE.md
|
||||
|
||||
### Tests
|
||||
|
||||
@@ -115,6 +165,10 @@ If an area that you're making a change in is not tested, write tests to characte
|
||||
behavior before changing it. This helps ensure that we don't introduce bugs to existing software
|
||||
using Ratatui (and helps make it easy to migrate apps still using `tui-rs`).
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Do not remove existing tests without clear justification. If tests need to be
|
||||
> modified due to API changes, explain why in your PR description.
|
||||
|
||||
For coverage, we have two [bacon](https://dystroy.org/bacon/) jobs (one for all tests, and one for
|
||||
unit tests, keyboard shortcuts `v` and `u` respectively) that run
|
||||
[cargo-llvm-cov](https://github.com/taiki-e/cargo-llvm-cov) to report the coverage. Several plugins
|
||||
@@ -182,6 +236,14 @@ We generally want to wait at least two versions before removing deprecated items
|
||||
time to update. However, if a deprecation is blocking for us to implement a new feature we may
|
||||
*consider* removing it in a one version notice.
|
||||
|
||||
Deprecation process:
|
||||
|
||||
1. Add `#[deprecated]` attribute with a clear message.
|
||||
2. Update documentation to point to the replacement.
|
||||
3. Add an entry to `BREAKING-CHANGES.md` if applicable.
|
||||
4. Wait at least two versions before removal.
|
||||
5. Consider the impact on the ecosystem before removing.
|
||||
|
||||
### Use of unsafe for optimization purposes
|
||||
|
||||
We don't currently use any unsafe code in Ratatui, and would like to keep it that way. However, there
|
||||
|
||||
294
Cargo.lock
generated
294
Cargo.lock
generated
@@ -274,15 +274,6 @@ dependencies = [
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "canvas"
|
||||
version = "0.0.0"
|
||||
@@ -293,69 +284,6 @@ dependencies = [
|
||||
"ratatui",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-platform"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-platform"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84982c6c0ae343635a3a4ee6dedef965513735c8b183caa7289fa6e27399ebd4"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-util-schemas"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e63d2780ac94487eb9f1fea7b0d56300abc9eb488800854ca217f102f5caccca"
|
||||
dependencies = [
|
||||
"semver",
|
||||
"serde",
|
||||
"serde-untagged",
|
||||
"serde-value",
|
||||
"thiserror 1.0.69",
|
||||
"toml",
|
||||
"unicode-xid",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.19.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"cargo-platform 0.1.9",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f7835cfc6135093070e95eb2b53e5d9b5c403dc3a6be6040ee026270aa82502"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"cargo-platform 0.2.0",
|
||||
"cargo-util-schemas",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.3.0"
|
||||
@@ -364,18 +292,18 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "castaway"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5"
|
||||
checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.27"
|
||||
version = "1.2.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
|
||||
checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@@ -445,27 +373,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.40"
|
||||
version = "4.5.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
|
||||
checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap-cargo"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d546f0e84ff2bfa4da1ce9b54be42285767ba39c688572ca32412a09a73851e5"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"cargo_metadata 0.19.2",
|
||||
"clap",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap-verbosity-flag"
|
||||
version = "3.0.3"
|
||||
@@ -478,9 +393,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.40"
|
||||
version = "4.5.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
|
||||
checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -490,9 +405,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.40"
|
||||
version = "4.5.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
|
||||
checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@@ -819,7 +734,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"crossterm",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"ratatui",
|
||||
"termion",
|
||||
"termwiz",
|
||||
@@ -834,7 +749,7 @@ dependencies = [
|
||||
"indoc",
|
||||
"itertools 0.14.0",
|
||||
"palette",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.9.0",
|
||||
"ratatui",
|
||||
"strum",
|
||||
@@ -938,16 +853,6 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "erased-serde"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"typeid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.13"
|
||||
@@ -1356,9 +1261,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.14"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
|
||||
checksum = "7f66d5bd4c6f02bf0542fad85d626775bab9258cf795a4256dcaf3161114d1df"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -1530,9 +1435,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.9.0"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@@ -1550,7 +1455,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"color-eyre",
|
||||
"crossterm",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"ratatui",
|
||||
]
|
||||
|
||||
@@ -1567,9 +1472,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "instability"
|
||||
version = "0.3.7"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bf9fed6d91cfb734e7476a06bde8300a1b94e217e1b523b6f0cd1a01998c71d"
|
||||
checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"indoc",
|
||||
@@ -1578,6 +1483,17 @@ dependencies = [
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-uring"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iri-string"
|
||||
version = "0.7.8"
|
||||
@@ -1665,9 +1581,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kasuari"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "def1b67294a9fdc95eeeeafd1209c7a1b8a82aa0bf80ac2ab2a7d0318e9c7622"
|
||||
version = "0.4.7"
|
||||
source = "git+https://github.com/j-g00da/kasuari.git?branch=js%2Fcycle-prevention#dd15b398666924a192ca05d5a6d207df9c84afe3"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"thiserror 2.0.12",
|
||||
@@ -1870,7 +1785,7 @@ dependencies = [
|
||||
"color-eyre",
|
||||
"crossterm",
|
||||
"line_drawing",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"ratatui",
|
||||
]
|
||||
|
||||
@@ -2041,15 +1956,6 @@ version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "2.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "4.6.0"
|
||||
@@ -2438,9 +2344,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.1"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
@@ -2572,7 +2478,7 @@ dependencies = [
|
||||
"instability",
|
||||
"palette",
|
||||
"pretty_assertions",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.9.0",
|
||||
"ratatui-core",
|
||||
"ratatui-crossterm",
|
||||
@@ -2859,9 +2765,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.28"
|
||||
version = "0.23.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643"
|
||||
checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
@@ -2895,9 +2801,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.3"
|
||||
version = "0.103.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435"
|
||||
checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
@@ -2986,9 +2892,6 @@ name = "semver"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
@@ -2999,27 +2902,6 @@ dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-untagged"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "299d9c19d7d466db4ab10addd5703e4c615dec2a5a16dbbafe191045e87ee66e"
|
||||
dependencies = [
|
||||
"erased-serde",
|
||||
"serde",
|
||||
"typeid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-value"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
|
||||
dependencies = [
|
||||
"ordered-float 2.10.1",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.219"
|
||||
@@ -3033,9 +2915,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.140"
|
||||
version = "1.0.141"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
@@ -3055,9 +2937,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.9"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
|
||||
checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -3096,9 +2978,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "shared_child"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2778001df1384cf20b6dc5a5a90f48da35539885edaaefd887f8d744e939c0b"
|
||||
checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"sigchld",
|
||||
@@ -3119,9 +3001,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "sigchld"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1219ef50fc0fdb04fcc243e6aa27f855553434ffafe4fa26554efb78b5b4bf89"
|
||||
checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"os_pipe",
|
||||
@@ -3248,9 +3130,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.27.1"
|
||||
version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
|
||||
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
|
||||
dependencies = [
|
||||
"strum_macros",
|
||||
]
|
||||
@@ -3395,7 +3277,7 @@ dependencies = [
|
||||
"nix",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"ordered-float 4.6.0",
|
||||
"ordered-float",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"phf",
|
||||
@@ -3530,14 +3412,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.45.1"
|
||||
version = "1.46.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
|
||||
checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"io-uring",
|
||||
"libc",
|
||||
"mio",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.52.0",
|
||||
@@ -3590,14 +3474,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.23"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
|
||||
checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
"toml_datetime 0.7.0",
|
||||
"toml_parser",
|
||||
"toml_writer",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3605,6 +3492,12 @@ name = "toml_datetime"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -3616,18 +3509,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_write",
|
||||
"toml_datetime 0.6.11",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_write"
|
||||
version = "0.1.2"
|
||||
name = "toml_parser"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
||||
checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_writer"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
@@ -3781,9 +3680,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "trybuild"
|
||||
version = "1.0.105"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c9bf9513a2f4aeef5fdac8677d7d349c79fdbcc03b9c86da6e9d254f1e43be2"
|
||||
checksum = "65af40ad689f2527aebbd37a0a816aea88ff5f774ceabe99de5be02f2f91dae2"
|
||||
dependencies = [
|
||||
"dissimilar",
|
||||
"glob",
|
||||
@@ -3795,12 +3694,6 @@ dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typeid"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.18.0"
|
||||
@@ -3838,15 +3731,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
@@ -4028,7 +3915,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"color-eyre",
|
||||
"crossterm",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"ratatui",
|
||||
]
|
||||
|
||||
@@ -4097,7 +3984,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f2ab60e120fd6eaa68d9567f3226e876684639d22a4219b313ff69ec0ccd5ac"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ordered-float 4.6.0",
|
||||
"ordered-float",
|
||||
"strsim",
|
||||
"thiserror 1.0.69",
|
||||
"wezterm-dynamic-derive",
|
||||
@@ -4383,9 +4270,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.11"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
|
||||
checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -4409,13 +4296,10 @@ checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
||||
name = "xtask"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.20.0",
|
||||
"clap",
|
||||
"clap-cargo",
|
||||
"clap-verbosity-flag",
|
||||
"color-eyre",
|
||||
"duct",
|
||||
"itertools 0.14.0",
|
||||
"tracing 0.1.41",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
@@ -41,7 +41,7 @@ hashbrown = "0.15"
|
||||
indoc = "2"
|
||||
instability = "0.3"
|
||||
itertools = { version = "0.14", default-features = false, features = ["use_alloc"] }
|
||||
kasuari = { version = "0.4", default-features = false }
|
||||
kasuari = { git = "https://github.com/j-g00da/kasuari.git", branch = "js/cycle-prevention", default-features = false }
|
||||
line-clipping = "0.3"
|
||||
lru = "0.14"
|
||||
palette = "0.7"
|
||||
@@ -71,7 +71,7 @@ trybuild = "1"
|
||||
unicode-segmentation = "1"
|
||||
unicode-truncate = { version = "2", default-features = false }
|
||||
# See <https://github.com/ratatui/ratatui/issues/1271> for information about why we pin unicode-width
|
||||
unicode-width = "=0.2.0"
|
||||
unicode-width = ">=0.2.0, <=0.2.1"
|
||||
|
||||
# Improve benchmark consistency
|
||||
[profile.bench]
|
||||
|
||||
1
assets/logo-simple.svg
Normal file
1
assets/logo-simple.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg"><title>Ratatui</title><path d="M17 29h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1h1v1H5v-1H4v-1H3v-1H2v-1H1v-1H0v-2h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h2zm-2 14h1v1h1v1h1v-2h-1v-1h-1v-1h-1zm0-6h-3v1h1v1h4v-4h-1v-1h-1zm35-21h-1v4h-1v1h-1v1h-1v1h-2v1h-1v1h-1v1h-1v1h-2v9h5v1h1v9h-1v1h-1v2h-1v1h-1v-1h-1v-1h-1v-1h1v-1h1v-1h1v-5h-1v1h-3v1h-1v3h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-2h1v-2h1v-1h-2v1h-4v-1h-1v-1h-1v-1h-1v-2h1v-1h1v-1h2v-1h7v-1h1v-1h1v-1h1v-1h1v-1h1v-1h4v-1h3v-1h10zm-17 2h-1v2h1v1h2v-1h1v-2h-1v-1h-2zM29 1h1v9h1v1h1v2h1v2h-1v1h-1v1h-1v1h-1v1h-1v1h-3v-1h-1v-1h-2v-1h-1v-1h-1v-1h-6v-1h-1V9h1V8h1V7h1V6h1V5h1V4h1V3h1V2h1V1h2V0h6z"/></svg>
|
||||
|
After Width: | Height: | Size: 831 B |
1
assets/logo.svg
Normal file
1
assets/logo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg role="img" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg"><title>Ratatui</title><path d="M50 16h-1v4h-1v1h-1v1h-1v1h-2v1h-1v1h-1v1h-1v1h-2v9h5v1h1v9h-1v1h-1v2h-1v1h-1v-1h-1v1h-2v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-1v-1h-2v1h-1v1h-1v1h-1v1h-1v1h-1v1h-1v1H9v1H8v1H7v1H6v1H5v1H4v1H3v1H2v2h1v1h1v1h1v1h1v1h1v1H5v-1H4v-1H3v-1H2v-1H1v-1H0v-2h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h1v-1h2v1h1v-1h-1v-1h-1v-2h1v-1h1v-1h2v-1h7v-1h1v-1h1v-1h1v-1h1v-1h1v-1h4v-1h3v-1h10zM39 49h1v-1h-1zm2-8h-3v1h-1v3h-1v-1h-1v1h1v1h1v1h1v1h1v-1h1v-1h1v-1h1v-5h-1zm-7 3h1v-1h-1zm-1-1h1v-1h-1zm-1-1h1v-1h-1zm-1-1h1v-1h-1zm-1-1h1v-1h-1zm-1-1h1v-1h-1zm-1-1h1v-1h-1zm-1-1h1v-1h-1zm-1-1h1v-1h-1zm-1-1h1v-1h-1zm-1-1h1v-1h-1zm-5-5h1v1h1v1h1v1h1v1h1v-2h1v-2h1v-1h-2v1h-4v-1h-1zm14-11h-1v2h1v1h2v-1h1v-2h-1v-1h-2zM18 40h1v1h1v2h-1v-1h-1v-1h-1v-2h1zm0-7h1v4h-4v-1h-1v-1h3v-3h1zM29 1h1v9h1v1h1v2h1v2h-1v1h-1v1h-1v1h-1v1h-1v1h-3v-1h-1v-1h-2v-1h-1v-1h-1v-1h-6v-1h-1V9h1V8h1V7h1V6h1V5h1V4h1V3h1V2h1V1h2V0h6z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
18
bacon.toml
18
bacon.toml
@@ -60,6 +60,22 @@ command = ["cargo", "xtask", "hack"]
|
||||
[jobs.format]
|
||||
command = ["cargo", "xtask", "format"]
|
||||
|
||||
[jobs.zizmor-offline]
|
||||
# zizmor checks the workflow files for security issues. The offline version is generally faster, but
|
||||
# checks for fewer issues.
|
||||
command = ["zizmor", "--color", "always", ".github/workflows", "--offline"]
|
||||
need_stdout = true
|
||||
default_watch = false
|
||||
watch = [".github/workflows/"]
|
||||
|
||||
[jobs.zizmor-online]
|
||||
# zizmor checks the workflow files for security issues. The online version is a bit slower, but it
|
||||
# checks for more issues
|
||||
command = ["zizmor", "--color", "always", ".github/workflows"]
|
||||
need_stdout = true
|
||||
default_watch = false
|
||||
watch = [".github/workflows/"]
|
||||
|
||||
# You may define here keybindings that would be specific to
|
||||
# a project, for example a shortcut to launch a specific job.
|
||||
# Shortcuts to internal functions (scrolling, toggling, etc.)
|
||||
@@ -74,3 +90,5 @@ ctrl-v = "job:coverage-unit-tests-only"
|
||||
u = "job:test-unit"
|
||||
n = "job:nextest"
|
||||
f = "job:format"
|
||||
z = "job:zizmor-offline"
|
||||
shift-z = "job:zizmor-online"
|
||||
|
||||
@@ -115,6 +115,7 @@ commit_parsers = [
|
||||
{ message = "^chore\\(changelog\\)", skip = true },
|
||||
{ message = "^[cC]hore", group = "<!-- 07 -->Miscellaneous Tasks" },
|
||||
{ body = ".*security", group = "<!-- 08 -->Security" },
|
||||
{ message = "^build\\(deps\\)", skip = true },
|
||||
{ message = "^build", group = "<!-- 09 -->Build" },
|
||||
{ message = "^ci", group = "<!-- 10 -->Continuous Integration" },
|
||||
{ message = "^revert", group = "<!-- 11 -->Reverted Commits" },
|
||||
|
||||
@@ -18,5 +18,5 @@ color-eyre = "0.6.5"
|
||||
crossterm = { workspace = true, features = ["event-stream"] }
|
||||
octocrab = "0.44.0"
|
||||
ratatui.workspace = true
|
||||
tokio = { version = "1.45.1", features = ["rt-multi-thread", "macros"] }
|
||||
tokio = { version = "1.46.1", features = ["rt-multi-thread", "macros"] }
|
||||
tokio-stream = "0.1.17"
|
||||
|
||||
@@ -12,9 +12,9 @@ termion = ["ratatui/termion", "dep:termion"]
|
||||
termwiz = ["ratatui/termwiz", "dep:termwiz"]
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.40", features = ["derive"] }
|
||||
clap = { version = "4.5.41", features = ["derive"] }
|
||||
crossterm = { workspace = true, optional = true }
|
||||
rand = "0.9.1"
|
||||
rand = "0.9.2"
|
||||
ratatui.workspace = true
|
||||
termwiz = { workspace = true, optional = true }
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ crossterm.workspace = true
|
||||
indoc.workspace = true
|
||||
itertools.workspace = true
|
||||
palette = "0.7.6"
|
||||
rand = "0.9.1"
|
||||
rand = "0.9.2"
|
||||
rand_chacha = "0.9.0"
|
||||
ratatui = { workspace = true, features = ["all-widgets"] }
|
||||
strum.workspace = true
|
||||
|
||||
@@ -8,7 +8,7 @@ rust-version.workspace = true
|
||||
[dependencies]
|
||||
color-eyre.workspace = true
|
||||
crossterm.workspace = true
|
||||
rand = "0.9.1"
|
||||
rand = "0.9.2"
|
||||
ratatui.workspace = true
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -10,7 +10,7 @@ color-eyre.workspace = true
|
||||
crossterm.workspace = true
|
||||
## a collection of line drawing algorithms (e.g. Bresenham's line algorithm)
|
||||
line_drawing = "1.0.1"
|
||||
rand = "0.9.1"
|
||||
rand = "0.9.2"
|
||||
ratatui.workspace = true
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -8,7 +8,7 @@ rust-version.workspace = true
|
||||
[dependencies]
|
||||
color-eyre.workspace = true
|
||||
crossterm.workspace = true
|
||||
rand = "0.9.1"
|
||||
rand = "0.9.2"
|
||||
ratatui.workspace = true
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::style::{Color, Modifier, Style};
|
||||
use crate::symbols::merge::MergeStrategy;
|
||||
|
||||
/// A buffer cell
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Cell {
|
||||
/// The string to be drawn in the cell.
|
||||
@@ -15,7 +15,7 @@ pub struct Cell {
|
||||
/// buffer for short strings.
|
||||
///
|
||||
/// See <https://github.com/ratatui/ratatui/pull/601> for more information.
|
||||
symbol: CompactString,
|
||||
symbol: Option<CompactString>,
|
||||
|
||||
/// The foreground color of the cell.
|
||||
pub fg: Color,
|
||||
@@ -36,30 +36,35 @@ pub struct Cell {
|
||||
|
||||
impl Cell {
|
||||
/// An empty `Cell`
|
||||
pub const EMPTY: Self = Self::new(" ");
|
||||
pub const EMPTY: Self = Self {
|
||||
symbol: None,
|
||||
fg: Color::Reset,
|
||||
bg: Color::Reset,
|
||||
#[cfg(feature = "underline-color")]
|
||||
underline_color: Color::Reset,
|
||||
modifier: Modifier::empty(),
|
||||
skip: false,
|
||||
};
|
||||
|
||||
/// Creates a new `Cell` with the given symbol.
|
||||
///
|
||||
/// This works at compile time and puts the symbol onto the stack. Fails to build when the
|
||||
/// symbol doesnt fit onto the stack and requires to be placed on the heap. Use
|
||||
/// symbol doesn't fit onto the stack and requires to be placed on the heap. Use
|
||||
/// `Self::default().set_symbol()` in that case. See [`CompactString::const_new`] for more
|
||||
/// details on this.
|
||||
pub const fn new(symbol: &'static str) -> Self {
|
||||
Self {
|
||||
symbol: CompactString::const_new(symbol),
|
||||
fg: Color::Reset,
|
||||
bg: Color::Reset,
|
||||
#[cfg(feature = "underline-color")]
|
||||
underline_color: Color::Reset,
|
||||
modifier: Modifier::empty(),
|
||||
skip: false,
|
||||
symbol: Some(CompactString::const_new(symbol)),
|
||||
..Self::EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the symbol of the cell.
|
||||
///
|
||||
/// If the cell has no symbol, returns a single space character.
|
||||
#[must_use]
|
||||
pub fn symbol(&self) -> &str {
|
||||
self.symbol.as_str()
|
||||
self.symbol.as_ref().map_or(" ", |s| s.as_str())
|
||||
}
|
||||
|
||||
/// Merges the symbol of the cell with the one already on the cell, using the provided
|
||||
@@ -73,6 +78,9 @@ impl Cell {
|
||||
/// produce a valid character. [`MergeStrategy`] defines how to handle such cases, e.g.,
|
||||
/// `Exact` for valid merges only, or `Fuzzy` for close matches.
|
||||
///
|
||||
/// If the cell has no symbol set, it will set the symbol to the provided one rather than
|
||||
/// merging.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
@@ -97,14 +105,17 @@ impl Cell {
|
||||
/// [border collapsing]: https://ratatui.rs/recipes/layout/collapse-borders/
|
||||
/// [Box Drawing Unicode block]: https://en.wikipedia.org/wiki/Box_Drawing
|
||||
pub fn merge_symbol(&mut self, symbol: &str, strategy: MergeStrategy) -> &mut Self {
|
||||
let merged = strategy.merge(self.symbol(), symbol);
|
||||
self.symbol = CompactString::new(merged);
|
||||
let merged_symbol = self
|
||||
.symbol
|
||||
.as_ref()
|
||||
.map_or(symbol, |s| strategy.merge(s, symbol));
|
||||
self.symbol = Some(CompactString::new(merged_symbol));
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the symbol of the cell.
|
||||
pub fn set_symbol(&mut self, symbol: &str) -> &mut Self {
|
||||
self.symbol = CompactString::new(symbol);
|
||||
self.symbol = Some(CompactString::new(symbol));
|
||||
self
|
||||
}
|
||||
|
||||
@@ -112,14 +123,14 @@ impl Cell {
|
||||
///
|
||||
/// This is particularly useful for adding zero-width characters to the cell.
|
||||
pub(crate) fn append_symbol(&mut self, symbol: &str) -> &mut Self {
|
||||
self.symbol.push_str(symbol);
|
||||
self.symbol.get_or_insert_default().push_str(symbol);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the symbol of the cell to a single character.
|
||||
pub fn set_char(&mut self, ch: char) -> &mut Self {
|
||||
let mut buf = [0; 4];
|
||||
self.symbol = CompactString::new(ch.encode_utf8(&mut buf));
|
||||
self.symbol = Some(CompactString::new(ch.encode_utf8(&mut buf)));
|
||||
self
|
||||
}
|
||||
|
||||
@@ -180,21 +191,49 @@ impl Cell {
|
||||
|
||||
/// Resets the cell to the empty state.
|
||||
pub fn reset(&mut self) {
|
||||
self.symbol = CompactString::const_new(" ");
|
||||
self.fg = Color::Reset;
|
||||
self.bg = Color::Reset;
|
||||
#[cfg(feature = "underline-color")]
|
||||
{
|
||||
self.underline_color = Color::Reset;
|
||||
}
|
||||
self.modifier = Modifier::empty();
|
||||
self.skip = false;
|
||||
*self = Self::EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Cell {
|
||||
fn default() -> Self {
|
||||
Self::EMPTY
|
||||
impl PartialEq for Cell {
|
||||
/// Compares two `Cell`s for equality.
|
||||
///
|
||||
/// Note that cells with no symbol (i.e., `Cell::EMPTY`) are considered equal to cells with a
|
||||
/// single space symbol. This is to ensure that empty cells are treated uniformly,
|
||||
/// regardless of how they were created
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
// Treat None and Some(" ") as equal
|
||||
let symbols_eq = self.symbol() == other.symbol();
|
||||
|
||||
#[cfg(feature = "underline-color")]
|
||||
let underline_color_eq = self.underline_color == other.underline_color;
|
||||
#[cfg(not(feature = "underline-color"))]
|
||||
let underline_color_eq = true;
|
||||
|
||||
symbols_eq
|
||||
&& underline_color_eq
|
||||
&& self.fg == other.fg
|
||||
&& self.bg == other.bg
|
||||
&& self.modifier == other.modifier
|
||||
&& self.skip == other.skip
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Cell {}
|
||||
|
||||
impl core::hash::Hash for Cell {
|
||||
/// Hashes the cell.
|
||||
///
|
||||
/// This treats symbols with Some(" ") as equal to None, so that empty cells are
|
||||
/// treated uniformly, regardless of how they were created.
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.symbol().hash(state);
|
||||
self.fg.hash(state);
|
||||
self.bg.hash(state);
|
||||
#[cfg(feature = "underline-color")]
|
||||
self.underline_color.hash(state);
|
||||
self.modifier.hash(state);
|
||||
self.skip.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +255,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
cell,
|
||||
Cell {
|
||||
symbol: CompactString::const_new("あ"),
|
||||
symbol: Some(CompactString::const_new("あ")),
|
||||
fg: Color::Reset,
|
||||
bg: Color::Reset,
|
||||
#[cfg(feature = "underline-color")]
|
||||
|
||||
@@ -626,7 +626,7 @@ impl Layout {
|
||||
.expect("invalid number of rects")
|
||||
}
|
||||
|
||||
/// Wrapper function around the cassowary solver to be able to split a given area into
|
||||
/// Wrapper function around the [`kasuari`] solver to be able to split a given area into
|
||||
/// smaller ones based on the preferred widths or heights and the direction.
|
||||
///
|
||||
/// Note that the constraints are applied to the whole area that is to be split, so using
|
||||
@@ -664,7 +664,7 @@ impl Layout {
|
||||
self.split_with_spacers(area).0
|
||||
}
|
||||
|
||||
/// Wrapper function around the cassowary solver that splits the given area into smaller ones
|
||||
/// Wrapper function around the [`kasuari`] solver that splits the given area into smaller ones
|
||||
/// based on the preferred widths or heights and the direction, with the ability to include
|
||||
/// spacers between the areas.
|
||||
///
|
||||
@@ -726,7 +726,7 @@ impl Layout {
|
||||
}
|
||||
|
||||
fn try_split(&self, area: Rect) -> Result<(Segments, Spacers), AddConstraintError> {
|
||||
// To take advantage of all of cassowary features, we would want to store the `Solver` in
|
||||
// To take advantage of all of [`kasuari`] features, we would want to store the `Solver` in
|
||||
// one of the fields of the Layout struct. And we would want to set it up such that we could
|
||||
// add or remove constraints as and when needed.
|
||||
// The advantage of doing it as described above is that it would allow users to
|
||||
@@ -2834,5 +2834,11 @@ mod tests {
|
||||
.collect::<Vec<(u16, u16)>>();
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[timeout(core::time::Duration::from_secs(10))]
|
||||
fn regression_1855() {
|
||||
Layout::horizontal(vec![Min(0); 40]).split(Rect::new(0, 0, 40, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +190,8 @@ impl From<anstyle::Style> for Style {
|
||||
Self {
|
||||
fg: style.get_fg_color().map(Color::from),
|
||||
bg: style.get_bg_color().map(Color::from),
|
||||
#[cfg(feature = "underline-color")]
|
||||
underline_color: style.get_underline_color().map(Color::from),
|
||||
add_modifier: style.get_effects().into(),
|
||||
..Default::default()
|
||||
}
|
||||
@@ -207,6 +209,11 @@ impl From<Style> for anstyle::Style {
|
||||
let bg = anstyle::Color::from(bg);
|
||||
anstyle_style = anstyle_style.bg_color(Some(bg));
|
||||
}
|
||||
#[cfg(feature = "underline-color")]
|
||||
if let Some(underline) = style.underline_color {
|
||||
let underline = anstyle::Color::from(underline);
|
||||
anstyle_style = anstyle_style.underline_color(Some(underline));
|
||||
}
|
||||
anstyle_style = anstyle_style.effects(style.add_modifier.into());
|
||||
anstyle_style
|
||||
}
|
||||
@@ -300,10 +307,13 @@ mod tests {
|
||||
let anstyle_style = anstyle::Style::new()
|
||||
.fg_color(Some(anstyle::Color::Ansi(AnsiColor::Red)))
|
||||
.bg_color(Some(anstyle::Color::Ansi(AnsiColor::Blue)))
|
||||
.underline_color(Some(anstyle::Color::Ansi(AnsiColor::Green)))
|
||||
.effects(Effects::BOLD | Effects::ITALIC);
|
||||
let style = Style::from(anstyle_style);
|
||||
assert_eq!(style.fg, Some(Color::Red));
|
||||
assert_eq!(style.bg, Some(Color::Blue));
|
||||
#[cfg(feature = "underline-color")]
|
||||
assert_eq!(style.underline_color, Some(Color::Green));
|
||||
assert!(style.add_modifier.contains(Modifier::BOLD));
|
||||
assert!(style.add_modifier.contains(Modifier::ITALIC));
|
||||
}
|
||||
@@ -313,6 +323,8 @@ mod tests {
|
||||
let style = Style {
|
||||
fg: Some(Color::Red),
|
||||
bg: Some(Color::Blue),
|
||||
#[cfg(feature = "underline-color")]
|
||||
underline_color: Some(Color::Green),
|
||||
add_modifier: Modifier::BOLD | Modifier::ITALIC,
|
||||
..Default::default()
|
||||
};
|
||||
@@ -325,6 +337,11 @@ mod tests {
|
||||
anstyle_style.get_bg_color(),
|
||||
Some(anstyle::Color::Ansi(AnsiColor::Blue))
|
||||
);
|
||||
#[cfg(feature = "underline-color")]
|
||||
assert_eq!(
|
||||
anstyle_style.get_underline_color(),
|
||||
Some(anstyle::Color::Ansi(AnsiColor::Green))
|
||||
);
|
||||
assert!(anstyle_style.get_effects().contains(Effects::BOLD));
|
||||
assert!(anstyle_style.get_effects().contains(Effects::ITALIC));
|
||||
}
|
||||
|
||||
@@ -300,15 +300,20 @@ impl MergeStrategy {
|
||||
/// [Box Drawing Unicode block]: https://en.wikipedia.org/wiki/Box_Drawing
|
||||
/// [`Cell::merge_symbol`]: crate::buffer::Cell::merge_symbol
|
||||
pub fn merge<'a>(self, prev: &'a str, next: &'a str) -> &'a str {
|
||||
let (Ok(prev_symbol), Ok(next_symbol)) =
|
||||
(BorderSymbol::from_str(prev), BorderSymbol::from_str(next))
|
||||
else {
|
||||
// Replace should always just return the last symbol.
|
||||
if self == Self::Replace {
|
||||
return next;
|
||||
};
|
||||
if let Ok(merged) = prev_symbol.merge(next_symbol, self).try_into() {
|
||||
return merged;
|
||||
}
|
||||
next
|
||||
|
||||
match (BorderSymbol::from_str(prev), BorderSymbol::from_str(next)) {
|
||||
(Ok(prev_symbol), Ok(next_symbol)) => prev_symbol
|
||||
.merge(next_symbol, self)
|
||||
.try_into()
|
||||
.unwrap_or(next),
|
||||
// Non-border symbols take precedence in strategies other than Replace.
|
||||
(Err(_), Ok(_)) => prev,
|
||||
(_, Err(_)) => next,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,7 +528,6 @@ macro_rules! define_symbols {
|
||||
}
|
||||
|
||||
define_symbols!(
|
||||
" " => (Nothing, Nothing, Nothing, Nothing),
|
||||
"─" => (Plain, Nothing, Plain, Nothing),
|
||||
"━" => (Thick, Nothing, Thick, Nothing),
|
||||
"│" => (Nothing, Plain, Nothing, Plain),
|
||||
@@ -666,7 +670,7 @@ mod tests {
|
||||
"╄", "╅", "╆", "╇", "╈", "╉", "╊", "╋", "╌", "╍", "╎", "╏", "═", "║", "╒", "╓", "╔",
|
||||
"╕", "╖", "╗", "╘", "╙", "╚", "╛", "╜", "╝", "╞", "╟", "╠", "╡", "╢", "╣", "╤", "╥",
|
||||
"╦", "╧", "╨", "╩", "╪", "╫", "╬", "╭", "╮", "╯", "╰", "╴", "╵", "╶", "╷", "╸", "╹",
|
||||
"╺", "╻", "╼", "╽", "╾", "╿", " ",
|
||||
"╺", "╻", "╼", "╽", "╾", "╿", " ", "a", "b",
|
||||
];
|
||||
|
||||
for a in symbols {
|
||||
@@ -695,8 +699,8 @@ mod tests {
|
||||
assert_eq!(strategy.merge("┵", "┝"), "┿");
|
||||
assert_eq!(strategy.merge("│", "━"), "┿");
|
||||
assert_eq!(strategy.merge("┵", "╞"), "╞");
|
||||
assert_eq!(strategy.merge(" ", "╠"), "╠");
|
||||
assert_eq!(strategy.merge("╠", " "), "╠");
|
||||
assert_eq!(strategy.merge(" ", "╠"), " ");
|
||||
assert_eq!(strategy.merge("╠", " "), " ");
|
||||
assert_eq!(strategy.merge("╎", "╧"), "╧");
|
||||
assert_eq!(strategy.merge("╛", "╒"), "╪");
|
||||
assert_eq!(strategy.merge("│", "═"), "╪");
|
||||
@@ -704,6 +708,9 @@ mod tests {
|
||||
assert_eq!(strategy.merge("╡", "╞"), "╪");
|
||||
assert_eq!(strategy.merge("┌", "╭"), "╭");
|
||||
assert_eq!(strategy.merge("┘", "╭"), "╭");
|
||||
assert_eq!(strategy.merge("┌", "a"), "a");
|
||||
assert_eq!(strategy.merge("a", "╭"), "a");
|
||||
assert_eq!(strategy.merge("a", "b"), "b");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -711,7 +718,7 @@ mod tests {
|
||||
let strategy = MergeStrategy::Fuzzy;
|
||||
assert_eq!(strategy.merge("┄", "╴"), "─");
|
||||
assert_eq!(strategy.merge("│", "┆"), "┆");
|
||||
assert_eq!(strategy.merge(" ", "┉"), "┉");
|
||||
assert_eq!(strategy.merge(" ", "┉"), " ");
|
||||
assert_eq!(strategy.merge("┋", "┋"), "┋");
|
||||
assert_eq!(strategy.merge("╷", "╶"), "┌");
|
||||
assert_eq!(strategy.merge("╭", "┌"), "┌");
|
||||
@@ -725,8 +732,8 @@ mod tests {
|
||||
assert_eq!(strategy.merge("┘", "┌"), "┼");
|
||||
assert_eq!(strategy.merge("┘", "╭"), "┼");
|
||||
assert_eq!(strategy.merge("╎", "┉"), "┿");
|
||||
assert_eq!(strategy.merge(" ", "╠"), "╠");
|
||||
assert_eq!(strategy.merge("╠", " "), "╠");
|
||||
assert_eq!(strategy.merge(" ", "╠"), " ");
|
||||
assert_eq!(strategy.merge("╠", " "), " ");
|
||||
assert_eq!(strategy.merge("┵", "╞"), "╪");
|
||||
assert_eq!(strategy.merge("╛", "╒"), "╪");
|
||||
assert_eq!(strategy.merge("│", "═"), "╪");
|
||||
@@ -734,5 +741,8 @@ mod tests {
|
||||
assert_eq!(strategy.merge("╡", "╞"), "╪");
|
||||
assert_eq!(strategy.merge("╎", "╧"), "╪");
|
||||
assert_eq!(strategy.merge("┌", "╭"), "╭");
|
||||
assert_eq!(strategy.merge("┌", "a"), "a");
|
||||
assert_eq!(strategy.merge("a", "╭"), "a");
|
||||
assert_eq!(strategy.merge("a", "b"), "b");
|
||||
}
|
||||
}
|
||||
|
||||
117
ratatui-widgets/examples/collapsed-borders.rs
Normal file
117
ratatui-widgets/examples/collapsed-borders.rs
Normal file
@@ -0,0 +1,117 @@
|
||||
//! # [Ratatui] [`Block`] with collapsed borders example
|
||||
//!
|
||||
//! The latest version of this example is available in the [widget examples] folder in the
|
||||
//! repository.
|
||||
//!
|
||||
//! Please note that the examples are designed to be run against the `main` branch of the Github
|
||||
//! repository. This means that you may not be able to compile with the latest release version on
|
||||
//! crates.io, or the one that you have installed locally.
|
||||
//!
|
||||
//! See the [examples readme] for more information on finding examples that match the version of the
|
||||
//! library you are using.
|
||||
//!
|
||||
//! [Ratatui]: https://github.com/ratatui/ratatui
|
||||
//! [widget examples]: https://github.com/ratatui/ratatui/blob/main/ratatui-widgets/examples
|
||||
//! [examples readme]: https://github.com/ratatui/ratatui/blob/main/examples/README.md
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use color_eyre::Result;
|
||||
use crossterm::event;
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Constraint, Layout, Rect, Spacing};
|
||||
use ratatui::style::{Color, Stylize};
|
||||
use ratatui::symbols::merge::MergeStrategy;
|
||||
use ratatui::text::Line;
|
||||
use ratatui::widgets::{Block, BorderType};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
ratatui::run(|terminal| {
|
||||
let mut selected_pane = Pane::Top;
|
||||
loop {
|
||||
terminal.draw(|frame| render(frame, selected_pane))?;
|
||||
if let Some(key_event) = event::read()?.as_key_press_event() {
|
||||
match key_event.code {
|
||||
event::KeyCode::Up => selected_pane = Pane::Top,
|
||||
event::KeyCode::Left => selected_pane = Pane::Left,
|
||||
event::KeyCode::Right => selected_pane = Pane::Right,
|
||||
event::KeyCode::Down => selected_pane = Pane::Bottom,
|
||||
event::KeyCode::Char('q') => return Ok(()),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Derive Eq, PartialEq, Hash for Pane to use as HashMap key
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
enum Pane {
|
||||
Top,
|
||||
Left,
|
||||
Right,
|
||||
Bottom,
|
||||
}
|
||||
|
||||
/// Render the UI with various blocks.
|
||||
fn render(frame: &mut Frame, selected_pane: Pane) {
|
||||
let [title, blocks] = frame.area().layout(&Layout::vertical([
|
||||
Constraint::Length(1),
|
||||
Constraint::Fill(1),
|
||||
]));
|
||||
|
||||
render_title(frame, title);
|
||||
render_blocks(selected_pane, frame, blocks);
|
||||
}
|
||||
|
||||
fn render_title(frame: &mut Frame<'_>, area: Rect) {
|
||||
let title = Line::from_iter([
|
||||
"Block With Collapsed Borders".bold(),
|
||||
" (Press 'q' to quit)".into(),
|
||||
]);
|
||||
frame.render_widget(title.centered(), area);
|
||||
}
|
||||
|
||||
fn render_blocks(selected_pane: Pane, frame: &mut Frame<'_>, area: Rect) {
|
||||
// The recipe to achieve collapsed borders is as follows:
|
||||
// 1. Use `MergeStrategy::Exact` (or `MergeStrategy::Fuzzy`) to merge borders of adjacent
|
||||
// blocks.
|
||||
// 2. Use a layout with `Spacing::Overlap(1)` to ensure that the borders overlap
|
||||
// 3. Use `BorderType::Thick` for the selected pane to make it visually distinct.
|
||||
// 4. Render the selected pane last so it appears on top of the others.
|
||||
let [top, middle, bottom] =
|
||||
area.layout(&Layout::vertical([Constraint::Fill(1); 3]).spacing(Spacing::Overlap(1)));
|
||||
let [left, right] =
|
||||
middle.layout(&Layout::horizontal([Constraint::Fill(1); 2]).spacing(Spacing::Overlap(1)));
|
||||
|
||||
// Store pane areas and titles in a single HashMap indexed by Pane. A real application might
|
||||
// store actual data or widgets in these areas instead (and use `WidgetRef` to handle
|
||||
// heterogeneous widgets).
|
||||
let mut panes = HashMap::new();
|
||||
panes.insert(Pane::Top, (top, "Top Block"));
|
||||
panes.insert(Pane::Left, (left, "Left Block"));
|
||||
panes.insert(Pane::Right, (right, "Right Block"));
|
||||
panes.insert(Pane::Bottom, (bottom, "Bottom Block"));
|
||||
|
||||
// Render all panes except the selected one first
|
||||
for (&pane, &(area, title)) in &panes {
|
||||
if pane != selected_pane {
|
||||
// MergeStrategy::Exact causes the borders to collapse
|
||||
let block = Block::bordered()
|
||||
.merge_borders(MergeStrategy::Exact)
|
||||
.title(title);
|
||||
frame.render_widget(block, area);
|
||||
}
|
||||
}
|
||||
// Render the selected pane last (so it appears on top) with a thick border
|
||||
if let Some(&(area, title)) = panes.get(&selected_pane) {
|
||||
// MergeStrategy::Exact causes the borders to collapse
|
||||
let block = Block::bordered()
|
||||
.merge_borders(MergeStrategy::Exact)
|
||||
.border_type(BorderType::Thick)
|
||||
.border_style(Color::Yellow)
|
||||
.title(title);
|
||||
frame.render_widget(block, area);
|
||||
}
|
||||
}
|
||||
17
ratatui-widgets/examples/vhs/collapsed-borders.tape
Normal file
17
ratatui-widgets/examples/vhs/collapsed-borders.tape
Normal file
@@ -0,0 +1,17 @@
|
||||
# This is a vhs script. See https://github.com/charmbracelet/vhs for more info.
|
||||
# To run this script, install vhs and run `vhs ./examples/vhs/gauge.tape`
|
||||
Output "target/collapsed-borders.gif"
|
||||
Set Theme "Aardvark Blue"
|
||||
Set Width 1200
|
||||
Set Height 800
|
||||
Hide
|
||||
Type "cargo run -p ratatui-widgets --example collapsed-borders"
|
||||
Enter
|
||||
Sleep 2s
|
||||
Show
|
||||
Sleep 1s
|
||||
Left Sleep 1s
|
||||
Right Sleep 1s
|
||||
Down Sleep 1s
|
||||
Hide
|
||||
Type "q"
|
||||
@@ -515,7 +515,7 @@ impl BarChart<'_> {
|
||||
let margin = u16::from(label_size != 0);
|
||||
Rect {
|
||||
x: area.x + label_size + margin,
|
||||
width: area.width - label_size - margin,
|
||||
width: area.width.saturating_sub(label_size).saturating_sub(margin),
|
||||
..area
|
||||
}
|
||||
};
|
||||
@@ -579,10 +579,10 @@ impl BarChart<'_> {
|
||||
}
|
||||
|
||||
fn render_vertical(&self, buf: &mut Buffer, area: Rect) {
|
||||
let label_info = self.label_info(area.height - 1);
|
||||
let label_info = self.label_info(area.height.saturating_sub(1));
|
||||
|
||||
let bars_area = Rect {
|
||||
height: area.height - label_info.height,
|
||||
height: area.height.saturating_sub(label_info.height),
|
||||
..area
|
||||
};
|
||||
|
||||
@@ -722,6 +722,7 @@ mod tests {
|
||||
use ratatui_core::layout::Alignment;
|
||||
use ratatui_core::style::{Color, Modifier, Stylize};
|
||||
use ratatui_core::text::Span;
|
||||
use rstest::rstest;
|
||||
|
||||
use super::*;
|
||||
use crate::borders::BorderType;
|
||||
@@ -1472,4 +1473,35 @@ mod tests {
|
||||
]);
|
||||
assert_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::horizontal(Direction::Horizontal)]
|
||||
#[case::vertical(Direction::Vertical)]
|
||||
fn render_in_minimal_buffer(#[case] direction: Direction) {
|
||||
let chart = BarChart::default()
|
||||
.data(&[("A", 1), ("B", 2)])
|
||||
.bar_width(3)
|
||||
.bar_gap(1)
|
||||
.direction(direction);
|
||||
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
// This should not panic, even if the buffer is too small to render the chart.
|
||||
chart.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines([" "]));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::horizontal(Direction::Horizontal)]
|
||||
#[case::vertical(Direction::Vertical)]
|
||||
fn render_in_zero_size_buffer(#[case] direction: Direction) {
|
||||
let chart = BarChart::default()
|
||||
.data(&[("A", 1), ("B", 2)])
|
||||
.bar_width(3)
|
||||
.bar_gap(1)
|
||||
.direction(direction);
|
||||
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
chart.render(buffer.area, &mut buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -933,41 +933,74 @@ impl Block<'_> {
|
||||
}
|
||||
|
||||
/// Render titles in the center of the block
|
||||
///
|
||||
/// Currently this method aligns the titles to the left inside a centered area. This is not
|
||||
/// ideal and should be fixed in the future to align the titles to the center of the block and
|
||||
/// truncate both sides of the titles if the block is too small to fit all titles.
|
||||
#[expect(clippy::similar_names)]
|
||||
fn render_center_titles(&self, position: TitlePosition, area: Rect, buf: &mut Buffer) {
|
||||
let area = self.titles_area(area, position);
|
||||
let titles = self
|
||||
.filtered_titles(position, Alignment::Center)
|
||||
.collect_vec();
|
||||
// titles are rendered with a space after each title except the last one
|
||||
let total_width = titles
|
||||
.iter()
|
||||
.map(|title| title.width() as u16 + 1) // space between titles
|
||||
.map(|title| title.width() as u16 + 1)
|
||||
.sum::<u16>()
|
||||
.saturating_sub(1); // no space for the last title
|
||||
.saturating_sub(1);
|
||||
|
||||
let titles_area = self.titles_area(area, position);
|
||||
let mut titles_area = Rect {
|
||||
x: titles_area.left() + (titles_area.width.saturating_sub(total_width) / 2),
|
||||
..titles_area
|
||||
};
|
||||
if total_width <= area.width {
|
||||
self.render_centered_titles_without_truncation(titles, total_width, area, buf);
|
||||
} else {
|
||||
self.render_centered_titles_with_truncation(titles, total_width, area, buf);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_centered_titles_without_truncation(
|
||||
&self,
|
||||
titles: Vec<&Line<'_>>,
|
||||
total_width: u16,
|
||||
area: Rect,
|
||||
buf: &mut Buffer,
|
||||
) {
|
||||
// titles fit in the area, center them
|
||||
let x = area.left() + area.width.saturating_sub(total_width) / 2;
|
||||
let mut area = Rect { x, ..area };
|
||||
for title in titles {
|
||||
if titles_area.is_empty() {
|
||||
break;
|
||||
}
|
||||
let title_width = title.width() as u16;
|
||||
let title_area = Rect {
|
||||
width: title_width.min(titles_area.width),
|
||||
..titles_area
|
||||
};
|
||||
let width = title.width() as u16;
|
||||
let title_area = Rect { width, ..area };
|
||||
buf.set_style(title_area, self.titles_style);
|
||||
title.render(title_area, buf);
|
||||
// Move the rendering cursor to the right, leaving 1 column space.
|
||||
area.x = area.x.saturating_add(width + 1);
|
||||
area.width = area.width.saturating_sub(width + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// bump the titles area to the right and reduce its width
|
||||
titles_area.x = titles_area.x.saturating_add(title_width + 1);
|
||||
titles_area.width = titles_area.width.saturating_sub(title_width + 1);
|
||||
fn render_centered_titles_with_truncation(
|
||||
&self,
|
||||
titles: Vec<&Line<'_>>,
|
||||
total_width: u16,
|
||||
mut area: Rect,
|
||||
buf: &mut Buffer,
|
||||
) {
|
||||
// titles do not fit in the area, truncate the left side using an offset. The right side
|
||||
// is truncated by the area width.
|
||||
let mut offset = total_width.saturating_sub(area.width) / 2;
|
||||
for title in titles {
|
||||
if area.is_empty() {
|
||||
break;
|
||||
}
|
||||
let width = area.width.min(title.width() as u16).saturating_sub(offset);
|
||||
let title_area = Rect { width, ..area };
|
||||
buf.set_style(title_area, self.titles_style);
|
||||
if offset > 0 {
|
||||
// truncate the left side of the title to fit the area
|
||||
title.clone().right_aligned().render(title_area, buf);
|
||||
offset = offset.saturating_sub(width).saturating_sub(1);
|
||||
} else {
|
||||
// truncate the right side of the title to fit the area if needed
|
||||
title.clone().left_aligned().render(title_area, buf);
|
||||
}
|
||||
// Leave 1 column of spacing between titles.
|
||||
area.x = area.x.saturating_add(width + 1);
|
||||
area.width = area.width.saturating_sub(width + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1936,6 +1969,92 @@ mod tests {
|
||||
pretty_assertions::assert_eq!(Buffer::with_lines(expected.lines()), buffer);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::replace(MergeStrategy::Replace, Buffer::with_lines([
|
||||
"┏block top━━┓",
|
||||
"┃ ┃",
|
||||
"┗━━━━━━━━━━━┛",
|
||||
"│ │",
|
||||
"└───────────┘",
|
||||
])
|
||||
)]
|
||||
#[case::replace(MergeStrategy::Exact, Buffer::with_lines([
|
||||
"┏block top━━┓",
|
||||
"┃ ┃",
|
||||
"┡block btm━━┩",
|
||||
"│ │",
|
||||
"└───────────┘",
|
||||
])
|
||||
)]
|
||||
#[case::replace(MergeStrategy::Fuzzy, Buffer::with_lines([
|
||||
"┏block top━━┓",
|
||||
"┃ ┃",
|
||||
"┡block btm━━┩",
|
||||
"│ │",
|
||||
"└───────────┘",
|
||||
])
|
||||
)]
|
||||
fn merged_titles_bottom_first(#[case] strategy: MergeStrategy, #[case] expected: Buffer) {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 13, 5));
|
||||
Block::bordered()
|
||||
.title("block btm")
|
||||
.render(Rect::new(0, 2, 13, 3), &mut buffer);
|
||||
Block::bordered()
|
||||
.title("block top")
|
||||
.border_type(BorderType::Thick)
|
||||
.merge_borders(strategy)
|
||||
.render(Rect::new(0, 0, 13, 3), &mut buffer);
|
||||
assert_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::replace(MergeStrategy::Replace, Buffer::with_lines([
|
||||
"┏block top━━┓",
|
||||
"┃ ┃",
|
||||
"┌block btm──┐",
|
||||
"│ │",
|
||||
"└───────────┘",
|
||||
])
|
||||
)]
|
||||
#[case::replace(MergeStrategy::Exact, Buffer::with_lines([
|
||||
"┏block top━━┓",
|
||||
"┃ ┃",
|
||||
"┞block btm──┦",
|
||||
"│ │",
|
||||
"└───────────┘",
|
||||
])
|
||||
)]
|
||||
#[case::replace(MergeStrategy::Fuzzy, Buffer::with_lines([
|
||||
"┏block top━━┓",
|
||||
"┃ ┃",
|
||||
"┞block btm──┦",
|
||||
"│ │",
|
||||
"└───────────┘",
|
||||
])
|
||||
)]
|
||||
fn merged_titles_top_first(#[case] strategy: MergeStrategy, #[case] expected: Buffer) {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 13, 5));
|
||||
Block::bordered()
|
||||
.title("block top")
|
||||
.border_type(BorderType::Thick)
|
||||
.render(Rect::new(0, 0, 13, 3), &mut buffer);
|
||||
Block::bordered()
|
||||
.title("block btm")
|
||||
.merge_borders(strategy)
|
||||
.render(Rect::new(0, 2, 13, 3), &mut buffer);
|
||||
assert_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn left_titles() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 1));
|
||||
Block::new()
|
||||
.title("L12")
|
||||
.title("L34")
|
||||
.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines(["L12 L34 "]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn left_titles_truncated() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 1));
|
||||
@@ -1946,12 +2065,16 @@ mod tests {
|
||||
assert_eq!(buffer, Buffer::with_lines(["L12345 L67"]));
|
||||
}
|
||||
|
||||
/// Note: this test is probably not what you'd expect, but it is how it works in the current
|
||||
/// implementation. Update this if the behavior changes.
|
||||
///
|
||||
/// This probably should render the titles centered as a whole and then truncate both titles
|
||||
/// to fit, but instead it renders each title and truncates them individually. This causes the
|
||||
/// left title to be displayed in full, while the right title is truncated.
|
||||
#[test]
|
||||
fn center_titles() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 1));
|
||||
Block::new()
|
||||
.title(Line::from("C12").centered())
|
||||
.title(Line::from("C34").centered())
|
||||
.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines([" C12 C34 "]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn center_titles_truncated() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 1));
|
||||
@@ -1959,7 +2082,17 @@ mod tests {
|
||||
.title(Line::from("C12345").centered())
|
||||
.title(Line::from("C67890").centered())
|
||||
.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines(["C12345 678"]));
|
||||
assert_eq!(buffer, Buffer::with_lines(["12345 C678"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn right_titles() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 1));
|
||||
Block::new()
|
||||
.title(Line::from("R12").right_aligned())
|
||||
.title(Line::from("R34").right_aligned())
|
||||
.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines([" R12 R34"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2001,4 +2134,25 @@ mod tests {
|
||||
.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines([" C1R67890"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_minimal_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
// This should not panic, even if the buffer is too small to render the block.
|
||||
Block::bordered()
|
||||
.title("I'm too big for this buffer")
|
||||
.padding(Padding::uniform(10))
|
||||
.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines(["┌"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_zero_size_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
Block::bordered()
|
||||
.title("I'm too big for this buffer")
|
||||
.padding(Padding::uniform(10))
|
||||
.render(buffer.area, &mut buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ bitflags! {
|
||||
#[derive(Default, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Borders: u8 {
|
||||
/// Show no border (default)
|
||||
const NONE = 0b0000;
|
||||
/// Show the top border
|
||||
const TOP = 0b0001;
|
||||
/// Show the right border
|
||||
@@ -25,6 +23,11 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
impl Borders {
|
||||
/// Show no border (default)
|
||||
pub const NONE: Self = Self::empty();
|
||||
}
|
||||
|
||||
/// The type of border of a [`Block`](crate::block::Block).
|
||||
///
|
||||
/// See the [`borders`](crate::block::Block::borders) method of `Block` to configure its borders.
|
||||
@@ -172,13 +175,11 @@ impl BorderType {
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement the `Debug` trait for the `Borders` bitflags. This is a manual implementation to
|
||||
/// display the flags in a more readable way. The default implementation would display the
|
||||
/// flags as 'Border(0x0)' for `Borders::NONE` for example.
|
||||
impl fmt::Debug for Borders {
|
||||
/// Display the Borders bitflags as a list of names. For example, `Borders::NONE` will be
|
||||
/// displayed as `NONE` and `Borders::ALL` will be displayed as `ALL`. If multiple flags are
|
||||
/// set, they will be displayed separated by a pipe character.
|
||||
/// Display the Borders bitflags as a list of names.
|
||||
///
|
||||
/// `Borders::NONE` is displayed as `NONE` and `Borders::ALL` is displayed as `ALL`. If multiple
|
||||
/// flags are set, they are otherwise displayed separated by a pipe character.
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.is_empty() {
|
||||
return write!(f, "NONE");
|
||||
@@ -186,17 +187,12 @@ impl fmt::Debug for Borders {
|
||||
if self.is_all() {
|
||||
return write!(f, "ALL");
|
||||
}
|
||||
let mut first = true;
|
||||
for (name, border) in self.iter_names() {
|
||||
if border == Self::NONE {
|
||||
continue;
|
||||
}
|
||||
if first {
|
||||
write!(f, "{name}")?;
|
||||
first = false;
|
||||
} else {
|
||||
write!(f, " | {name}")?;
|
||||
}
|
||||
let mut names = self.iter_names().map(|(name, _)| name);
|
||||
if let Some(first) = names.next() {
|
||||
write!(f, "{first}")?;
|
||||
}
|
||||
for name in names {
|
||||
write!(f, " | {name}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -302,4 +302,27 @@ mod tests {
|
||||
fn test_today() {
|
||||
CalendarEventStore::today(Style::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_minimal_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
let calendar = Monthly::new(
|
||||
Date::from_calendar_date(1984, Month::January, 1).unwrap(),
|
||||
CalendarEventStore::default(),
|
||||
);
|
||||
// This should not panic, even if the buffer is too small to render the calendar.
|
||||
calendar.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines([" "]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_zero_size_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
let calendar = Monthly::new(
|
||||
Date::from_calendar_date(1984, Month::January, 1).unwrap(),
|
||||
CalendarEventStore::default(),
|
||||
);
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
calendar.render(buffer.area, &mut buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -976,4 +976,27 @@ mod tests {
|
||||
b_grid.paint(usize::MAX, usize::MAX, Color::Red);
|
||||
c_grid.paint(usize::MAX, usize::MAX, Color::Red);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_minimal_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
let canvas = Canvas::default()
|
||||
.x_bounds([0.0, 10.0])
|
||||
.y_bounds([0.0, 10.0])
|
||||
.paint(|_ctx| {});
|
||||
// This should not panic, even if the buffer is too small to render the canvas.
|
||||
canvas.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines([" "]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_zero_size_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
let canvas = Canvas::default()
|
||||
.x_bounds([0.0, 10.0])
|
||||
.y_bounds([0.0, 10.0])
|
||||
.paint(|_ctx| {});
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
canvas.render(buffer.area, &mut buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1547,4 +1547,25 @@ mod tests {
|
||||
]);
|
||||
assert_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_minimal_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
let chart = Chart::new(vec![Dataset::default().data(&[(0.0, 0.0), (1.0, 1.0)])])
|
||||
.x_axis(Axis::default().bounds([0.0, 1.0]))
|
||||
.y_axis(Axis::default().bounds([0.0, 1.0]));
|
||||
// This should not panic, even if the buffer is too small to render the chart.
|
||||
chart.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines(["•"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_zero_size_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
let chart = Chart::new(vec![Dataset::default().data(&[(0.0, 0.0), (1.0, 1.0)])])
|
||||
.x_axis(Axis::default().bounds([0.0, 1.0]))
|
||||
.y_axis(Axis::default().bounds([0.0, 1.0]));
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
chart.render(buffer.area, &mut buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,4 +586,38 @@ mod tests {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_minimal_buffer_gauge() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
let gauge = Gauge::default().percent(50);
|
||||
// This should not panic, even if the buffer is too small to render the gauge.
|
||||
gauge.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines(["5"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_minimal_buffer_line_gauge() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
let line_gauge = LineGauge::default().ratio(0.5);
|
||||
// This should not panic, even if the buffer is too small to render the line gauge.
|
||||
line_gauge.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines(["5"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_zero_size_buffer_gauge() {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
let gauge = Gauge::default().percent(50);
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
gauge.render(buffer.area, &mut buffer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_zero_size_buffer_line_gauge() {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
let line_gauge = LineGauge::default().ratio(0.5);
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
line_gauge.render(buffer.area, &mut buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,4 +625,33 @@ mod tests {
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_minimal_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
let mut state = ListState::default().with_selected(None);
|
||||
let items = vec![
|
||||
ListItem::new("Item 1"),
|
||||
ListItem::new("Item 2"),
|
||||
ListItem::new("Item 3"),
|
||||
];
|
||||
let list = List::new(items);
|
||||
// This should not panic, even if the buffer is too small to render the list.
|
||||
list.render(buffer.area, &mut buffer, &mut state);
|
||||
assert_eq!(buffer, Buffer::with_lines(["I"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_zero_size_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
let mut state = ListState::default().with_selected(None);
|
||||
let items = vec![
|
||||
ListItem::new("Item 1"),
|
||||
ListItem::new("Item 2"),
|
||||
ListItem::new("Item 3"),
|
||||
];
|
||||
let list = List::new(items);
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
list.render(buffer.area, &mut buffer, &mut state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,4 +236,25 @@ mod tests {
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::tiny(Size::Tiny, Buffer::with_lines(["▛"]))]
|
||||
#[case::small(Size::Small, Buffer::with_lines(["█"]))]
|
||||
fn render_in_minimal_buffer(#[case] size: Size, #[case] expected: Buffer) {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
let logo = RatatuiLogo::new(size);
|
||||
// This should not panic, even if the buffer is too small to render the logo.
|
||||
logo.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::tiny(Size::Tiny)]
|
||||
#[case::small(Size::Small)]
|
||||
fn render_in_zero_size_buffer(#[case] size: Size) {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
let logo = RatatuiLogo::new(size);
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
logo.render(buffer.area, &mut buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,10 +135,21 @@ impl Widget for RatatuiMascot {
|
||||
/// The logo colors are hardcorded in the widget.
|
||||
/// The eye color depends on whether it's open / blinking
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let area = area.intersection(buf.area);
|
||||
if area.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
for (y, (line1, line2)) in RATATUI_MASCOT.lines().tuples().enumerate() {
|
||||
for (x, (ch1, ch2)) in line1.chars().zip(line2.chars()).enumerate() {
|
||||
let x = area.left() + x as u16;
|
||||
let y = area.top() + y as u16;
|
||||
|
||||
// Check if coordinates are within the buffer area
|
||||
if x >= area.right() || y >= area.bottom() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let cell = &mut buf[(x, y)];
|
||||
// given two cells which make up the top and bottom of the character,
|
||||
// Foreground color should be the non-space, non-terminal
|
||||
@@ -229,4 +240,21 @@ mod tests {
|
||||
.collect::<String>()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_minimal_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
let mascot = RatatuiMascot::new();
|
||||
// This should not panic, even if the buffer is too small to render the mascot.
|
||||
mascot.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines([" "]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_zero_size_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
let mascot = RatatuiMascot::new();
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
mascot.render(buffer.area, &mut buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ impl<'a> Paragraph<'a> {
|
||||
/// convention across the crate.
|
||||
///
|
||||
/// For more information about future scrolling design and concerns, see [RFC: Design of
|
||||
/// Scrollable Widgets](https://github.com/ratatui/ratatui/issues/174) on GitHub.
|
||||
/// Scrollable Widgets](https://github.com/ratatui/ratatui/discussions/1924) on GitHub.
|
||||
#[must_use = "method moves the value of self and returns the modified value"]
|
||||
pub const fn scroll(mut self, offset: (Vertical, Horizontal)) -> Self {
|
||||
self.scroll = Position {
|
||||
@@ -406,6 +406,7 @@ impl Widget for Paragraph<'_> {
|
||||
|
||||
impl Widget for &Paragraph<'_> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let area = area.intersection(buf.area);
|
||||
buf.set_style(area, self.style);
|
||||
self.block.as_ref().render(area, buf);
|
||||
let inner = self.block.inner_if_some(area);
|
||||
@@ -500,6 +501,7 @@ mod tests {
|
||||
use ratatui_core::style::{Color, Modifier, Style, Stylize};
|
||||
use ratatui_core::text::{Line, Span, Text};
|
||||
use ratatui_core::widgets::Widget;
|
||||
use rstest::rstest;
|
||||
|
||||
use super::*;
|
||||
use crate::block::TitlePosition;
|
||||
@@ -1193,4 +1195,45 @@ mod tests {
|
||||
expected.set_style(Rect::new(1, 1, 11, 1), Style::default().fg(Color::Green));
|
||||
assert_eq!(buf, expected);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::bottom(Rect::new(0, 5, 15, 1))]
|
||||
#[case::right(Rect::new(20, 0, 15, 1))]
|
||||
#[case::bottom_right(Rect::new(20, 5, 15, 1))]
|
||||
fn test_render_paragraph_out_of_bounds(#[case] area: Rect) {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 3));
|
||||
Paragraph::new("Beyond the pale").render(area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines(vec![" "; 3]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_out_of_bounds() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 15, 3));
|
||||
Paragraph::new("Hello World").render(Rect::new(10, 0, 10, 3), &mut buffer);
|
||||
assert_eq!(
|
||||
buffer,
|
||||
Buffer::with_lines(vec![
|
||||
" Hello",
|
||||
" ",
|
||||
" ",
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_minimal_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
let paragraph = Paragraph::new("Lorem ipsum");
|
||||
// This should not panic, even if the buffer is too small to render the paragraph.
|
||||
paragraph.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines(["L"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_zero_size_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
let paragraph = Paragraph::new("Lorem ipsum");
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
paragraph.render(buffer.area, &mut buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -970,6 +970,8 @@ mod tests {
|
||||
#[case::position_8("<---#####>", 8, 10)]
|
||||
#[case::position_9("<----####>", 9, 10)]
|
||||
#[case::position_one_out_of_bounds("<----####>", 10, 10)]
|
||||
#[case::position_few_out_of_bounds("<----####>", 15, 10)]
|
||||
#[case::position_very_many_out_of_bounds("<----####>", 500, 10)]
|
||||
fn render_scrollbar_vertical_left(
|
||||
#[case] expected: &str,
|
||||
#[case] position: usize,
|
||||
@@ -1000,7 +1002,9 @@ mod tests {
|
||||
#[case::position_8("<---#####>", 8, 10)]
|
||||
#[case::position_9("<----####>", 9, 10)]
|
||||
#[case::position_one_out_of_bounds("<----####>", 10, 10)]
|
||||
fn render_scrollbar_vertical_rightl(
|
||||
#[case::position_few_out_of_bounds("<----####>", 15, 10)]
|
||||
#[case::position_very_many_out_of_bounds("<----####>", 500, 10)]
|
||||
fn render_scrollbar_vertical_right(
|
||||
#[case] expected: &str,
|
||||
#[case] position: usize,
|
||||
#[case] content_length: usize,
|
||||
@@ -1089,4 +1093,31 @@ mod tests {
|
||||
let mut state = ScrollbarState::new(10);
|
||||
scrollbar.render(zero_width_area, &mut buffer, &mut state);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::vertical_left(ScrollbarOrientation::VerticalLeft)]
|
||||
#[case::vertical_right(ScrollbarOrientation::VerticalRight)]
|
||||
#[case::horizontal_top(ScrollbarOrientation::HorizontalTop)]
|
||||
#[case::horizontal_bottom(ScrollbarOrientation::HorizontalBottom)]
|
||||
fn render_in_minimal_buffer(#[case] orientation: ScrollbarOrientation) {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
let scrollbar = Scrollbar::new(orientation);
|
||||
let mut state = ScrollbarState::new(10).position(5);
|
||||
// This should not panic, even if the buffer is too small to render the scrollbar.
|
||||
scrollbar.render(buffer.area, &mut buffer, &mut state);
|
||||
assert_eq!(buffer, Buffer::with_lines([" "]));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::vertical_left(ScrollbarOrientation::VerticalLeft)]
|
||||
#[case::vertical_right(ScrollbarOrientation::VerticalRight)]
|
||||
#[case::horizontal_top(ScrollbarOrientation::HorizontalTop)]
|
||||
#[case::horizontal_bottom(ScrollbarOrientation::HorizontalBottom)]
|
||||
fn render_in_zero_size_buffer(#[case] orientation: ScrollbarOrientation) {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
let scrollbar = Scrollbar::new(orientation);
|
||||
let mut state = ScrollbarState::new(10).position(5);
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
scrollbar.render(buffer.area, &mut buffer, &mut state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -699,4 +699,25 @@ mod tests {
|
||||
.remove_modifier(Modifier::DIM)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_minimal_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
let sparkline = Sparkline::default()
|
||||
.data([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
||||
.max(10);
|
||||
// This should not panic, even if the buffer is too small to render the sparkline.
|
||||
sparkline.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines([" "]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_zero_size_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
let sparkline = Sparkline::default()
|
||||
.data([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
||||
.max(10);
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
sparkline.render(buffer.area, &mut buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2273,4 +2273,33 @@ mod tests {
|
||||
let column_count = table.column_count();
|
||||
assert_eq!(column_count, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_minimal_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
let rows = vec![
|
||||
Row::new(vec!["Cell1", "Cell2", "Cell3"]),
|
||||
Row::new(vec!["Cell4", "Cell5", "Cell6"]),
|
||||
];
|
||||
let table = Table::new(rows, [Constraint::Length(10); 3])
|
||||
.header(Row::new(vec!["Header1", "Header2", "Header3"]))
|
||||
.footer(Row::new(vec!["Footer1", "Footer2", "Footer3"]));
|
||||
// This should not panic, even if the buffer is too small to render the table.
|
||||
Widget::render(table, buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines([" "]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_zero_size_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
let rows = vec![
|
||||
Row::new(vec!["Cell1", "Cell2", "Cell3"]),
|
||||
Row::new(vec!["Cell4", "Cell5", "Cell6"]),
|
||||
];
|
||||
let table = Table::new(rows, [Constraint::Length(10); 3])
|
||||
.header(Row::new(vec!["Header1", "Header2", "Header3"]))
|
||||
.footer(Row::new(vec!["Footer1", "Footer2", "Footer3"]));
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
Widget::render(table, buffer.area, &mut buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -676,4 +676,25 @@ mod tests {
|
||||
Style::default().black().on_white().bold().not_italic()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_minimal_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
let tabs = Tabs::new(vec!["Tab1", "Tab2", "Tab3", "Tab4"])
|
||||
.select(1)
|
||||
.divider("|");
|
||||
// This should not panic, even if the buffer is too small to render the tabs.
|
||||
tabs.render(buffer.area, &mut buffer);
|
||||
assert_eq!(buffer, Buffer::with_lines([" "]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_in_zero_size_buffer() {
|
||||
let mut buffer = Buffer::empty(Rect::ZERO);
|
||||
let tabs = Tabs::new(vec!["Tab1", "Tab2", "Tab3", "Tab4"])
|
||||
.select(1)
|
||||
.divider("|");
|
||||
// This should not panic, even if the buffer has zero size.
|
||||
tabs.render(buffer.area, &mut buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,9 @@ publish = false
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
cargo_metadata = "0.20"
|
||||
clap = { version = "4.5.40", features = ["derive"] }
|
||||
clap-cargo = { version = "0.15.1", features = ["cargo_metadata"] }
|
||||
clap = { version = "4.5.41", features = ["derive"] }
|
||||
clap-verbosity-flag = { version = "3.0.3", default-features = false, features = ["tracing"] }
|
||||
color-eyre = "0.6.5"
|
||||
duct = "1.0.0"
|
||||
itertools.workspace = true
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = { version = "0.3.18" }
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use color_eyre::Result;
|
||||
use itertools::{Itertools, Position};
|
||||
|
||||
use crate::{Run, run_cargo_nightly, workspace_libs};
|
||||
use crate::{Run, run_cargo_nightly};
|
||||
|
||||
/// Check documentation for errors and warnings
|
||||
#[derive(Clone, Debug, clap::Args)]
|
||||
@@ -13,14 +12,11 @@ pub struct Docs {
|
||||
|
||||
impl Run for Docs {
|
||||
fn run(self) -> Result<()> {
|
||||
let packages = workspace_libs()?;
|
||||
for (position, package) in packages.iter().with_position() {
|
||||
let mut args = vec!["docs-rs", "--package", &package];
|
||||
if self.open && matches!(position, Position::Last | Position::Only) {
|
||||
args.push("--open");
|
||||
}
|
||||
run_cargo_nightly(args)?;
|
||||
// cargo +nightly hack --all --ignore-private docs-rs
|
||||
let mut args = vec!["hack", "--all", "--ignore-private", "docs-rs"];
|
||||
if self.open {
|
||||
args.push("--open");
|
||||
}
|
||||
Ok(())
|
||||
run_cargo_nightly(args)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use color_eyre::Result;
|
||||
|
||||
use crate::{Run, run_cargo, workspace_libs};
|
||||
use crate::{Run, run_cargo};
|
||||
|
||||
/// Check if README.md is up-to-date (using cargo-rdme)
|
||||
#[derive(Clone, Debug, clap::Args)]
|
||||
@@ -10,22 +10,30 @@ pub struct Readme {
|
||||
check: bool,
|
||||
}
|
||||
|
||||
/// The projects that should have their README.md generated from the source code.
|
||||
///
|
||||
/// Notably, we removed `ratatui` from this list as we have a more specifically crafted README for
|
||||
/// the main crate.
|
||||
const PROJECTS: &[&str] = &[
|
||||
"ratatui-core",
|
||||
"ratatui-crossterm",
|
||||
"ratatui-macros",
|
||||
"ratatui-termion",
|
||||
"ratatui-termwiz",
|
||||
"ratatui-widgets",
|
||||
];
|
||||
|
||||
impl Run for Readme {
|
||||
fn run(self) -> Result<()> {
|
||||
let args = if self.check {
|
||||
vec!["rdme", "--check"]
|
||||
} else {
|
||||
vec!["rdme"]
|
||||
};
|
||||
for package in workspace_libs()? {
|
||||
if package == "ratatui" {
|
||||
// Skip the main crate as we removed rdme
|
||||
continue;
|
||||
// This would be simpler perhaps with cargo-hack, however cargo-rdme does not support the
|
||||
// `--manifest-path` option that is required for this to work, so it's easiest to hard code
|
||||
// the package names here. See https://github.com/orium/cargo-rdme/issues/261
|
||||
for package in PROJECTS {
|
||||
let mut args = vec!["rdme", "--workspace-project", package];
|
||||
if self.check {
|
||||
args.push("--check");
|
||||
}
|
||||
let mut package_args = args.clone();
|
||||
package_args.push("--workspace-project");
|
||||
package_args.push(&package);
|
||||
run_cargo(package_args)?;
|
||||
run_cargo(args)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
use std::io;
|
||||
use std::process::Output;
|
||||
|
||||
use cargo_metadata::{MetadataCommand, TargetKind};
|
||||
use clap::Parser;
|
||||
use clap::builder::styling::{AnsiColor, Styles};
|
||||
use clap_verbosity_flag::{InfoLevel, Verbosity};
|
||||
use color_eyre::Result;
|
||||
use color_eyre::eyre::Context;
|
||||
use commands::Command;
|
||||
use duct::cmd;
|
||||
|
||||
@@ -39,8 +38,18 @@ fn main() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Matches the clap styling
|
||||
pub const HELP_STYLES: Styles = Styles::styled()
|
||||
.header(AnsiColor::Green.on_default().bold())
|
||||
.usage(AnsiColor::Green.on_default().bold())
|
||||
.literal(AnsiColor::Cyan.on_default().bold())
|
||||
.placeholder(AnsiColor::Cyan.on_default())
|
||||
.error(AnsiColor::Red.on_default().bold())
|
||||
.valid(AnsiColor::Cyan.on_default().bold())
|
||||
.invalid(AnsiColor::Yellow.on_default().bold());
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(bin_name = "cargo xtask", styles = clap_cargo::style::CLAP_STYLING)]
|
||||
#[command(bin_name = "cargo xtask", styles = HELP_STYLES)]
|
||||
struct Args {
|
||||
#[command(subcommand)]
|
||||
command: Command,
|
||||
@@ -49,20 +58,6 @@ struct Args {
|
||||
verbosity: Verbosity<InfoLevel>,
|
||||
}
|
||||
|
||||
/// Return the available libs in the workspace
|
||||
fn workspace_libs() -> Result<Vec<String>> {
|
||||
let meta = MetadataCommand::new()
|
||||
.exec()
|
||||
.wrap_err("failed to get cargo metadata")?;
|
||||
let packages = meta
|
||||
.workspace_packages()
|
||||
.iter()
|
||||
.filter(|v| v.targets.iter().any(|t| t.kind.contains(&TargetKind::Lib)))
|
||||
.map(|v| v.name.to_string())
|
||||
.collect();
|
||||
Ok(packages)
|
||||
}
|
||||
|
||||
/// Run a cargo subcommand with the default toolchain
|
||||
fn run_cargo(args: Vec<&str>) -> Result<()> {
|
||||
cmd("cargo", args).run_with_trace()?;
|
||||
|
||||
Reference in New Issue
Block a user