Compare commits
59 Commits
653/master
...
v0.20.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
343ec220b4 | ||
|
|
2da4c10384 | ||
|
|
829dfee9e5 | ||
|
|
26c7bcfdd5 | ||
|
|
cf1b05d16e | ||
|
|
cfa8b8042a | ||
|
|
f0c0985708 | ||
|
|
73c937bc30 | ||
|
|
33e67abbe9 | ||
|
|
c20fb723ef | ||
|
|
ccd142df97 | ||
|
|
f6dbd1c0b5 | ||
|
|
d38d185d1c | ||
|
|
ef79b72471 | ||
|
|
ed12ab16e0 | ||
|
|
24820cfcff | ||
|
|
e10f62663e | ||
|
|
02573b0ad2 | ||
|
|
0dc39434c2 | ||
|
|
33acfce083 | ||
|
|
79d0eadbd6 | ||
|
|
73f7f16298 | ||
|
|
66eb0e42fe | ||
|
|
052ae53b6e | ||
|
|
1c0ed3268b | ||
|
|
0456abb327 | ||
|
|
ec50458491 | ||
|
|
b834ccaa2f | ||
|
|
ffb3de6c36 | ||
|
|
454c8459f2 | ||
|
|
94a0d09591 | ||
|
|
9b7a6ed85d | ||
|
|
7e31035114 | ||
|
|
e15a6146f8 | ||
|
|
e49cb1126b | ||
|
|
142bc5720e | ||
|
|
feaeb7870f | ||
|
|
9df0eefe49 | ||
|
|
8e89a9377a | ||
|
|
d3df8fe7ef | ||
|
|
9feda988a5 | ||
|
|
9534d533e3 | ||
|
|
85eefe1d8b | ||
|
|
3343270680 | ||
|
|
bf9d502742 | ||
|
|
85c0779ac0 | ||
|
|
070de44069 | ||
|
|
33087e3a99 | ||
|
|
fe4eb5e771 | ||
|
|
2fead23556 | ||
|
|
bc5a9e4c06 | ||
|
|
fafad6c961 | ||
|
|
a4de409235 | ||
|
|
a05fd45959 | ||
|
|
24de2f8a96 | ||
|
|
eee37011a5 | ||
|
|
a67706bea0 | ||
|
|
faa69b6cfe | ||
|
|
ba5ea2deff |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -7,7 +7,7 @@ assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
Hi there, sorry `tui` is not working as expected.
|
||||
Hi there, sorry `ratatui` is not working as expected.
|
||||
Please fill this bug report conscientiously.
|
||||
A detailed and complete issue is more likely to be processed quickly.
|
||||
-->
|
||||
|
||||
17
.github/pull_request_template.md
vendored
17
.github/pull_request_template.md
vendored
@@ -1,17 +0,0 @@
|
||||
## Description
|
||||
<!--
|
||||
A clear and concise description of what this PR changes.
|
||||
-->
|
||||
|
||||
## Testing guidelines
|
||||
<!--
|
||||
A clear and concise description of how the changes can be tested.
|
||||
For example, you can include a command to run the relevant tests or examples.
|
||||
You can also include screenshots of the expected behavior.
|
||||
-->
|
||||
|
||||
## Checklist
|
||||
|
||||
* [ ] I have read the [contributing guidelines](../CONTRIBUTING.md).
|
||||
* [ ] I have added relevant tests.
|
||||
* [ ] I have documented all new additions.
|
||||
19
.github/workflows/cd.yml
vendored
Normal file
19
.github/workflows/cd.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: Continuous Deployment
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Publish on crates.io
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Publish
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: publish
|
||||
args: --token ${{ secrets.CARGO_TOKEN }}
|
||||
117
.github/workflows/ci.yml
vendored
117
.github/workflows/ci.yml
vendored
@@ -1,71 +1,76 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
|
||||
name: CI
|
||||
|
||||
env:
|
||||
CI_CARGO_MAKE_VERSION: 0.35.8
|
||||
CI_CARGO_MAKE_VERSION: 0.35.16
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
name: Linux
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
rust: ["1.59.0", "stable"]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
triple: x86_64-unknown-linux-musl
|
||||
- os: windows-latest
|
||||
triple: x86_64-pc-windows-msvc
|
||||
- os: macos-latest
|
||||
triple: x86_64-apple-darwin
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: hecrj/setup-rust-action@50a120e4d34903c2c1383dec0e9b1d349a9cc2b1
|
||||
with:
|
||||
rust-version: ${{ matrix.rust }}
|
||||
components: rustfmt,clippy
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install cargo-make on Linux or macOS
|
||||
if: ${{ runner.os != 'windows' }}
|
||||
shell: bash
|
||||
run: |
|
||||
curl -LO 'https://github.com/sagiegurari/cargo-make/releases/download/${{ env.CI_CARGO_MAKE_VERSION }}/cargo-make-v${{ env.CI_CARGO_MAKE_VERSION }}-${{ matrix.triple }}.zip'
|
||||
unzip 'cargo-make-v${{ env.CI_CARGO_MAKE_VERSION }}-${{ matrix.triple }}.zip'
|
||||
cp 'cargo-make-v${{ env.CI_CARGO_MAKE_VERSION }}-${{ matrix.triple }}/cargo-make' ~/.cargo/bin/
|
||||
cargo make --version
|
||||
- name: Install cargo-make on Windows
|
||||
if: ${{ runner.os == 'windows' }}
|
||||
shell: bash
|
||||
run: |
|
||||
# `cargo-make-v0.35.16-{target}/` directory is created on Linux and macOS, but it is not creatd on Windows.
|
||||
mkdir cargo-make-temporary
|
||||
cd cargo-make-temporary
|
||||
curl -LO 'https://github.com/sagiegurari/cargo-make/releases/download/${{ env.CI_CARGO_MAKE_VERSION }}/cargo-make-v${{ env.CI_CARGO_MAKE_VERSION }}-${{ matrix.triple }}.zip'
|
||||
unzip 'cargo-make-v${{ env.CI_CARGO_MAKE_VERSION }}-${{ matrix.triple }}.zip'
|
||||
cp cargo-make.exe ~/.cargo/bin/
|
||||
cd ..
|
||||
cargo make --version
|
||||
- name: "Format / Build / Test"
|
||||
run: cargo make ci
|
||||
env:
|
||||
RUST_BACKTRACE: full
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
rust: ["1.56.1", "stable"]
|
||||
steps:
|
||||
- uses: hecrj/setup-rust-action@967aec96c6a27a0ce15c1dac3aaba332d60565e2
|
||||
- name: Checkout
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
rust-version: ${{ matrix.rust }}
|
||||
components: rustfmt,clippy
|
||||
- uses: actions/checkout@v1
|
||||
- name: "Get cargo bin directory"
|
||||
id: cargo-bin-dir
|
||||
run: echo "::set-output name=dir::$HOME/.cargo/bin"
|
||||
- name: "Cache cargo make"
|
||||
id: cache-cargo-make
|
||||
uses: actions/cache@v2
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: "Check conventional commits"
|
||||
uses: crate-ci/committed@master
|
||||
with:
|
||||
path: ${{ steps.cargo-bin-dir.outputs.dir }}/cargo-make
|
||||
key: ${{ runner.os }}-${{ matrix.rust }}-cargo-make-${{ env.CI_CARGO_MAKE_VERSION }}
|
||||
- name: "Install cargo-make"
|
||||
if: steps.cache-cargo-make.outputs.cache-hit != 'true'
|
||||
run: cargo install cargo-make --version ${{ env.CI_CARGO_MAKE_VERSION }}
|
||||
- name: "Format / Build / Test"
|
||||
run: cargo make ci
|
||||
env:
|
||||
RUST_BACKTRACE: full
|
||||
windows:
|
||||
name: Windows
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
rust: ["1.56.1", "stable"]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: hecrj/setup-rust-action@967aec96c6a27a0ce15c1dac3aaba332d60565e2
|
||||
with:
|
||||
rust-version: ${{ matrix.rust }}
|
||||
components: rustfmt,clippy
|
||||
- uses: actions/checkout@v1
|
||||
- name: "Get cargo bin directory"
|
||||
id: cargo-bin-dir
|
||||
run: echo "::set-output name=dir::$HOME\.cargo\bin"
|
||||
- name: "Cache cargo make"
|
||||
id: cache-cargo-make
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.cargo-bin-dir.outputs.dir }}\cargo-make.exe
|
||||
key: ${{ runner.os }}-${{ matrix.rust }}-cargo-make-${{ env.CI_CARGO_MAKE_VERSION }}
|
||||
- name: "Install cargo-make"
|
||||
if: steps.cache-cargo-make.outputs.cache-hit != 'true'
|
||||
run: cargo install cargo-make --version ${{ env.CI_CARGO_MAKE_VERSION }}
|
||||
- name: "Format / Build / Test"
|
||||
run: cargo make ci
|
||||
env:
|
||||
RUST_BACKTRACE: full
|
||||
args: "-vv"
|
||||
commits: "HEAD"
|
||||
- name: "Check typos"
|
||||
uses: crate-ci/typos@master
|
||||
|
||||
44
APPS.md
Normal file
44
APPS.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Apps using `ratatui`
|
||||
|
||||
| Name | Description | Author |
|
||||
| -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
||||
| [adsb_deku/radar](https://github.com/rsadsb/adsb_deku#radar-tui) | Rust ADS-B decoder + TUI radar application | [Rust ADS-B](https://github.com/rsadsb) |
|
||||
| [bandwhich](https://github.com/imsnif/bandwhich) | Terminal utility for displaying current network utilization by process, connection and remote IP/hostname | [Aram Drevekenin](https://github.com/imsnif) |
|
||||
| [battleship.rs](https://github.com/deepu105/battleship-rs) | A terminal battleship game in Rust | [Deepu K Sasidharan](https://github.com/deepu105) |
|
||||
| [bottom](https://github.com/ClementTsang/bottom) | Yet another cross-platform graphical process/system monitor | [Clement Tsang](https://github.com/ClementTsang) |
|
||||
| [conclusive](https://github.com/mrusme/conclusive) | Command line client for Plausible Analytics | [mrusme](https://github.com/mrusme) |
|
||||
| [cotp](https://github.com/replydev/cotp) | Trustworthy, encrypted, command-line TOTP/HOTP authenticator app with import functionality | [Reply](https://github.com/replydev) |
|
||||
| [cube timer](https://github.com/paarthmadan/cube) | A tui-based Rubik's cube timer written in Rust | [Paarth Madan](https://github.com/paarthmadan) |
|
||||
| [desed](https://github.com/SoptikHa2/desed) | Debugger for Sed: demystify and debug your sed scripts, from comfort of your terminal | [Petr Šťastný](https://github.com/SoptikHa2) |
|
||||
| [diskonaut](https://github.com/imsnif/diskonaut) | Terminal disk space navigator | [Aram Drevekenin](https://github.com/imsnif) |
|
||||
| [exhaust](https://github.com/heyrict/exhaust) | Exhaust all your possibilities.. for the next coming exam | [Zhenhui Xie](https://github.com/heyrict) |
|
||||
| [game-of-life-rs](https://github.com/kachark/game-of-life-rs) | Conway's Game of Life implemented in Rust and visualized with Tui-rs | [kachark](https://github.com/kachark) |
|
||||
| [gitui](https://github.com/extrawurst/gitui) | Blazing fast terminal-ui for Git written in Rust | [extrawurst](https://github.com/extrawurst) |
|
||||
| [glicol-cli](https://github.com/glicol/glicol-cli) | Music live coding in terminal | [glicol](https://github.com/glicol) |
|
||||
| [gpg-tui](https://github.com/orhun/gpg-tui) | Manage your GnuPG keys with ease! | [Orhun Parmaksız](https://github.com/orhun) |
|
||||
| [gping](https://github.com/orf/gping) | Ping, but with a graph | [Tom Forbes](https://github.com/orf) |
|
||||
| [joshuto](https://github.com/kamiyaa/joshuto) | Ranger-like terminal file manager written in Rust | [Jeff Zhao](https://github.com/kamiyaa) |
|
||||
| [kDash](https://github.com/kdash-rs/kdash) | A simple and fast dashboard for Kubernetes | [kdash-rs ](https://github.com/kdash-rs) |
|
||||
| [kmon](https://github.com/orhun/kmon) | Linux Kernel Manager and Activity Monitor | [Orhun Parmaksız](https://github.com/orhun) |
|
||||
| [kubectl-watch](https://github.com/imuxin/kubectl-watch) | A kubectl plugin to provide a pretty delta change view of being watched kubernetes resources | [牧心](https://github.com/imuxin) |
|
||||
| [logss](https://github.com/todoesverso/logss) | A simple command line tool that helps you visualize an input stream of text. | [Victor Rosales](https://github.com/todoesverso) |
|
||||
| [minesweep](https://github.com/cpcloud/minesweep-rs) | Sweep some mines for fun, and probably not for profit | [Phillip Cloud](https://github.com/cpcloud) |
|
||||
| [oha](https://github.com/hatoo/oha) | HTTP load generator, inspired by rakyll/hey with tui animation | [hatoo](https://github.com/hatoo) |
|
||||
| [oxker](https://github.com/mrjackwills/oxker) | a simple tui to view & control docker containers | [Jack Wills](https://github.com/mrjackwills) |
|
||||
| [poketex](https://github.com/ckaznable/poketex) | A simple pokedex based on TUI | [CK Aznable](https://github.com/ckaznable) |
|
||||
| [repgrep](https://github.com/acheronfail/repgrep) | An interactive find and replace app powered by ripgrep | [acheronfail](https://github.com/acheronfail) |
|
||||
| [rrtop](https://github.com/wojciech-zurek/rrtop) | Redis monitoring (top like) app | [Wojciech Żurek](https://github.com/wojciech-zurek) |
|
||||
| [rust-sadari-cli](https://github.com/24seconds/rust-sadari-cli) | Sadari game based on terminal | [24seconds](https://github.com/24seconds) |
|
||||
| [rusty-krab-manager](https://github.com/aryakaul/rusty-krab-manager) | Time-management TUI in Rust | [Arya](https://github.com/aryakaul) |
|
||||
| [spotify-tui](https://github.com/Rigellute/spotify-tui) | Spotify for the terminal written in Rust | [Alexander Keliris](https://github.com/Rigellute) |
|
||||
| [systeroid](https://github.com/orhun/systeroid) | A more powerful alternative to sysctl(8) with a terminal user interface | [Orhun Parmaksız](https://github.com/orhun) |
|
||||
| [taskwarrior-tui](https://github.com/kdheepak/taskwarrior-tui) | A terminal user interface for Taskwarrior | [Dheepak Krishnamurthy](https://github.com/kdheepak) |
|
||||
| [termchat](https://github.com/lemunozm/termchat) | Terminal chat through the LAN with video streaming and file transfer | [Luis Enrique Muñoz Martín](https://github.com/lemunozm) |
|
||||
| [termscp](https://github.com/veeso/termscp) | A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/S3 | [Christian Visintin](https://github.com/veeso) |
|
||||
| [tick-rs](https://github.com/tarkah/tickrs) | Realtime ticker data in your terminal | [Cory Forsstrom](https://github.com/tarkah) |
|
||||
| [tsuchita](https://github.com/kamiyaa/tsuchita) | Client-server notification center for dbus desktop notifications | [Jeff Zhao](https://github.com/kamiyaa) |
|
||||
| [tuinance](https://github.com/landchad/tuinance) | Display financial data on the terminal | [bloatoo](https://github.com/bloatoo) |
|
||||
| [vector](https://vector.dev) | A lightweight, ultra-fast tool for building observability pipelines | [vectordotdev](https://github.com/vectordotdev) |
|
||||
| [xplr](https://github.com/sayanarijit/xplr) | A hackable, minimal, fast TUI file explorer | [Arijit Basu](https://github.com/sayanarijit/xplr) |
|
||||
| [ytop](https://github.com/cjbassi/ytop) | A TUI system monitor written in Rust (no longer maintained) | [Caleb Bassi](https://github.com/cjbassi) |
|
||||
| [zenith](https://github.com/bvaisvil/zenith) | Sort of like top or htop but with zoom-able charts, CPU, GPU, network, and disk usage | [Benjamin Vaisvil](https://github.com/bvaisvil) |
|
||||
133
CHANGELOG.md
133
CHANGELOG.md
@@ -1,6 +1,121 @@
|
||||
# Changelog
|
||||
|
||||
## To be released
|
||||
## v0.20.1 - 2023-03-19
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- *(style)* Bold needs a bit ([#104](https://github.com/tui-rs-revival/ratatui/issues/104))
|
||||
|
||||
### Documentation
|
||||
|
||||
- *(apps)* Add "logss" to apps ([#105](https://github.com/tui-rs-revival/ratatui/issues/105))
|
||||
- *(uncategorized)* Fixup remaining tui references ([#106](https://github.com/tui-rs-revival/ratatui/issues/106))
|
||||
|
||||
### Contributors
|
||||
|
||||
Thank you so much to everyone that contributed to this release!
|
||||
|
||||
- [@joshka](https://github.com/)
|
||||
- [@todoesverso](https://github.com/todoesverso)
|
||||
- [@UncleScientist](https://github.com/UncleScientist)
|
||||
|
||||
## v0.20.0 - 2023-03-19
|
||||
|
||||
This marks the first release of `ratatui`, a community-maintained fork of [tui](https://github.com/fdehau/tui-rs).
|
||||
|
||||
The purpose of this release is to include **bug fixes** and **small changes** into the repository thus **no new features** are added. We have transferred all the pull requests from the original repository and worked on the low hanging ones to incorporate them in this "maintenance" release.
|
||||
|
||||
Here is a list of changes:
|
||||
|
||||
### Features
|
||||
|
||||
- *(cd)* Add continuous deployment workflow ([#93](https://github.com/tui-rs-revival/ratatui/issues/93))
|
||||
- *(ci)* Add MacOS to CI ([#60](https://github.com/tui-rs-revival/ratatui/issues/60))
|
||||
- *(widget)* Add `offset()` to `TableState` ([#10](https://github.com/tui-rs-revival/ratatui/issues/10))
|
||||
- *(widget)* Add `width()` to ListItem ([#17](https://github.com/tui-rs-revival/ratatui/issues/17))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- *(ci)* Test MSRV compatibility on CI ([#85](https://github.com/tui-rs-revival/ratatui/issues/85))
|
||||
- *(ci)* Bump Rust version to 1.63.0 ([#80](https://github.com/tui-rs-revival/ratatui/issues/80))
|
||||
- *(ci)* Use env for the cargo-make version ([#76](https://github.com/tui-rs-revival/ratatui/issues/76))
|
||||
- *(ci)* Fix deprecation warnings on CI ([#58](https://github.com/tui-rs-revival/ratatui/issues/58))
|
||||
- *(doc)* Add 3rd party libraries accidentally removed at #21 ([#61](https://github.com/tui-rs-revival/ratatui/issues/61))
|
||||
- *(widget)* List should not ignore empty string items ([#42](https://github.com/tui-rs-revival/ratatui/issues/42)) [**breaking**]
|
||||
- *(uncategorized)* Cassowary/layouts: add extra constraints for fixing Min(v)/Max(v) combination. ([#31](https://github.com/tui-rs-revival/ratatui/issues/31))
|
||||
- *(uncategorized)* Fix user_input example double key press registered on windows
|
||||
- *(uncategorized)* Ignore zero-width symbol on rendering `Paragraph`
|
||||
- *(uncategorized)* Fix typos ([#45](https://github.com/tui-rs-revival/ratatui/issues/45))
|
||||
- *(uncategorized)* Fix typos ([#47](https://github.com/tui-rs-revival/ratatui/issues/47))
|
||||
|
||||
### Refactor
|
||||
|
||||
- *(style)* Make bitflags smaller ([#13](https://github.com/tui-rs-revival/ratatui/issues/13))
|
||||
|
||||
### Documentation
|
||||
|
||||
- *(apps)* Move 'apps using ratatui' to dedicated file ([#98](https://github.com/tui-rs-revival/ratatui/issues/98)) ([#99](https://github.com/tui-rs-revival/ratatui/issues/99))
|
||||
- *(canvas)* Add documentation for x_bounds, y_bounds ([#35](https://github.com/tui-rs-revival/ratatui/issues/35))
|
||||
- *(contributing)* Specify the use of unsafe for optimization ([#67](https://github.com/tui-rs-revival/ratatui/issues/67))
|
||||
- *(github)* Remove pull request template ([#68](https://github.com/tui-rs-revival/ratatui/issues/68))
|
||||
- *(readme)* Update crate status badge ([#102](https://github.com/tui-rs-revival/ratatui/issues/102))
|
||||
- *(readme)* Small edits before first release ([#101](https://github.com/tui-rs-revival/ratatui/issues/101))
|
||||
- *(readme)* Add install instruction and update title ([#100](https://github.com/tui-rs-revival/ratatui/issues/100))
|
||||
- *(readme)* Add systeroid to application list ([#92](https://github.com/tui-rs-revival/ratatui/issues/92))
|
||||
- *(readme)* Add glicol-cli to showcase list ([#95](https://github.com/tui-rs-revival/ratatui/issues/95))
|
||||
- *(readme)* Add oxker to application list ([#74](https://github.com/tui-rs-revival/ratatui/issues/74))
|
||||
- *(readme)* Add app kubectl-watch which uses tui ([#73](https://github.com/tui-rs-revival/ratatui/issues/73))
|
||||
- *(readme)* Add poketex to 'apps using tui' in README ([#64](https://github.com/tui-rs-revival/ratatui/issues/64))
|
||||
- *(readme)* Update README.md ([#39](https://github.com/tui-rs-revival/ratatui/issues/39))
|
||||
- *(readme)* Update README.md ([#40](https://github.com/tui-rs-revival/ratatui/issues/40))
|
||||
- *(readme)* Clarify README.md fork status update
|
||||
- *(uncategorized)* Fix: fix typos ([#90](https://github.com/tui-rs-revival/ratatui/issues/90))
|
||||
- *(uncategorized)* Update to build more backends ([#81](https://github.com/tui-rs-revival/ratatui/issues/81))
|
||||
- *(uncategorized)* Expand "Apps" and "Third-party" sections ([#21](https://github.com/tui-rs-revival/ratatui/issues/21))
|
||||
- *(uncategorized)* Add tui-input and update xplr in README.md
|
||||
- *(uncategorized)* Add hncli to list of applications made with tui-rs ([#41](https://github.com/tui-rs-revival/ratatui/issues/41))
|
||||
- *(uncategorized)* Updated readme and contributing guide with updates about the fork ([#46](https://github.com/tui-rs-revival/ratatui/issues/46))
|
||||
|
||||
### Performance
|
||||
|
||||
- *(layout)* Better safe shared layout cache ([#62](https://github.com/tui-rs-revival/ratatui/issues/62))
|
||||
|
||||
### Miscellaneous Tasks
|
||||
|
||||
- *(cargo)* Update project metadata ([#94](https://github.com/tui-rs-revival/ratatui/issues/94))
|
||||
- *(ci)* Integrate `typos` for checking typos ([#91](https://github.com/tui-rs-revival/ratatui/issues/91))
|
||||
- *(ci)* Change the target branch to main ([#79](https://github.com/tui-rs-revival/ratatui/issues/79))
|
||||
- *(ci)* Re-enable clippy on CI ([#59](https://github.com/tui-rs-revival/ratatui/issues/59))
|
||||
- *(uncategorized)* Integrate `committed` for checking conventional commits ([#77](https://github.com/tui-rs-revival/ratatui/issues/77))
|
||||
- *(uncategorized)* Update `rust-version` to 1.59 in Cargo.toml ([#57](https://github.com/tui-rs-revival/ratatui/issues/57))
|
||||
- *(uncategorized)* Update deps ([#51](https://github.com/tui-rs-revival/ratatui/issues/51))
|
||||
- *(uncategorized)* Fix typo in layout.rs ([#619](https://github.com/tui-rs-revival/ratatui/issues/619))
|
||||
- *(uncategorized)* Add apps using `tui`
|
||||
|
||||
### Contributors
|
||||
|
||||
Thank you so much to everyone that contributed to this release!
|
||||
|
||||
- [@orhun](https://github.com/orhun)
|
||||
- [@mindoodoo](https://github.com/mindoodoo)
|
||||
- [@sayanarijit](https://github.com/sayanarijit)
|
||||
- [@Owletti](https://github.com/Owletti)
|
||||
- [@UncleScientist](https://github.com/UncleScientist)
|
||||
- [@rhysd](https://github.com/rhysd)
|
||||
- [@ckaznable](https://github.com/ckaznable)
|
||||
- [@imuxin](https://github.com/imuxin)
|
||||
- [@mrjackwills](https://github.com/mrjackwills)
|
||||
- [@conradludgate](https://github.com/conradludgate)
|
||||
- [@kianmeng](https://github.com/kianmeng)
|
||||
- [@chaosprint](https://github.com/chaosprint)
|
||||
|
||||
And most importantly, special thanks to [Florian Dehau](https://github.com/fdehau) for creating this awesome library 💖 We look forward to building on the strong foundations that the original crate laid out.
|
||||
|
||||
## v0.19.0 - 2022-08-14
|
||||
|
||||
### Features
|
||||
|
||||
* Bump `crossterm` to `0.25`
|
||||
|
||||
## v0.18.0 - 2022-04-24
|
||||
|
||||
@@ -12,7 +127,7 @@
|
||||
|
||||
### Features
|
||||
|
||||
* Add option to `widgets::List` to repeat the hightlight symbol for each line of multi-line items (#533).
|
||||
* Add option to `widgets::List` to repeat the highlight symbol for each line of multi-line items (#533).
|
||||
* Add option to control the alignment of `Axis` labels in the `Chart` widget (#568).
|
||||
|
||||
### Breaking changes
|
||||
@@ -270,7 +385,7 @@ In this new release, you may now write this as:
|
||||
```rust
|
||||
Block::default()
|
||||
.style(Style::default().bg(Color::Green))
|
||||
// The style is not overidden anymore, we simply add new style rule for the title.
|
||||
// The style is not overridden anymore, we simply add new style rule for the title.
|
||||
.title(Span::styled("My title", Style::default().add_modifier(Modifier::BOLD)))
|
||||
```
|
||||
|
||||
@@ -278,9 +393,9 @@ In addition, the crate now provides a method `patch` to combine two styles into
|
||||
rules:
|
||||
|
||||
```rust
|
||||
let style = Style::default().modifer(Modifier::BOLD);
|
||||
let style = Style::default().modifier(Modifier::BOLD);
|
||||
let style = style.patch(Style::default().add_modifier(Modifier::ITALIC));
|
||||
// style.modifer == Modifier::BOLD | Modifier::ITALIC, the modifier has been enriched not overidden
|
||||
// style.modifier == Modifier::BOLD | Modifier::ITALIC, the modifier has been enriched not overridden
|
||||
```
|
||||
|
||||
- `Style::modifier` has been removed in favor of `Style::add_modifier` and `Style::remove_modifier`.
|
||||
@@ -598,7 +713,7 @@ let style = Style::default().add_modifier(Modifier::ITALIC | Modifier::BOLD);
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Ensure correct behavoir of the alternate screens with the `Crossterm` backend.
|
||||
* Ensure correct behavior of the alternate screens with the `Crossterm` backend.
|
||||
* Fix out of bounds panic when two `Buffer` are merged.
|
||||
|
||||
## v0.4.0 - 2019-02-03
|
||||
@@ -667,7 +782,7 @@ additional `termion` features.
|
||||
|
||||
* Replace `Item` by a generic and flexible `Text` that can be used in both
|
||||
`Paragraph` and `List` widgets.
|
||||
* Remove unecessary borrows on `Style`.
|
||||
* Remove unnecessary borrows on `Style`.
|
||||
|
||||
## v0.3.0-beta.0 - 2018-09-04
|
||||
|
||||
@@ -690,7 +805,7 @@ widgets on the given `Frame`
|
||||
* All widgets use the consumable builder pattern
|
||||
* `SelectableList` can have no selected item and the highlight symbol is hidden
|
||||
in this case
|
||||
* Remove markup langage inside `Paragraph`. `Paragraph` now expects an iterator
|
||||
* Remove markup language inside `Paragraph`. `Paragraph` now expects an iterator
|
||||
of `Text` items
|
||||
|
||||
## v0.2.3 - 2018-06-09
|
||||
@@ -698,7 +813,7 @@ of `Text` items
|
||||
### Features
|
||||
|
||||
* Add `start_corner` option for `List`
|
||||
* Add more text aligment options for `Paragraph`
|
||||
* Add more text alignment options for `Paragraph`
|
||||
|
||||
## v0.2.2 - 2018-05-06
|
||||
|
||||
|
||||
@@ -1,10 +1,38 @@
|
||||
# Fork Status
|
||||
|
||||
## Pull Requests
|
||||
|
||||
**All** pull requests opened on the original repository have been imported. We'll be going through any open PRs in a timely manner, starting with the **smallest bug fixes and README updates**. If you have an open PR make sure to let us know about it on our [discord](https://discord.gg/pMCEU9hNEj) as it helps to know you are still active.
|
||||
|
||||
## Issues
|
||||
|
||||
We have been unsuccessful in importing all issues opened on the previous repository.
|
||||
For that reason, anyone wanting to **work on or discuss** an issue will have to follow the following workflow :
|
||||
|
||||
- Recreate the issue
|
||||
- Start by referencing the **original issue**: ```Referencing issue #[<issue number>](<original issue link>)```
|
||||
- Then, paste the original issues **opening** text
|
||||
|
||||
You can then resume the conversation by replying to this new issue you have created.
|
||||
|
||||
### Closing Issues
|
||||
|
||||
If you close an issue that you have "imported" to this fork, please make sure that you add the issue to the **CLOSED_ISSUES.md**. This will enable us to keep track of which issues have been closed from the original repo, in case we are able to have the original repository transferred.
|
||||
|
||||
# Contributing
|
||||
|
||||
## Implementation Guidelines
|
||||
|
||||
### Use of unsafe for optimization purposes
|
||||
|
||||
**Do not** use unsafe to achieve better performances. This is subject to change, [see.](https://github.com/tui-rs-revival/tui-rs-revival/discussions/66)
|
||||
The only exception to this rule is if it's to fix **reproducible slowness.**
|
||||
|
||||
## Building
|
||||
|
||||
[cargo-make]: https://github.com/sagiegurari/cargo-make "cargo-make"
|
||||
|
||||
`tui` is an ordinary Rust project where common tasks are managed with [cargo-make].
|
||||
`ratatui` is an ordinary Rust project where common tasks are managed with [cargo-make].
|
||||
It wraps common `cargo` commands with sane defaults depending on your platform of choice.
|
||||
Building the project should be as easy as running `cargo make build`.
|
||||
|
||||
@@ -28,6 +56,6 @@ You can also check most of those things yourself locally using `cargo make ci` w
|
||||
## Tests
|
||||
|
||||
The test coverage of the crate is far from being ideal but we already have a fair amount of tests in place.
|
||||
Beside the usual doc and unit tests, one of the most valuable test you can write for `tui` is a test again the `TestBackend`.
|
||||
Beside the usual doc and unit tests, one of the most valuable test you can write for `ratatui` is a test against the `TestBackend`.
|
||||
It allows you to assert the content of the output buffer that would have been flushed to the terminal after a given draw call.
|
||||
See `widgets_block_renders` in [tests/widgets_block.rs](./tests/widget_block.rs) for an example.
|
||||
|
||||
18
Cargo.toml
18
Cargo.toml
@@ -1,31 +1,35 @@
|
||||
[package]
|
||||
name = "tui"
|
||||
version = "0.18.0"
|
||||
name = "ratatui"
|
||||
version = "0.20.1"
|
||||
authors = ["Florian Dehau <work@fdehau.com>"]
|
||||
description = """
|
||||
A library to build rich terminal user interfaces or dashboards
|
||||
"""
|
||||
documentation = "https://docs.rs/tui/0.18.0/tui/"
|
||||
documentation = "https://docs.rs/ratatui/latest/ratatui/"
|
||||
keywords = ["tui", "terminal", "dashboard"]
|
||||
repository = "https://github.com/fdehau/tui-rs"
|
||||
repository = "https://github.com/tui-rs-revival/ratatui"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
exclude = ["assets/*", ".github", "Makefile.toml", "CONTRIBUTING.md", "*.log", "tags"]
|
||||
autoexamples = true
|
||||
edition = "2021"
|
||||
rust-version = "1.59.0"
|
||||
|
||||
[badges]
|
||||
|
||||
[features]
|
||||
default = ["crossterm"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.3"
|
||||
cassowary = "0.3"
|
||||
unicode-segmentation = "1.2"
|
||||
unicode-segmentation = "1.10"
|
||||
unicode-width = "0.1"
|
||||
termion = { version = "1.5", optional = true }
|
||||
crossterm = { version = "0.23", optional = true }
|
||||
termion = { version = "2.0", optional = true }
|
||||
crossterm = { version = "0.26", optional = true }
|
||||
serde = { version = "1", optional = true, features = ["derive"]}
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
135
README.md
135
README.md
@@ -1,19 +1,42 @@
|
||||
# tui-rs
|
||||
# ratatui
|
||||
|
||||
[](https://github.com/fdehau/tui-rs/actions?query=workflow%3ACI+)
|
||||
[](https://crates.io/crates/tui)
|
||||
[](https://docs.rs/crate/tui/)
|
||||
An actively maintained `tui`-rs fork.
|
||||
|
||||
[](https://github.com/tui-rs-revival/ratatui/actions?query=workflow%3ACI+)
|
||||
[](https://crates.io/crates/ratatui)
|
||||
[](https://docs.rs/crate/ratatui/)
|
||||
|
||||
<img src="./assets/demo.gif" alt="Demo cast under Linux Termite with Inconsolata font 12pt">
|
||||
|
||||
`tui-rs` is a [Rust](https://www.rust-lang.org) library to build rich terminal
|
||||
# Install
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
tui = { package = "ratatui" }
|
||||
```
|
||||
|
||||
# What is this fork?
|
||||
|
||||
This fork was created to continue maintenance on the original TUI project. The original maintainer had created an [issue](https://github.com/fdehau/tui-rs/issues/654) explaining how he couldn't find time to continue development, which led to us creating this fork.
|
||||
|
||||
With that in mind, **we the community** look forward to continuing the work started by [**Florian Dehau.**](https://github.com/fdehau) :rocket:
|
||||
|
||||
In order to organize ourselves, we currently use a [discord server](https://discord.gg/pMCEU9hNEj), feel free to join and come chat ! There are also plans to implement a [matrix](https://matrix.org/) bridge in the near future.
|
||||
**Discord is not a MUST to contribute,** we follow a pretty standard github centered open source workflow keeping the most important conversations on github, open an issue or PR and it will be addressed. :smile:
|
||||
|
||||
Please make sure you read the updated contributing guidelines, especially if you are interested in working on a PR or issue opened in the previous repository.
|
||||
|
||||
# Introduction
|
||||
|
||||
`ratatui`-rs is a [Rust](https://www.rust-lang.org) library to build rich terminal
|
||||
user interfaces and dashboards. It is heavily inspired by the `Javascript`
|
||||
library [blessed-contrib](https://github.com/yaronn/blessed-contrib) and the
|
||||
`Go` library [termui](https://github.com/gizak/termui).
|
||||
|
||||
The library supports multiple backends:
|
||||
- [crossterm](https://github.com/crossterm-rs/crossterm) [default]
|
||||
- [termion](https://github.com/ticki/termion)
|
||||
|
||||
- [crossterm](https://github.com/crossterm-rs/crossterm) [default]
|
||||
- [termion](https://github.com/ticki/termion)
|
||||
|
||||
The library is based on the principle of immediate rendering with intermediate
|
||||
buffers. This means that at each new frame you should build all widgets that are
|
||||
@@ -26,13 +49,15 @@ comes from the terminal emulator than the library itself.
|
||||
Moreover, the library does not provide any input handling nor any event system and
|
||||
you may rely on the previously cited libraries to achieve such features.
|
||||
|
||||
### Rust version requirements
|
||||
## Rust version requirements
|
||||
|
||||
Since version 0.17.0, `tui` requires **rustc version 1.56.1 or greater**.
|
||||
Since version 0.17.0, `ratatui` requires **rustc version 1.59.0 or greater**.
|
||||
|
||||
### [Documentation](https://docs.rs/tui)
|
||||
# Documentation
|
||||
|
||||
### Demo
|
||||
The documentation can be found on [docs.rs.](https://docs.rs/ratatui)
|
||||
|
||||
# Demo
|
||||
|
||||
The demo shown in the gif can be run with all available backends.
|
||||
|
||||
@@ -45,8 +70,8 @@ cargo run --example demo --no-default-features --features=termion --release -- -
|
||||
|
||||
where `tick-rate` is the UI refresh rate in ms.
|
||||
|
||||
The UI code is in [examples/demo/ui.rs](https://github.com/fdehau/tui-rs/blob/v0.18.0/examples/demo/ui.rs) while the
|
||||
application state is in [examples/demo/app.rs](https://github.com/fdehau/tui-rs/blob/v0.18.0/examples/demo/app.rs).
|
||||
The UI code is in [examples/demo/ui.rs](https://github.com/tui-rs-revival/ratatui/blob/main/examples/demo/ui.rs) while the
|
||||
application state is in [examples/demo/app.rs](https://github.com/tui-rs-revival/ratatui/blob/main/examples/demo/app.rs).
|
||||
|
||||
If the user interface contains glyphs that are not displayed correctly by your terminal, you may want to run
|
||||
the demo without those symbols:
|
||||
@@ -55,72 +80,56 @@ the demo without those symbols:
|
||||
cargo run --example demo --release -- --tick-rate 200 --enhanced-graphics false
|
||||
```
|
||||
|
||||
### Widgets
|
||||
# Widgets
|
||||
|
||||
## Built in
|
||||
|
||||
The library comes with the following list of widgets:
|
||||
|
||||
* [Block](https://github.com/fdehau/tui-rs/blob/v0.18.0/examples/block.rs)
|
||||
* [Gauge](https://github.com/fdehau/tui-rs/blob/v0.18.0/examples/gauge.rs)
|
||||
* [Sparkline](https://github.com/fdehau/tui-rs/blob/v0.18.0/examples/sparkline.rs)
|
||||
* [Chart](https://github.com/fdehau/tui-rs/blob/v0.18.0/examples/chart.rs)
|
||||
* [BarChart](https://github.com/fdehau/tui-rs/blob/v0.18.0/examples/barchart.rs)
|
||||
* [List](https://github.com/fdehau/tui-rs/blob/v0.18.0/examples/list.rs)
|
||||
* [Table](https://github.com/fdehau/tui-rs/blob/v0.18.0/examples/table.rs)
|
||||
* [Paragraph](https://github.com/fdehau/tui-rs/blob/v0.18.0/examples/paragraph.rs)
|
||||
* [Canvas (with line, point cloud, map)](https://github.com/fdehau/tui-rs/blob/v0.18.0/examples/canvas.rs)
|
||||
* [Tabs](https://github.com/fdehau/tui-rs/blob/v0.18.0/examples/tabs.rs)
|
||||
- [Block](https://github.com/tui-rs-revival/ratatui/blob/main/examples/block.rs)
|
||||
- [Gauge](https://github.com/tui-rs-revival/ratatui/blob/main/examples/gauge.rs)
|
||||
- [Sparkline](https://github.com/tui-rs-revival/ratatui/blob/main/examples/sparkline.rs)
|
||||
- [Chart](https://github.com/tui-rs-revival/ratatui/blob/main/examples/chart.rs)
|
||||
- [BarChart](https://github.com/tui-rs-revival/ratatui/blob/main/examples/barchart.rs)
|
||||
- [List](https://github.com/tui-rs-revival/ratatui/blob/main/examples/list.rs)
|
||||
- [Table](https://github.com/tui-rs-revival/ratatui/blob/main/examples/table.rs)
|
||||
- [Paragraph](https://github.com/tui-rs-revival/ratatui/blob/main/examples/paragraph.rs)
|
||||
- [Canvas (with line, point cloud, map)](https://github.com/tui-rs-revival/ratatui/blob/main/examples/canvas.rs)
|
||||
- [Tabs](https://github.com/tui-rs-revival/ratatui/blob/main/examples/tabs.rs)
|
||||
|
||||
Click on each item to see the source of the example. Run the examples with with
|
||||
Click on each item to see the source of the example. Run the examples with with
|
||||
cargo (e.g. to run the gauge example `cargo run --example gauge`), and quit by pressing `q`.
|
||||
|
||||
You can run all examples by running `cargo make run-examples` (require
|
||||
`cargo-make` that can be installed with `cargo install cargo-make`).
|
||||
|
||||
### Third-party widgets
|
||||
### Third-party libraries, bootstrapping templates and widgets
|
||||
|
||||
* [tui-logger](https://github.com/gin66/tui-logger)
|
||||
- [ansi-to-tui](https://github.com/uttarayan21/ansi-to-tui) — Convert ansi colored text to `tui::text::Text`
|
||||
- [color-to-tui](https://github.com/uttarayan21/color-to-tui) — Parse hex colors to `tui::style::Color`
|
||||
- [rust-tui-template](https://github.com/orhun/rust-tui-template) — A template for bootstrapping a Rust TUI application with Tui-rs & crossterm
|
||||
- [simple-tui-rs](https://github.com/pmsanford/simple-tui-rs) — A simple example tui-rs app
|
||||
- [tui-builder](https://github.com/jkelleyrtp/tui-builder) — Batteries-included MVC framework for Tui-rs + Crossterm apps
|
||||
- [tui-clap](https://github.com/kegesch/tui-clap-rs) — Use clap-rs together with Tui-rs
|
||||
- [tui-log](https://github.com/kegesch/tui-log-rs) — Example of how to use logging with Tui-rs
|
||||
- [tui-logger](https://github.com/gin66/tui-logger) — Logger and Widget for Tui-rs
|
||||
- [tui-realm](https://github.com/veeso/tui-realm) — Tui-rs framework to build stateful applications with a React/Elm inspired approach
|
||||
- [tui-realm-treeview](https://github.com/veeso/tui-realm-treeview) — Treeview component for Tui-realm
|
||||
- [tui tree widget](https://github.com/EdJoPaTo/tui-rs-tree-widget) — Tree Widget for Tui-rs
|
||||
- [tui-windows](https://github.com/markatk/tui-windows-rs) — Tui-rs abstraction to handle multiple windows and their rendering
|
||||
- [tui-textarea](https://github.com/rhysd/tui-textarea): Simple yet powerful multi-line text editor widget supporting several key shortcuts, undo/redo, text search, etc.
|
||||
- [tui-rs-tree-widgets](https://github.com/EdJoPaTo/tui-rs-tree-widget): Widget for tree data structures.
|
||||
- [tui-input](https://github.com/sayanarijit/tui-input): TUI input library supporting multiple backends and tui-rs.
|
||||
|
||||
### Apps using tui
|
||||
# Apps
|
||||
|
||||
* [spotify-tui](https://github.com/Rigellute/spotify-tui)
|
||||
* [bandwhich](https://github.com/imsnif/bandwhich)
|
||||
* [kmon](https://github.com/orhun/kmon)
|
||||
* [gpg-tui](https://github.com/orhun/gpg-tui)
|
||||
* [ytop](https://github.com/cjbassi/ytop)
|
||||
* [zenith](https://github.com/bvaisvil/zenith)
|
||||
* [bottom](https://github.com/ClementTsang/bottom)
|
||||
* [oha](https://github.com/hatoo/oha)
|
||||
* [gitui](https://github.com/extrawurst/gitui)
|
||||
* [rust-sadari-cli](https://github.com/24seconds/rust-sadari-cli)
|
||||
* [desed](https://github.com/SoptikHa2/desed)
|
||||
* [diskonaut](https://github.com/imsnif/diskonaut)
|
||||
* [tickrs](https://github.com/tarkah/tickrs)
|
||||
* [rusty-krab-manager](https://github.com/aryakaul/rusty-krab-manager)
|
||||
* [termchat](https://github.com/lemunozm/termchat)
|
||||
* [taskwarrior-tui](https://github.com/kdheepak/taskwarrior-tui)
|
||||
* [gping](https://github.com/orf/gping/)
|
||||
* [Vector](https://vector.dev)
|
||||
* [KDash](https://github.com/kdash-rs/kdash)
|
||||
* [xplr](https://github.com/sayanarijit/xplr)
|
||||
* [minesweep](https://github.com/cpcloud/minesweep-rs)
|
||||
* [Battleship.rs](https://github.com/deepu105/battleship-rs)
|
||||
* [termscp](https://github.com/veeso/termscp)
|
||||
* [joshuto](https://github.com/kamiyaa/joshuto)
|
||||
* [adsb_deku/radar](https://github.com/wcampbell0x2a/adsb_deku#radar-tui)
|
||||
* [hoard](https://github.com/Hyde46/hoard)
|
||||
* [tokio-console](https://github.com/tokio-rs/console): a diagnostics and debugging tool for asynchronous Rust programs.
|
||||
* [hwatch](https://github.com/blacknon/hwatch): a alternative watch command that records the result of command execution and can display its history and diffs.
|
||||
* [ytui-music](https://github.com/sudipghimire533/ytui-music): listen to music from youtube inside your terminal.
|
||||
* [mqttui](https://github.com/EdJoPaTo/mqttui): subscribe or publish to a MQTT Topic quickly from the terminal.
|
||||
* [meteo-tui](https://github.com/16arpi/meteo-tui): french weather via the command line.
|
||||
* [picterm](https://github.com/ksk001100/picterm): preview images in your terminal.
|
||||
* [gobang](https://github.com/TaKO8Ki/gobang): a cross-platform TUI database management tool.
|
||||
Check out the list of [close to 40 apps](./APPS.md) using `ratatui`!
|
||||
|
||||
### Alternatives
|
||||
# Alternatives
|
||||
|
||||
You might want to checkout [Cursive](https://github.com/gyscos/Cursive) for an
|
||||
alternative solution to build text user interfaces in Rust.
|
||||
|
||||
## License
|
||||
# License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
10
RELEASE.md
Normal file
10
RELEASE.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Creating a Release
|
||||
|
||||
[crates.io](https://crates.io/crates/ratatui) releases are automated via [GitHub actions](.github/workflows/cd.yml) and triggered by pushing a tag.
|
||||
|
||||
1. Bump the version in [Cargo.toml](Cargo.toml).
|
||||
2. Ensure [CHANGELOG.md](CHANGELOG.md) is updated. [git-cliff](https://github.com/orhun/git-cliff) can be used for generating the entries.
|
||||
3. Commit and push the changes.
|
||||
4. Create a new tag: `git tag -a v[X.Y.Z]`
|
||||
5. Push the tag: `git push --tags`
|
||||
6. Wait for [Continuous Deployment](https://github.com/tui-rs-revival/ratatui/actions) workflow to finish.
|
||||
85
cliff.toml
Normal file
85
cliff.toml
Normal file
@@ -0,0 +1,85 @@
|
||||
# configuration file for git-cliff
|
||||
# see https://github.com/orhun/git-cliff#configuration-file
|
||||
|
||||
[changelog]
|
||||
# changelog header
|
||||
header = """
|
||||
# Changelog\n
|
||||
All notable changes to this project will be documented in this file.\n
|
||||
"""
|
||||
# template for the changelog body
|
||||
# https://tera.netlify.app/docs/#introduction
|
||||
body = """
|
||||
{% if version %}\
|
||||
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
|
||||
{% else %}\
|
||||
## [unreleased]
|
||||
{% endif %}\
|
||||
{% for group, commits in commits | group_by(attribute="group") %}
|
||||
### {{ group | striptags | trim | upper_first }}
|
||||
{% for commit in commits
|
||||
| filter(attribute="scope")
|
||||
| sort(attribute="scope") %}
|
||||
- *({{commit.scope}})* {{ commit.message | upper_first }}{% if commit.breaking %} [**breaking**]{% endif %}
|
||||
{%- endfor -%}
|
||||
{% raw %}\n{% endraw %}\
|
||||
{%- for commit in commits %}
|
||||
{%- if commit.scope -%}
|
||||
{% else -%}
|
||||
- *(uncategorized)* {{ commit.message | upper_first }}{% if commit.breaking %} [**breaking**]{% endif %}
|
||||
{% endif -%}
|
||||
{% endfor -%}
|
||||
{% endfor %}\n
|
||||
"""
|
||||
# remove the leading and trailing whitespace from the template
|
||||
trim = true
|
||||
# changelog footer
|
||||
footer = """
|
||||
<!-- generated by git-cliff -->
|
||||
"""
|
||||
|
||||
[git]
|
||||
# parse the commits based on https://www.conventionalcommits.org
|
||||
conventional_commits = true
|
||||
# filter out the commits that are not conventional
|
||||
filter_unconventional = true
|
||||
# process each line of a commit as an individual commit
|
||||
split_commits = false
|
||||
# regex for preprocessing the commit messages
|
||||
commit_preprocessors = [
|
||||
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/tui-rs-revival/ratatui/issues/${2}))"},
|
||||
{ pattern = '(better safe shared layout cache)', replace = "perf(layout): ${1}" },
|
||||
{ pattern = '(Clarify README.md)', replace = "docs(readme): ${1}" },
|
||||
{ pattern = '(Update README.md)', replace = "docs(readme): ${1}" },
|
||||
{ pattern = '(fix typos|Fix typos)', replace = "fix: ${1}" }
|
||||
]
|
||||
# regex for parsing and grouping commits
|
||||
commit_parsers = [
|
||||
{ message = "^feat", group = "<!-- 0 -->Features"},
|
||||
{ message = "^fix", group = "<!-- 1 -->Bug Fixes"},
|
||||
{ message = "^Fix", group = "<!-- 1 -->Bug Fixes"},
|
||||
{ message = "^doc", group = "<!-- 3 -->Documentation"},
|
||||
{ message = "^perf", group = "<!-- 4 -->Performance"},
|
||||
{ message = "^refactor", group = "<!-- 2 -->Refactor"},
|
||||
{ message = "^style", group = "<!-- 5 -->Styling"},
|
||||
{ message = "^test", group = "<!-- 6 -->Testing"},
|
||||
{ message = "^chore\\(release\\): prepare for", skip = true},
|
||||
{ message = "^chore\\(pr\\)", skip = true},
|
||||
{ message = "^chore\\(pull\\)", skip = true},
|
||||
{ message = "^chore", group = "<!-- 7 -->Miscellaneous Tasks"},
|
||||
{ body = ".*security", group = "<!-- 8 -->Security"},
|
||||
]
|
||||
# protect breaking changes from being skipped due to matching a skipping commit_parser
|
||||
protect_breaking_commits = false
|
||||
# filter out the commits that are not matched by commit parsers
|
||||
filter_commits = false
|
||||
# glob pattern for matching git tags
|
||||
tag_pattern = "v[0-9]*"
|
||||
# regex for skipping tags
|
||||
skip_tags = "v0.1.0-rc.1"
|
||||
# regex for ignoring tags
|
||||
ignore_tags = ""
|
||||
# sort the tags topologically
|
||||
topo_order = false
|
||||
# sort the commits inside sections by oldest/newest order
|
||||
sort_commits = "newest"
|
||||
16
committed.toml
Normal file
16
committed.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
# configuration for https://github.com/crate-ci/committed
|
||||
|
||||
# https://www.conventionalcommits.org
|
||||
style="conventional"
|
||||
# disallow merge commits
|
||||
merge_commit = false
|
||||
# subject is not required to be capitalized
|
||||
subject_capitalized = false
|
||||
# subject should start with an imperative verb
|
||||
imperative_subject = true
|
||||
# subject should not end with a punctuation
|
||||
subject_not_punctuated = true
|
||||
# disable line length
|
||||
line_length = 0
|
||||
# disable subject length
|
||||
subject_length = 0
|
||||
@@ -3,18 +3,18 @@ use crossterm::{
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Constraint, Direction, Layout},
|
||||
style::{Color, Modifier, Style},
|
||||
widgets::{BarChart, Block, Borders},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
struct App<'a> {
|
||||
data: Vec<(&'a str, u64)>,
|
||||
|
||||
@@ -3,8 +3,7 @@ use crossterm::{
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Alignment, Constraint, Direction, Layout},
|
||||
style::{Color, Modifier, Style},
|
||||
@@ -12,6 +11,7 @@ use tui::{
|
||||
widgets::{Block, BorderType, Borders},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// setup terminal
|
||||
|
||||
@@ -3,12 +3,7 @@ use crossterm::{
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
style::{Color, Style},
|
||||
@@ -19,6 +14,11 @@ use tui::{
|
||||
},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
struct App {
|
||||
x: f64,
|
||||
|
||||
@@ -3,12 +3,7 @@ use crossterm::{
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Constraint, Direction, Layout},
|
||||
style::{Color, Modifier, Style},
|
||||
@@ -17,6 +12,11 @@ use tui::{
|
||||
widgets::{Axis, Block, Borders, Chart, Dataset, GraphType},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
const DATA: [(f64, f64); 5] = [(0.0, 0.0), (1.0, 1.0), (2.0, 2.0), (3.0, 3.0), (4.0, 4.0)];
|
||||
const DATA2: [(f64, f64); 7] = [
|
||||
|
||||
@@ -3,8 +3,7 @@ use crossterm::{
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
buffer::Buffer,
|
||||
layout::Rect,
|
||||
@@ -12,6 +11,7 @@ use tui::{
|
||||
widgets::Widget,
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
|
||||
#[derive(Default)]
|
||||
struct Label<'a> {
|
||||
|
||||
@@ -2,7 +2,7 @@ use rand::{
|
||||
distributions::{Distribution, Uniform},
|
||||
rngs::ThreadRng,
|
||||
};
|
||||
use tui::widgets::ListState;
|
||||
use ratatui::widgets::ListState;
|
||||
|
||||
const TASKS: [&str; 24] = [
|
||||
"Item1", "Item2", "Item3", "Item4", "Item5", "Item6", "Item7", "Item8", "Item9", "Item10",
|
||||
|
||||
@@ -4,15 +4,15 @@ use crossterm::{
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
Terminal,
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
Terminal,
|
||||
};
|
||||
|
||||
pub fn run(tick_rate: Duration, enhanced_graphics: bool) -> Result<(), Box<dyn Error>> {
|
||||
// setup terminal
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
use crate::{app::App, ui};
|
||||
use ratatui::{
|
||||
backend::{Backend, TermionBackend},
|
||||
Terminal,
|
||||
};
|
||||
use std::{error::Error, io, sync::mpsc, thread, time::Duration};
|
||||
use termion::{
|
||||
event::Key,
|
||||
input::{MouseTerminal, TermRead},
|
||||
raw::IntoRawMode,
|
||||
screen::AlternateScreen,
|
||||
};
|
||||
use tui::{
|
||||
backend::{Backend, TermionBackend},
|
||||
Terminal,
|
||||
screen::IntoAlternateScreen,
|
||||
};
|
||||
|
||||
pub fn run(tick_rate: Duration, enhanced_graphics: bool) -> Result<(), Box<dyn Error>> {
|
||||
// setup terminal
|
||||
let stdout = io::stdout().into_raw_mode()?;
|
||||
let stdout = io::stdout()
|
||||
.into_raw_mode()
|
||||
.unwrap()
|
||||
.into_alternate_screen()
|
||||
.unwrap();
|
||||
let stdout = MouseTerminal::from(stdout);
|
||||
let stdout = AlternateScreen::from(stdout);
|
||||
let backend = TermionBackend::new(stdout);
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::app::App;
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::Backend,
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
style::{Color, Modifier, Style},
|
||||
|
||||
@@ -3,12 +3,7 @@ use crossterm::{
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Constraint, Direction, Layout},
|
||||
style::{Color, Modifier, Style},
|
||||
@@ -16,6 +11,11 @@ use tui::{
|
||||
widgets::{Block, Borders, Gauge},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
struct App {
|
||||
progress1: u16,
|
||||
|
||||
@@ -3,13 +3,13 @@ use crossterm::{
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Constraint, Direction, Layout},
|
||||
widgets::{Block, Borders},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// setup terminal
|
||||
|
||||
@@ -3,12 +3,7 @@ use crossterm::{
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Constraint, Corner, Direction, Layout},
|
||||
style::{Color, Modifier, Style},
|
||||
@@ -16,6 +11,11 @@ use tui::{
|
||||
widgets::{Block, Borders, List, ListItem, ListState},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
struct StatefulList<T> {
|
||||
state: ListState,
|
||||
|
||||
@@ -24,11 +24,11 @@ use crossterm::event::{self, Event, KeyCode};
|
||||
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
|
||||
use crossterm::terminal::{EnterAlternateScreen, LeaveAlternateScreen};
|
||||
|
||||
use tui::backend::{Backend, CrosstermBackend};
|
||||
use tui::layout::Alignment;
|
||||
use tui::text::Spans;
|
||||
use tui::widgets::{Block, Borders, Paragraph};
|
||||
use tui::{Frame, Terminal};
|
||||
use ratatui::backend::{Backend, CrosstermBackend};
|
||||
use ratatui::layout::Alignment;
|
||||
use ratatui::text::Spans;
|
||||
use ratatui::widgets::{Block, Borders, Paragraph};
|
||||
use ratatui::{Frame, Terminal};
|
||||
|
||||
type Result<T> = std::result::Result<T, Box<dyn Error>>;
|
||||
|
||||
@@ -59,7 +59,7 @@ fn main() -> Result<()> {
|
||||
reset_terminal()?;
|
||||
|
||||
if let Err(err) = res {
|
||||
println!("{:?}", err);
|
||||
println!("{err:?}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -127,7 +127,7 @@ fn ui<B: Backend>(f: &mut Frame<B>, app: &App) {
|
||||
Spans::from("with the `reset` command"),
|
||||
Spans::from(""),
|
||||
Spans::from("with the chained panic hook enabled,"),
|
||||
Spans::from("you should see the panic report as you would without tui"),
|
||||
Spans::from("you should see the panic report as you would without ratatui"),
|
||||
Spans::from(""),
|
||||
Spans::from("try first without the panic handler to see the difference"),
|
||||
];
|
||||
|
||||
@@ -3,12 +3,7 @@ use crossterm::{
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Alignment, Constraint, Direction, Layout},
|
||||
style::{Color, Modifier, Style},
|
||||
@@ -16,6 +11,11 @@ use tui::{
|
||||
widgets::{Block, Borders, Paragraph, Wrap},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
struct App {
|
||||
scroll: u16,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use std::{error::Error, io};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Alignment, Constraint, Direction, Layout, Rect},
|
||||
style::{Color, Modifier, Style},
|
||||
@@ -7,6 +6,7 @@ use tui::{
|
||||
widgets::{Block, Borders, Clear, Paragraph, Wrap},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
|
||||
use crossterm::{
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
|
||||
|
||||
@@ -7,18 +7,18 @@ use rand::{
|
||||
distributions::{Distribution, Uniform},
|
||||
rngs::ThreadRng,
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Constraint, Direction, Layout},
|
||||
style::{Color, Style},
|
||||
widgets::{Block, Borders, Sparkline},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RandomSignal {
|
||||
|
||||
@@ -3,14 +3,14 @@ use crossterm::{
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Constraint, Layout},
|
||||
style::{Color, Modifier, Style},
|
||||
widgets::{Block, Borders, Cell, Row, Table, TableState},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
|
||||
struct App<'a> {
|
||||
state: TableState,
|
||||
|
||||
@@ -3,8 +3,7 @@ use crossterm::{
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Constraint, Direction, Layout},
|
||||
style::{Color, Modifier, Style},
|
||||
@@ -12,6 +11,7 @@ use tui::{
|
||||
widgets::{Block, Borders, Tabs},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
|
||||
struct App<'a> {
|
||||
pub titles: Vec<&'a str>,
|
||||
|
||||
@@ -10,12 +10,11 @@
|
||||
/// * Pressing Enter pushes the current input in the history of previous
|
||||
/// messages
|
||||
use crossterm::{
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind},
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, CrosstermBackend},
|
||||
layout::{Constraint, Direction, Layout},
|
||||
style::{Color, Modifier, Style},
|
||||
@@ -23,6 +22,7 @@ use tui::{
|
||||
widgets::{Block, Borders, List, ListItem, Paragraph},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{error::Error, io};
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
enum InputMode {
|
||||
@@ -93,7 +93,7 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<(
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
InputMode::Editing => match key.code {
|
||||
InputMode::Editing if key.kind == KeyEventKind::Press => match key.code {
|
||||
KeyCode::Enter => {
|
||||
app.messages.push(app.input.drain(..).collect());
|
||||
}
|
||||
@@ -108,6 +108,7 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<(
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,7 +168,7 @@ fn ui<B: Backend>(f: &mut Frame<B>, app: &App) {
|
||||
{}
|
||||
|
||||
InputMode::Editing => {
|
||||
// Make the cursor visible and ask tui-rs to put it at the specified coordinates after rendering
|
||||
// Make the cursor visible and ask ratatui to put it at the specified coordinates after rendering
|
||||
f.set_cursor(
|
||||
// Put cursor past the end of the input text
|
||||
chunks[1].x + app.input.width() as u16 + 1,
|
||||
|
||||
@@ -8,7 +8,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
/// A buffer cell
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Cell {
|
||||
pub symbol: String,
|
||||
pub fg: Color,
|
||||
@@ -88,9 +88,9 @@ impl Default for Cell {
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// use tui::buffer::{Buffer, Cell};
|
||||
/// use tui::layout::Rect;
|
||||
/// use tui::style::{Color, Style, Modifier};
|
||||
/// use ratatui::buffer::{Buffer, Cell};
|
||||
/// use ratatui::layout::Rect;
|
||||
/// use ratatui::style::{Color, Style, Modifier};
|
||||
///
|
||||
/// let mut buf = Buffer::empty(Rect{x: 0, y: 0, width: 10, height: 5});
|
||||
/// buf.get_mut(0, 2).set_symbol("x");
|
||||
@@ -105,7 +105,7 @@ impl Default for Cell {
|
||||
/// buf.get_mut(5, 0).set_char('x');
|
||||
/// assert_eq!(buf.get(5, 0).symbol, "x");
|
||||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct Buffer {
|
||||
/// The area represented by this buffer
|
||||
pub area: Rect,
|
||||
@@ -176,15 +176,15 @@ impl Buffer {
|
||||
&mut self.content[i]
|
||||
}
|
||||
|
||||
/// Returns the index in the Vec<Cell> for the given global (x, y) coordinates.
|
||||
/// Returns the index in the `Vec<Cell>` for the given global (x, y) coordinates.
|
||||
///
|
||||
/// Global coordinates are offset by the Buffer's area offset (`x`/`y`).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::buffer::Buffer;
|
||||
/// # use tui::layout::Rect;
|
||||
/// # use ratatui::buffer::Buffer;
|
||||
/// # use ratatui::layout::Rect;
|
||||
/// let rect = Rect::new(200, 100, 10, 10);
|
||||
/// let buffer = Buffer::empty(rect);
|
||||
/// // Global coordinates to the top corner of this buffer's area
|
||||
@@ -196,8 +196,8 @@ impl Buffer {
|
||||
/// Panics when given an coordinate that is outside of this Buffer's area.
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use tui::buffer::Buffer;
|
||||
/// # use tui::layout::Rect;
|
||||
/// # use ratatui::buffer::Buffer;
|
||||
/// # use ratatui::layout::Rect;
|
||||
/// let rect = Rect::new(200, 100, 10, 10);
|
||||
/// let buffer = Buffer::empty(rect);
|
||||
/// // Top coordinate is outside of the buffer in global coordinate space, as the Buffer's area
|
||||
@@ -225,8 +225,8 @@ impl Buffer {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::buffer::Buffer;
|
||||
/// # use tui::layout::Rect;
|
||||
/// # use ratatui::buffer::Buffer;
|
||||
/// # use ratatui::layout::Rect;
|
||||
/// let rect = Rect::new(200, 100, 10, 10);
|
||||
/// let buffer = Buffer::empty(rect);
|
||||
/// assert_eq!(buffer.pos_of(0), (200, 100));
|
||||
@@ -238,8 +238,8 @@ impl Buffer {
|
||||
/// Panics when given an index that is outside the Buffer's content.
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use tui::buffer::Buffer;
|
||||
/// # use tui::layout::Rect;
|
||||
/// # use ratatui::buffer::Buffer;
|
||||
/// # use ratatui::layout::Rect;
|
||||
/// let rect = Rect::new(0, 0, 10, 10); // 100 cells in total
|
||||
/// let buffer = Buffer::empty(rect);
|
||||
/// // Index 100 is the 101th cell, which lies outside of the area of this Buffer.
|
||||
@@ -289,7 +289,7 @@ impl Buffer {
|
||||
continue;
|
||||
}
|
||||
// `x_offset + width > max_offset` could be integer overflow on 32-bit machines if we
|
||||
// change dimenstions to usize or u32 and someone resizes the terminal to 1x2^32.
|
||||
// change dimensions to usize or u32 and someone resizes the terminal to 1x2^32.
|
||||
if width > max_offset.saturating_sub(x_offset) {
|
||||
break;
|
||||
}
|
||||
@@ -306,7 +306,7 @@ impl Buffer {
|
||||
(x_offset as u16, y)
|
||||
}
|
||||
|
||||
pub fn set_spans<'a>(&mut self, x: u16, y: u16, spans: &Spans<'a>, width: u16) -> (u16, u16) {
|
||||
pub fn set_spans(&mut self, x: u16, y: u16, spans: &Spans<'_>, width: u16) -> (u16, u16) {
|
||||
let mut remaining_width = width;
|
||||
let mut x = x;
|
||||
for span in &spans.0 {
|
||||
@@ -327,7 +327,7 @@ impl Buffer {
|
||||
(x, y)
|
||||
}
|
||||
|
||||
pub fn set_span<'a>(&mut self, x: u16, y: u16, span: &Span<'a>, width: u16) -> (u16, u16) {
|
||||
pub fn set_span(&mut self, x: u16, y: u16, span: &Span<'_>, width: u16) -> (u16, u16) {
|
||||
self.set_stringn(x, y, span.content.as_ref(), width as usize, span.style)
|
||||
}
|
||||
|
||||
@@ -434,9 +434,9 @@ impl Buffer {
|
||||
let width = self.area.width;
|
||||
|
||||
let mut updates: Vec<(u16, u16, &Cell)> = vec![];
|
||||
// Cells invalidated by drawing/replacing preceeding multi-width characters:
|
||||
// Cells invalidated by drawing/replacing preceding multi-width characters:
|
||||
let mut invalidated: usize = 0;
|
||||
// Cells from the current buffer to skip due to preceeding multi-width characters taking their
|
||||
// Cells from the current buffer to skip due to preceding multi-width characters taking their
|
||||
// place (the skipped cells should be blank anyway):
|
||||
let mut to_skip: usize = 0;
|
||||
for (i, (current, previous)) in next_buffer.iter().zip(previous_buffer.iter()).enumerate() {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use std::cell::RefCell;
|
||||
use std::cmp::{max, min};
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
use cassowary::strength::{REQUIRED, WEAK};
|
||||
use cassowary::strength::{MEDIUM, REQUIRED, WEAK};
|
||||
use cassowary::WeightedRelation::*;
|
||||
use cassowary::{Constraint as CassowaryConstraint, Expression, Solver, Variable};
|
||||
|
||||
@@ -51,7 +52,7 @@ pub struct Margin {
|
||||
pub horizontal: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Alignment {
|
||||
Left,
|
||||
Center,
|
||||
@@ -68,8 +69,9 @@ pub struct Layout {
|
||||
expand_to_fill: bool,
|
||||
}
|
||||
|
||||
type Cache = HashMap<(Rect, Layout), Rc<[Rect]>>;
|
||||
thread_local! {
|
||||
static LAYOUT_CACHE: RefCell<HashMap<(Rect, Layout), Vec<Rect>>> = RefCell::new(HashMap::new());
|
||||
static LAYOUT_CACHE: RefCell<Cache> = RefCell::new(HashMap::new());
|
||||
}
|
||||
|
||||
impl Default for Layout {
|
||||
@@ -128,7 +130,7 @@ impl Layout {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use tui::layout::{Rect, Constraint, Direction, Layout};
|
||||
/// # use ratatui::layout::{Rect, Constraint, Direction, Layout};
|
||||
/// let chunks = Layout::default()
|
||||
/// .direction(Direction::Vertical)
|
||||
/// .constraints([Constraint::Length(5), Constraint::Min(0)].as_ref())
|
||||
@@ -139,8 +141,8 @@ impl Layout {
|
||||
/// height: 10,
|
||||
/// });
|
||||
/// assert_eq!(
|
||||
/// chunks,
|
||||
/// vec![
|
||||
/// chunks[..],
|
||||
/// [
|
||||
/// Rect {
|
||||
/// x: 2,
|
||||
/// y: 2,
|
||||
@@ -166,8 +168,8 @@ impl Layout {
|
||||
/// height: 2,
|
||||
/// });
|
||||
/// assert_eq!(
|
||||
/// chunks,
|
||||
/// vec![
|
||||
/// chunks[..],
|
||||
/// [
|
||||
/// Rect {
|
||||
/// x: 0,
|
||||
/// y: 0,
|
||||
@@ -183,7 +185,7 @@ impl Layout {
|
||||
/// ]
|
||||
/// );
|
||||
/// ```
|
||||
pub fn split(&self, area: Rect) -> Vec<Rect> {
|
||||
pub fn split(&self, area: Rect) -> Rc<[Rect]> {
|
||||
// TODO: Maybe use a fixed size cache ?
|
||||
LAYOUT_CACHE.with(|c| {
|
||||
c.borrow_mut()
|
||||
@@ -194,7 +196,7 @@ impl Layout {
|
||||
}
|
||||
}
|
||||
|
||||
fn split(area: Rect, layout: &Layout) -> Vec<Rect> {
|
||||
fn split(area: Rect, layout: &Layout) -> Rc<[Rect]> {
|
||||
let mut solver = Solver::new();
|
||||
let mut vars: HashMap<Variable, (usize, usize)> = HashMap::new();
|
||||
let elements = layout
|
||||
@@ -202,11 +204,13 @@ fn split(area: Rect, layout: &Layout) -> Vec<Rect> {
|
||||
.iter()
|
||||
.map(|_| Element::new())
|
||||
.collect::<Vec<Element>>();
|
||||
let mut results = layout
|
||||
let mut res = layout
|
||||
.constraints
|
||||
.iter()
|
||||
.map(|_| Rect::default())
|
||||
.collect::<Vec<Rect>>();
|
||||
.collect::<Rc<[Rect]>>();
|
||||
|
||||
let mut results = Rc::get_mut(&mut res).expect("newly created Rc should have no shared refs");
|
||||
|
||||
let dest_area = area.inner(&layout.margin);
|
||||
for (i, e) in elements.iter().enumerate() {
|
||||
@@ -248,18 +252,28 @@ fn split(area: Rect, layout: &Layout) -> Vec<Rect> {
|
||||
ccs.push(elements[i].y | EQ(REQUIRED) | f64::from(dest_area.y));
|
||||
ccs.push(elements[i].height | EQ(REQUIRED) | f64::from(dest_area.height));
|
||||
ccs.push(match *size {
|
||||
Constraint::Length(v) => elements[i].width | EQ(WEAK) | f64::from(v),
|
||||
Constraint::Length(v) => elements[i].width | EQ(MEDIUM) | f64::from(v),
|
||||
Constraint::Percentage(v) => {
|
||||
elements[i].width | EQ(WEAK) | (f64::from(v * dest_area.width) / 100.0)
|
||||
elements[i].width | EQ(MEDIUM) | (f64::from(v * dest_area.width) / 100.0)
|
||||
}
|
||||
Constraint::Ratio(n, d) => {
|
||||
elements[i].width
|
||||
| EQ(WEAK)
|
||||
| EQ(MEDIUM)
|
||||
| (f64::from(dest_area.width) * f64::from(n) / f64::from(d))
|
||||
}
|
||||
Constraint::Min(v) => elements[i].width | GE(WEAK) | f64::from(v),
|
||||
Constraint::Max(v) => elements[i].width | LE(WEAK) | f64::from(v),
|
||||
Constraint::Min(v) => elements[i].width | GE(MEDIUM) | f64::from(v),
|
||||
Constraint::Max(v) => elements[i].width | LE(MEDIUM) | f64::from(v),
|
||||
});
|
||||
|
||||
match *size {
|
||||
Constraint::Min(v) => {
|
||||
ccs.push(elements[i].width | EQ(WEAK) | f64::from(v));
|
||||
}
|
||||
Constraint::Max(v) => {
|
||||
ccs.push(elements[i].width | EQ(WEAK) | f64::from(v));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Direction::Vertical => {
|
||||
@@ -270,18 +284,28 @@ fn split(area: Rect, layout: &Layout) -> Vec<Rect> {
|
||||
ccs.push(elements[i].x | EQ(REQUIRED) | f64::from(dest_area.x));
|
||||
ccs.push(elements[i].width | EQ(REQUIRED) | f64::from(dest_area.width));
|
||||
ccs.push(match *size {
|
||||
Constraint::Length(v) => elements[i].height | EQ(WEAK) | f64::from(v),
|
||||
Constraint::Length(v) => elements[i].height | EQ(MEDIUM) | f64::from(v),
|
||||
Constraint::Percentage(v) => {
|
||||
elements[i].height | EQ(WEAK) | (f64::from(v * dest_area.height) / 100.0)
|
||||
elements[i].height | EQ(MEDIUM) | (f64::from(v * dest_area.height) / 100.0)
|
||||
}
|
||||
Constraint::Ratio(n, d) => {
|
||||
elements[i].height
|
||||
| EQ(WEAK)
|
||||
| EQ(MEDIUM)
|
||||
| (f64::from(dest_area.height) * f64::from(n) / f64::from(d))
|
||||
}
|
||||
Constraint::Min(v) => elements[i].height | GE(WEAK) | f64::from(v),
|
||||
Constraint::Max(v) => elements[i].height | LE(WEAK) | f64::from(v),
|
||||
Constraint::Min(v) => elements[i].height | GE(MEDIUM) | f64::from(v),
|
||||
Constraint::Max(v) => elements[i].height | LE(MEDIUM) | f64::from(v),
|
||||
});
|
||||
|
||||
match *size {
|
||||
Constraint::Min(v) => {
|
||||
ccs.push(elements[i].height | EQ(WEAK) | f64::from(v));
|
||||
}
|
||||
Constraint::Max(v) => {
|
||||
ccs.push(elements[i].height | EQ(WEAK) | f64::from(v));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -323,7 +347,7 @@ fn split(area: Rect, layout: &Layout) -> Vec<Rect> {
|
||||
}
|
||||
}
|
||||
}
|
||||
results
|
||||
res
|
||||
}
|
||||
|
||||
/// A container used by the solver inside split
|
||||
@@ -361,7 +385,7 @@ impl Element {
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple rectangle used in the computation of the layout and to give widgets an hint about the
|
||||
/// A simple rectangle used in the computation of the layout and to give widgets a hint about the
|
||||
/// area they are supposed to render to.
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Default)]
|
||||
pub struct Rect {
|
||||
|
||||
23
src/lib.rs
23
src/lib.rs
@@ -1,16 +1,17 @@
|
||||
//! [tui](https://github.com/fdehau/tui-rs) is a library used to build rich
|
||||
//! [ratatui](https://github.com/tui-rs-revival/ratatui) is a library used to build rich
|
||||
//! terminal users interfaces and dashboards.
|
||||
//!
|
||||
//! 
|
||||
//! 
|
||||
//!
|
||||
//! # Get started
|
||||
//!
|
||||
//! ## Adding `tui` as a dependency
|
||||
//! ## Adding `ratatui` as a dependency
|
||||
//!
|
||||
//! Add the following to your `Cargo.toml`:
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! tui = "0.18"
|
||||
//! crossterm = "0.23"
|
||||
//! crossterm = "0.26"
|
||||
//! ratatui = "0.20"
|
||||
//! ```
|
||||
//!
|
||||
//! The crate is using the `crossterm` backend by default that works on most platforms. But if for
|
||||
@@ -20,7 +21,7 @@
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! termion = "1.5"
|
||||
//! tui = { version = "0.18", default-features = false, features = ['termion'] }
|
||||
//! ratatui = { version = "0.20", default-features = false, features = ['termion'] }
|
||||
//!
|
||||
//! ```
|
||||
//!
|
||||
@@ -28,13 +29,13 @@
|
||||
//!
|
||||
//! ## Creating a `Terminal`
|
||||
//!
|
||||
//! Every application using `tui` should start by instantiating a `Terminal`. It is a light
|
||||
//! Every application using `ratatui` should start by instantiating a `Terminal`. It is a light
|
||||
//! abstraction over available backends that provides basic functionalities such as clearing the
|
||||
//! screen, hiding the cursor, etc.
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! use std::io;
|
||||
//! use tui::{backend::CrosstermBackend, Terminal};
|
||||
//! use ratatui::{backend::CrosstermBackend, Terminal};
|
||||
//!
|
||||
//! fn main() -> Result<(), io::Error> {
|
||||
//! let stdout = io::stdout();
|
||||
@@ -49,7 +50,7 @@
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! use std::io;
|
||||
//! use tui::{backend::TermionBackend, Terminal};
|
||||
//! use ratatui::{backend::TermionBackend, Terminal};
|
||||
//! use termion::raw::IntoRawMode;
|
||||
//!
|
||||
//! fn main() -> Result<(), io::Error> {
|
||||
@@ -77,7 +78,7 @@
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! use std::{io, thread, time::Duration};
|
||||
//! use tui::{
|
||||
//! use ratatui::{
|
||||
//! backend::CrosstermBackend,
|
||||
//! widgets::{Widget, Block, Borders},
|
||||
//! layout::{Layout, Constraint, Direction},
|
||||
@@ -127,7 +128,7 @@
|
||||
//! full customization. And `Layout` is no exception:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! use tui::{
|
||||
//! use ratatui::{
|
||||
//! backend::Backend,
|
||||
//! layout::{Constraint, Direction, Layout},
|
||||
//! widgets::{Block, Borders},
|
||||
|
||||
59
src/style.rs
59
src/style.rs
@@ -2,7 +2,7 @@
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Color {
|
||||
Reset,
|
||||
@@ -34,7 +34,7 @@ bitflags! {
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::Modifier;
|
||||
/// # use ratatui::style::Modifier;
|
||||
///
|
||||
/// let m = Modifier::BOLD | Modifier::ITALIC;
|
||||
/// ```
|
||||
@@ -55,7 +55,7 @@ bitflags! {
|
||||
/// Style let you control the main characteristics of the displayed elements.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// # use ratatui::style::{Color, Modifier, Style};
|
||||
/// Style::default()
|
||||
/// .fg(Color::Black)
|
||||
/// .bg(Color::Green)
|
||||
@@ -67,9 +67,9 @@ bitflags! {
|
||||
/// just S3.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// # use tui::buffer::Buffer;
|
||||
/// # use tui::layout::Rect;
|
||||
/// # use ratatui::style::{Color, Modifier, Style};
|
||||
/// # use ratatui::buffer::Buffer;
|
||||
/// # use ratatui::layout::Rect;
|
||||
/// let styles = [
|
||||
/// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC),
|
||||
/// Style::default().bg(Color::Red),
|
||||
@@ -94,9 +94,9 @@ bitflags! {
|
||||
/// reset all properties until that point use [`Style::reset`].
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// # use tui::buffer::Buffer;
|
||||
/// # use tui::layout::Rect;
|
||||
/// # use ratatui::style::{Color, Modifier, Style};
|
||||
/// # use ratatui::buffer::Buffer;
|
||||
/// # use ratatui::layout::Rect;
|
||||
/// let styles = [
|
||||
/// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC),
|
||||
/// Style::reset().fg(Color::Yellow),
|
||||
@@ -115,7 +115,7 @@ bitflags! {
|
||||
/// buffer.get(0, 0).style(),
|
||||
/// );
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Style {
|
||||
pub fg: Option<Color>,
|
||||
@@ -151,7 +151,7 @@ impl Style {
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Style};
|
||||
/// # use ratatui::style::{Color, Style};
|
||||
/// let style = Style::default().fg(Color::Blue);
|
||||
/// let diff = Style::default().fg(Color::Red);
|
||||
/// assert_eq!(style.patch(diff), Style::default().fg(Color::Red));
|
||||
@@ -166,7 +166,7 @@ impl Style {
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Style};
|
||||
/// # use ratatui::style::{Color, Style};
|
||||
/// let style = Style::default().bg(Color::Blue);
|
||||
/// let diff = Style::default().bg(Color::Red);
|
||||
/// assert_eq!(style.patch(diff), Style::default().bg(Color::Red));
|
||||
@@ -183,7 +183,7 @@ impl Style {
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// # use ratatui::style::{Color, Modifier, Style};
|
||||
/// let style = Style::default().add_modifier(Modifier::BOLD);
|
||||
/// let diff = Style::default().add_modifier(Modifier::ITALIC);
|
||||
/// let patched = style.patch(diff);
|
||||
@@ -203,7 +203,7 @@ impl Style {
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// # use ratatui::style::{Color, Modifier, Style};
|
||||
/// let style = Style::default().add_modifier(Modifier::BOLD | Modifier::ITALIC);
|
||||
/// let diff = Style::default().remove_modifier(Modifier::ITALIC);
|
||||
/// let patched = style.patch(diff);
|
||||
@@ -221,7 +221,7 @@ impl Style {
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// # use ratatui::style::{Color, Modifier, Style};
|
||||
/// let style_1 = Style::default().fg(Color::Yellow);
|
||||
/// let style_2 = Style::default().bg(Color::Red);
|
||||
/// let combined = style_1.patch(style_2);
|
||||
@@ -278,4 +278,33 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn combine_individual_modifiers() {
|
||||
use crate::{buffer::Buffer, layout::Rect};
|
||||
|
||||
let mods = vec![
|
||||
Modifier::BOLD,
|
||||
Modifier::DIM,
|
||||
Modifier::ITALIC,
|
||||
Modifier::UNDERLINED,
|
||||
Modifier::SLOW_BLINK,
|
||||
Modifier::RAPID_BLINK,
|
||||
Modifier::REVERSED,
|
||||
Modifier::HIDDEN,
|
||||
Modifier::CROSSED_OUT,
|
||||
];
|
||||
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
|
||||
|
||||
for m in &mods {
|
||||
buffer.get_mut(0, 0).set_style(Style::reset());
|
||||
buffer
|
||||
.get_mut(0, 0)
|
||||
.set_style(Style::default().add_modifier(*m));
|
||||
let style = buffer.get(0, 0).style();
|
||||
assert!(style.add_modifier.contains(*m));
|
||||
assert!(!style.sub_modifier.contains(*m));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,10 +83,10 @@ where
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::Terminal;
|
||||
/// # use tui::backend::TestBackend;
|
||||
/// # use tui::layout::Rect;
|
||||
/// # use tui::widgets::Block;
|
||||
/// # use ratatui::Terminal;
|
||||
/// # use ratatui::backend::TestBackend;
|
||||
/// # use ratatui::layout::Rect;
|
||||
/// # use ratatui::widgets::Block;
|
||||
/// # let backend = TestBackend::new(5, 5);
|
||||
/// # let mut terminal = Terminal::new(backend).unwrap();
|
||||
/// let block = Block::default();
|
||||
@@ -109,10 +109,10 @@ where
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::Terminal;
|
||||
/// # use tui::backend::TestBackend;
|
||||
/// # use tui::layout::Rect;
|
||||
/// # use tui::widgets::{List, ListItem, ListState};
|
||||
/// # use ratatui::Terminal;
|
||||
/// # use ratatui::backend::TestBackend;
|
||||
/// # use ratatui::layout::Rect;
|
||||
/// # use ratatui::widgets::{List, ListItem, ListState};
|
||||
/// # let backend = TestBackend::new(5, 5);
|
||||
/// # let mut terminal = Terminal::new(backend).unwrap();
|
||||
/// let mut state = ListState::default();
|
||||
|
||||
64
src/text.rs
64
src/text.rs
@@ -1,7 +1,7 @@
|
||||
//! Primitives for styled text.
|
||||
//!
|
||||
//! A terminal UI is at its root a lot of strings. In order to make it accessible and stylish,
|
||||
//! those strings may be associated to a set of styles. `tui` has three ways to represent them:
|
||||
//! those strings may be associated to a set of styles. `ratatui` has three ways to represent them:
|
||||
//! - A single line string where all graphemes have the same style is represented by a [`Span`].
|
||||
//! - A single line string where each grapheme may have its own style is represented by [`Spans`].
|
||||
//! - A multiple line string where each grapheme may have its own style is represented by a
|
||||
@@ -11,7 +11,7 @@
|
||||
//! is a [`Spans`].
|
||||
//!
|
||||
//! Keep it mind that a lot of widgets will use those types to advertise what kind of string is
|
||||
//! supported for their properties. Moreover, `tui` provides convenient `From` implementations so
|
||||
//! supported for their properties. Moreover, `ratatui` provides convenient `From` implementations so
|
||||
//! that you can start by using simple `String` or `&str` and then promote them to the previous
|
||||
//! primitives when you need additional styling capabilities.
|
||||
//!
|
||||
@@ -19,9 +19,9 @@
|
||||
//! its `title` property (which is a [`Spans`] under the hood):
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use tui::widgets::Block;
|
||||
//! # use tui::text::{Span, Spans};
|
||||
//! # use tui::style::{Color, Style};
|
||||
//! # use ratatui::widgets::Block;
|
||||
//! # use ratatui::text::{Span, Spans};
|
||||
//! # use ratatui::style::{Color, Style};
|
||||
//! // A simple string with no styling.
|
||||
//! // Converted to Spans(vec![
|
||||
//! // Span { content: Cow::Borrowed("My title"), style: Style { .. } }
|
||||
@@ -52,14 +52,14 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
/// A grapheme associated to a style.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct StyledGrapheme<'a> {
|
||||
pub symbol: &'a str,
|
||||
pub style: Style,
|
||||
}
|
||||
|
||||
/// A string where all graphemes have the same style.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Span<'a> {
|
||||
pub content: Cow<'a, str>,
|
||||
pub style: Style,
|
||||
@@ -71,7 +71,7 @@ impl<'a> Span<'a> {
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::text::Span;
|
||||
/// # use ratatui::text::Span;
|
||||
/// Span::raw("My text");
|
||||
/// Span::raw(String::from("My text"));
|
||||
/// ```
|
||||
@@ -90,8 +90,8 @@ impl<'a> Span<'a> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::text::Span;
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// # use ratatui::text::Span;
|
||||
/// # use ratatui::style::{Color, Modifier, Style};
|
||||
/// let style = Style::default().fg(Color::Yellow).add_modifier(Modifier::ITALIC);
|
||||
/// Span::styled("My text", style);
|
||||
/// Span::styled(String::from("My text"), style);
|
||||
@@ -119,8 +119,8 @@ impl<'a> Span<'a> {
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::text::{Span, StyledGrapheme};
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// # use ratatui::text::{Span, StyledGrapheme};
|
||||
/// # use ratatui::style::{Color, Modifier, Style};
|
||||
/// # use std::iter::Iterator;
|
||||
/// let style = Style::default().fg(Color::Yellow);
|
||||
/// let span = Span::styled("Text", style);
|
||||
@@ -194,7 +194,7 @@ impl<'a> From<&'a str> for Span<'a> {
|
||||
}
|
||||
|
||||
/// A string composed of clusters of graphemes, each with their own style.
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, PartialEq, Default, Eq)]
|
||||
pub struct Spans<'a>(pub Vec<Span<'a>>);
|
||||
|
||||
impl<'a> Spans<'a> {
|
||||
@@ -203,8 +203,8 @@ impl<'a> Spans<'a> {
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::text::{Span, Spans};
|
||||
/// # use tui::style::{Color, Style};
|
||||
/// # use ratatui::text::{Span, Spans};
|
||||
/// # use ratatui::style::{Color, Style};
|
||||
/// let spans = Spans::from(vec![
|
||||
/// Span::styled("My", Style::default().fg(Color::Yellow)),
|
||||
/// Span::raw(" text"),
|
||||
@@ -257,8 +257,8 @@ impl<'a> From<Spans<'a>> for String {
|
||||
/// [`core::iter::Extend`] which enables the concatenation of several [`Text`] blocks.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::text::Text;
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// # use ratatui::text::Text;
|
||||
/// # use ratatui::style::{Color, Modifier, Style};
|
||||
/// let style = Style::default().fg(Color::Yellow).add_modifier(Modifier::ITALIC);
|
||||
///
|
||||
/// // An initial two lines of `Text` built from a `&str`
|
||||
@@ -273,7 +273,7 @@ impl<'a> From<Spans<'a>> for String {
|
||||
/// text.extend(Text::styled("Some more lines\nnow with more style!", style));
|
||||
/// assert_eq!(6, text.height());
|
||||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, PartialEq, Default, Eq)]
|
||||
pub struct Text<'a> {
|
||||
pub lines: Vec<Spans<'a>>,
|
||||
}
|
||||
@@ -284,7 +284,7 @@ impl<'a> Text<'a> {
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::text::Text;
|
||||
/// # use ratatui::text::Text;
|
||||
/// Text::raw("The first line\nThe second line");
|
||||
/// Text::raw(String::from("The first line\nThe second line"));
|
||||
/// ```
|
||||
@@ -292,12 +292,14 @@ impl<'a> Text<'a> {
|
||||
where
|
||||
T: Into<Cow<'a, str>>,
|
||||
{
|
||||
Text {
|
||||
lines: match content.into() {
|
||||
Cow::Borrowed(s) => s.lines().map(Spans::from).collect(),
|
||||
Cow::Owned(s) => s.lines().map(|l| Spans::from(l.to_owned())).collect(),
|
||||
},
|
||||
}
|
||||
let lines: Vec<_> = match content.into() {
|
||||
Cow::Borrowed("") => vec![Spans::from("")],
|
||||
Cow::Borrowed(s) => s.lines().map(Spans::from).collect(),
|
||||
Cow::Owned(s) if s.is_empty() => vec![Spans::from("")],
|
||||
Cow::Owned(s) => s.lines().map(|l| Spans::from(l.to_owned())).collect(),
|
||||
};
|
||||
|
||||
Text { lines }
|
||||
}
|
||||
|
||||
/// Create some text (potentially multiple lines) with a style.
|
||||
@@ -305,8 +307,8 @@ impl<'a> Text<'a> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::text::Text;
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// # use ratatui::text::Text;
|
||||
/// # use ratatui::style::{Color, Modifier, Style};
|
||||
/// let style = Style::default().fg(Color::Yellow).add_modifier(Modifier::ITALIC);
|
||||
/// Text::styled("The first line\nThe second line", style);
|
||||
/// Text::styled(String::from("The first line\nThe second line"), style);
|
||||
@@ -325,7 +327,7 @@ impl<'a> Text<'a> {
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use tui::text::Text;
|
||||
/// use ratatui::text::Text;
|
||||
/// let text = Text::from("The first line\nThe second line");
|
||||
/// assert_eq!(15, text.width());
|
||||
/// ```
|
||||
@@ -342,7 +344,7 @@ impl<'a> Text<'a> {
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use tui::text::Text;
|
||||
/// use ratatui::text::Text;
|
||||
/// let text = Text::from("The first line\nThe second line");
|
||||
/// assert_eq!(2, text.height());
|
||||
/// ```
|
||||
@@ -355,8 +357,8 @@ impl<'a> Text<'a> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::text::Text;
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// # use ratatui::text::Text;
|
||||
/// # use ratatui::style::{Color, Modifier, Style};
|
||||
/// let style = Style::default().fg(Color::Yellow).add_modifier(Modifier::ITALIC);
|
||||
/// let mut raw_text = Text::raw("The first line\nThe second line");
|
||||
/// let styled_text = Text::styled(String::from("The first line\nThe second line"), style);
|
||||
|
||||
@@ -13,8 +13,8 @@ use unicode_width::UnicodeWidthStr;
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::widgets::{Block, Borders, BarChart};
|
||||
/// # use tui::style::{Style, Color, Modifier};
|
||||
/// # use ratatui::widgets::{Block, Borders, BarChart};
|
||||
/// # use ratatui::style::{Style, Color, Modifier};
|
||||
/// BarChart::default()
|
||||
/// .block(Block::default().title("BarChart").borders(Borders::ALL))
|
||||
/// .bar_width(3)
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::{
|
||||
widgets::{Borders, Widget},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum BorderType {
|
||||
Plain,
|
||||
Rounded,
|
||||
@@ -32,8 +32,8 @@ impl BorderType {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::widgets::{Block, BorderType, Borders};
|
||||
/// # use tui::style::{Style, Color};
|
||||
/// # use ratatui::widgets::{Block, BorderType, Borders};
|
||||
/// # use ratatui::style::{Style, Color};
|
||||
/// Block::default()
|
||||
/// .title("Block")
|
||||
/// .borders(Borders::LEFT | Borders::RIGHT)
|
||||
@@ -41,7 +41,7 @@ impl BorderType {
|
||||
/// .border_type(BorderType::Rounded)
|
||||
/// .style(Style::default().bg(Color::Black));
|
||||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Block<'a> {
|
||||
/// Optional title place on the upper left of the block
|
||||
title: Option<Spans<'a>>,
|
||||
|
||||
@@ -183,7 +183,7 @@ impl<'a, 'b> Painter<'a, 'b> {
|
||||
///
|
||||
/// # Examples:
|
||||
/// ```
|
||||
/// use tui::{symbols, widgets::canvas::{Painter, Context}};
|
||||
/// use ratatui::{symbols, widgets::canvas::{Painter, Context}};
|
||||
///
|
||||
/// let mut ctx = Context::new(2, 2, [1.0, 2.0], [0.0, 2.0], symbols::Marker::Braille);
|
||||
/// let mut painter = Painter::from(&mut ctx);
|
||||
@@ -220,7 +220,7 @@ impl<'a, 'b> Painter<'a, 'b> {
|
||||
///
|
||||
/// # Examples:
|
||||
/// ```
|
||||
/// use tui::{style::Color, symbols, widgets::canvas::{Painter, Context}};
|
||||
/// use ratatui::{style::Color, symbols, widgets::canvas::{Painter, Context}};
|
||||
///
|
||||
/// let mut ctx = Context::new(1, 1, [0.0, 2.0], [0.0, 2.0], symbols::Marker::Braille);
|
||||
/// let mut painter = Painter::from(&mut ctx);
|
||||
@@ -317,10 +317,10 @@ impl<'a> Context<'a> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::widgets::{Block, Borders};
|
||||
/// # use tui::layout::Rect;
|
||||
/// # use tui::widgets::canvas::{Canvas, Shape, Line, Rectangle, Map, MapResolution};
|
||||
/// # use tui::style::Color;
|
||||
/// # use ratatui::widgets::{Block, Borders};
|
||||
/// # use ratatui::layout::Rect;
|
||||
/// # use ratatui::widgets::canvas::{Canvas, Shape, Line, Rectangle, Map, MapResolution};
|
||||
/// # use ratatui::style::Color;
|
||||
/// Canvas::default()
|
||||
/// .block(Block::default().title("Canvas").borders(Borders::ALL))
|
||||
/// .x_bounds([-180.0, 180.0])
|
||||
@@ -384,11 +384,18 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
/// Define the viewport of the canvas.
|
||||
/// If you were to "zoom" to a certain part of the world you may want to choose different
|
||||
/// bounds.
|
||||
pub fn x_bounds(mut self, bounds: [f64; 2]) -> Canvas<'a, F> {
|
||||
self.x_bounds = bounds;
|
||||
self
|
||||
}
|
||||
|
||||
/// Define the viewport of the canvas.
|
||||
///
|
||||
/// If you were to "zoom" to a certain part of the world you may want to choose different
|
||||
/// bounds.
|
||||
pub fn y_bounds(mut self, bounds: [f64; 2]) -> Canvas<'a, F> {
|
||||
self.y_bounds = bounds;
|
||||
self
|
||||
@@ -412,8 +419,8 @@ where
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::widgets::canvas::Canvas;
|
||||
/// # use tui::symbols;
|
||||
/// # use ratatui::widgets::canvas::Canvas;
|
||||
/// # use ratatui::symbols;
|
||||
/// Canvas::default().marker(symbols::Marker::Braille).paint(|ctx| {});
|
||||
///
|
||||
/// Canvas::default().marker(symbols::Marker::Dot).paint(|ctx| {});
|
||||
@@ -461,7 +468,7 @@ where
|
||||
painter(&mut ctx);
|
||||
ctx.finish();
|
||||
|
||||
// Retreive painted points for each layer
|
||||
// Retrieve painted points for each layer
|
||||
for layer in ctx.layers {
|
||||
for (i, (ch, color)) in layer
|
||||
.string
|
||||
|
||||
@@ -181,10 +181,10 @@ struct ChartLayout {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::symbols;
|
||||
/// # use tui::widgets::{Block, Borders, Chart, Axis, Dataset, GraphType};
|
||||
/// # use tui::style::{Style, Color};
|
||||
/// # use tui::text::Span;
|
||||
/// # use ratatui::symbols;
|
||||
/// # use ratatui::widgets::{Block, Borders, Chart, Axis, Dataset, GraphType};
|
||||
/// # use ratatui::style::{Style, Color};
|
||||
/// # use ratatui::text::Span;
|
||||
/// let datasets = vec![
|
||||
/// Dataset::default()
|
||||
/// .name("data1")
|
||||
@@ -265,8 +265,8 @@ impl<'a> Chart<'a> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::widgets::Chart;
|
||||
/// # use tui::layout::Constraint;
|
||||
/// # use ratatui::widgets::Chart;
|
||||
/// # use ratatui::layout::Constraint;
|
||||
/// let constraints = (
|
||||
/// Constraint::Ratio(1, 3),
|
||||
/// Constraint::Ratio(1, 4)
|
||||
|
||||
@@ -2,16 +2,16 @@ use crate::{buffer::Buffer, layout::Rect, widgets::Widget};
|
||||
|
||||
/// A widget to clear/reset a certain area to allow overdrawing (e.g. for popups).
|
||||
///
|
||||
/// This widget **cannot be used to clear the terminal on the first render** as `tui` assumes the
|
||||
/// This widget **cannot be used to clear the terminal on the first render** as `ratatui` assumes the
|
||||
/// render area is empty. Use [`crate::Terminal::clear`] instead.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::widgets::{Clear, Block, Borders};
|
||||
/// # use tui::layout::Rect;
|
||||
/// # use tui::Frame;
|
||||
/// # use tui::backend::Backend;
|
||||
/// # use ratatui::widgets::{Clear, Block, Borders};
|
||||
/// # use ratatui::layout::Rect;
|
||||
/// # use ratatui::Frame;
|
||||
/// # use ratatui::backend::Backend;
|
||||
/// fn draw_on_clear<B: Backend>(f: &mut Frame<B>, area: Rect) {
|
||||
/// let block = Block::default().title("Block").borders(Borders::ALL);
|
||||
/// f.render_widget(Clear, area); // <- this will clear/reset the area first
|
||||
|
||||
@@ -12,8 +12,8 @@ use crate::{
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::widgets::{Widget, Gauge, Block, Borders};
|
||||
/// # use tui::style::{Style, Color, Modifier};
|
||||
/// # use ratatui::widgets::{Widget, Gauge, Block, Borders};
|
||||
/// # use ratatui::style::{Style, Color, Modifier};
|
||||
/// Gauge::default()
|
||||
/// .block(Block::default().borders(Borders::ALL).title("Progress"))
|
||||
/// .gauge_style(Style::default().fg(Color::White).bg(Color::Black).add_modifier(Modifier::ITALIC))
|
||||
@@ -163,9 +163,9 @@ fn get_unicode_block<'a>(frac: f64) -> &'a str {
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::widgets::{Widget, LineGauge, Block, Borders};
|
||||
/// # use tui::style::{Style, Color, Modifier};
|
||||
/// # use tui::symbols;
|
||||
/// # use ratatui::widgets::{Widget, LineGauge, Block, Borders};
|
||||
/// # use ratatui::style::{Style, Color, Modifier};
|
||||
/// # use ratatui::symbols;
|
||||
/// LineGauge::default()
|
||||
/// .block(Block::default().borders(Borders::ALL).title("Progress"))
|
||||
/// .gauge_style(Style::default().fg(Color::White).bg(Color::Black).add_modifier(Modifier::BOLD))
|
||||
|
||||
@@ -26,7 +26,7 @@ impl ListState {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ListItem<'a> {
|
||||
content: Text<'a>,
|
||||
style: Style,
|
||||
@@ -51,6 +51,10 @@ impl<'a> ListItem<'a> {
|
||||
pub fn height(&self) -> usize {
|
||||
self.content.height()
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
self.content.width()
|
||||
}
|
||||
}
|
||||
|
||||
/// A widget to display several items among which one can be selected (optional)
|
||||
@@ -58,8 +62,8 @@ impl<'a> ListItem<'a> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::widgets::{Block, Borders, List, ListItem};
|
||||
/// # use tui::style::{Style, Color, Modifier};
|
||||
/// # use ratatui::widgets::{Block, Borders, List, ListItem};
|
||||
/// # use ratatui::style::{Style, Color, Modifier};
|
||||
/// let items = [ListItem::new("Item 1"), ListItem::new("Item 2"), ListItem::new("Item 3")];
|
||||
/// List::new(items)
|
||||
/// .block(Block::default().title("List").borders(Borders::ALL))
|
||||
@@ -227,7 +231,7 @@ impl<'a> StatefulWidget for List<'a> {
|
||||
|
||||
let is_selected = state.selected.map(|s| s == i).unwrap_or(false);
|
||||
for (j, line) in item.content.lines.iter().enumerate() {
|
||||
// if the item is selected, we need to display the hightlight symbol:
|
||||
// if the item is selected, we need to display the highlight symbol:
|
||||
// - either for the first line of the item only,
|
||||
// - or for each line of the item if the appropriate option is set
|
||||
let symbol = if is_selected && (j == 0 || self.repeat_highlight_symbol) {
|
||||
@@ -243,11 +247,11 @@ impl<'a> StatefulWidget for List<'a> {
|
||||
list_area.width as usize,
|
||||
item_style,
|
||||
);
|
||||
(elem_x, (list_area.width - (elem_x - x)) as u16)
|
||||
(elem_x, (list_area.width - (elem_x - x)))
|
||||
} else {
|
||||
(x, list_area.width)
|
||||
};
|
||||
buf.set_spans(elem_x, y + j as u16, line, max_element_width as u16);
|
||||
buf.set_spans(elem_x, y + j as u16, line, max_element_width);
|
||||
}
|
||||
if is_selected {
|
||||
buf.set_style(area, self.highlight_style);
|
||||
|
||||
@@ -44,17 +44,17 @@ use bitflags::bitflags;
|
||||
|
||||
bitflags! {
|
||||
/// Bitflags that can be composed to set the visible borders essentially on the block widget.
|
||||
pub struct Borders: u32 {
|
||||
pub struct Borders: u8 {
|
||||
/// Show no border (default)
|
||||
const NONE = 0b0000_0001;
|
||||
const NONE = 0b0000;
|
||||
/// Show the top border
|
||||
const TOP = 0b0000_0010;
|
||||
const TOP = 0b0001;
|
||||
/// Show the right border
|
||||
const RIGHT = 0b0000_0100;
|
||||
const RIGHT = 0b0010;
|
||||
/// Show the bottom border
|
||||
const BOTTOM = 0b000_1000;
|
||||
const BOTTOM = 0b0100;
|
||||
/// Show the left border
|
||||
const LEFT = 0b0001_0000;
|
||||
const LEFT = 0b1000;
|
||||
/// Show all borders
|
||||
const ALL = Self::TOP.bits | Self::RIGHT.bits | Self::BOTTOM.bits | Self::LEFT.bits;
|
||||
}
|
||||
@@ -86,9 +86,9 @@ pub trait Widget {
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use std::io;
|
||||
/// # use tui::Terminal;
|
||||
/// # use tui::backend::{Backend, TestBackend};
|
||||
/// # use tui::widgets::{Widget, List, ListItem, ListState};
|
||||
/// # use ratatui::Terminal;
|
||||
/// # use ratatui::backend::{Backend, TestBackend};
|
||||
/// # use ratatui::widgets::{Widget, List, ListItem, ListState};
|
||||
///
|
||||
/// // Let's say we have some events to display.
|
||||
/// struct Events {
|
||||
@@ -165,7 +165,7 @@ pub trait Widget {
|
||||
/// loop {
|
||||
/// terminal.draw(|f| {
|
||||
/// // The items managed by the application are transformed to something
|
||||
/// // that is understood by tui.
|
||||
/// // that is understood by ratatui.
|
||||
/// let items: Vec<ListItem>= events.items.iter().map(|i| ListItem::new(i.as_ref())).collect();
|
||||
/// // The `List` widget is then built with those items.
|
||||
/// let list = List::new(items);
|
||||
|
||||
@@ -24,10 +24,10 @@ fn get_line_offset(line_width: u16, text_area_width: u16, alignment: Alignment)
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::text::{Text, Spans, Span};
|
||||
/// # use tui::widgets::{Block, Borders, Paragraph, Wrap};
|
||||
/// # use tui::style::{Style, Color, Modifier};
|
||||
/// # use tui::layout::{Alignment};
|
||||
/// # use ratatui::text::{Text, Spans, Span};
|
||||
/// # use ratatui::widgets::{Block, Borders, Paragraph, Wrap};
|
||||
/// # use ratatui::style::{Style, Color, Modifier};
|
||||
/// # use ratatui::layout::{Alignment};
|
||||
/// let text = vec![
|
||||
/// Spans::from(vec![
|
||||
/// Span::raw("First"),
|
||||
@@ -63,8 +63,8 @@ pub struct Paragraph<'a> {
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::widgets::{Paragraph, Wrap};
|
||||
/// # use tui::text::Text;
|
||||
/// # use ratatui::widgets::{Paragraph, Wrap};
|
||||
/// # use ratatui::text::Text;
|
||||
/// let bullet_points = Text::from(r#"Some indented points:
|
||||
/// - First thing goes here and is long so that it wraps
|
||||
/// - Here is another point that is long enough to wrap"#);
|
||||
@@ -176,6 +176,10 @@ impl<'a> Widget for Paragraph<'a> {
|
||||
if y >= self.scroll.0 {
|
||||
let mut x = get_line_offset(current_line_width, text_area.width, self.alignment);
|
||||
for StyledGrapheme { symbol, style } in current_line {
|
||||
let width = symbol.width();
|
||||
if width == 0 {
|
||||
continue;
|
||||
}
|
||||
buf.get_mut(text_area.left() + x, text_area.top() + y - self.scroll.0)
|
||||
.set_symbol(if symbol.is_empty() {
|
||||
// If the symbol is empty, the last char which rendered last time will
|
||||
@@ -185,7 +189,7 @@ impl<'a> Widget for Paragraph<'a> {
|
||||
symbol
|
||||
})
|
||||
.set_style(*style);
|
||||
x += symbol.width() as u16;
|
||||
x += width as u16;
|
||||
}
|
||||
}
|
||||
y += 1;
|
||||
@@ -195,3 +199,16 @@ impl<'a> Widget for Paragraph<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn zero_width_char_at_end_of_line() {
|
||||
let line = "foo\0";
|
||||
let paragraph = Paragraph::new(line);
|
||||
let mut buf = Buffer::with_lines(vec![line]);
|
||||
paragraph.render(*buf.area(), &mut buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ pub struct LineTruncator<'a, 'b> {
|
||||
symbols: &'b mut dyn Iterator<Item = StyledGrapheme<'a>>,
|
||||
max_line_width: u16,
|
||||
current_line: Vec<StyledGrapheme<'a>>,
|
||||
/// Record the offet to skip render
|
||||
/// Record the offset to skip render
|
||||
horizontal_offset: u16,
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ mod test {
|
||||
assert_eq!(line_truncator, vec![" "]);
|
||||
}
|
||||
|
||||
/// Tests an input starting with a letter, folowed by spaces - some of the behaviour is
|
||||
/// Tests an input starting with a letter, followed by spaces - some of the behaviour is
|
||||
/// incidental.
|
||||
#[test]
|
||||
fn line_composer_char_plus_lots_of_spaces() {
|
||||
|
||||
@@ -12,8 +12,8 @@ use std::cmp::min;
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::widgets::{Block, Borders, Sparkline};
|
||||
/// # use tui::style::{Style, Color};
|
||||
/// # use ratatui::widgets::{Block, Borders, Sparkline};
|
||||
/// # use ratatui::style::{Style, Color};
|
||||
/// Sparkline::default()
|
||||
/// .block(Block::default().title("Sparkline").borders(Borders::ALL))
|
||||
/// .data(&[0, 2, 3, 4, 1, 4, 10])
|
||||
|
||||
@@ -11,9 +11,9 @@ use unicode_width::UnicodeWidthStr;
|
||||
///
|
||||
/// It can be created from anything that can be converted to a [`Text`].
|
||||
/// ```rust
|
||||
/// # use tui::widgets::Cell;
|
||||
/// # use tui::style::{Style, Modifier};
|
||||
/// # use tui::text::{Span, Spans, Text};
|
||||
/// # use ratatui::widgets::Cell;
|
||||
/// # use ratatui::style::{Style, Modifier};
|
||||
/// # use ratatui::text::{Span, Spans, Text};
|
||||
/// # use std::borrow::Cow;
|
||||
/// Cell::from("simple string");
|
||||
///
|
||||
@@ -31,7 +31,7 @@ use unicode_width::UnicodeWidthStr;
|
||||
///
|
||||
/// You can apply a [`Style`] on the entire [`Cell`] using [`Cell::style`] or rely on the styling
|
||||
/// capabilities of [`Text`].
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct Cell<'a> {
|
||||
content: Text<'a>,
|
||||
style: Style,
|
||||
@@ -61,14 +61,14 @@ where
|
||||
///
|
||||
/// A [`Row`] is a collection of cells. It can be created from simple strings:
|
||||
/// ```rust
|
||||
/// # use tui::widgets::Row;
|
||||
/// # use ratatui::widgets::Row;
|
||||
/// Row::new(vec!["Cell1", "Cell2", "Cell3"]);
|
||||
/// ```
|
||||
///
|
||||
/// But if you need a bit more control over individual cells, you can explicity create [`Cell`]s:
|
||||
/// But if you need a bit more control over individual cells, you can explicitly create [`Cell`]s:
|
||||
/// ```rust
|
||||
/// # use tui::widgets::{Row, Cell};
|
||||
/// # use tui::style::{Style, Color};
|
||||
/// # use ratatui::widgets::{Row, Cell};
|
||||
/// # use ratatui::style::{Style, Color};
|
||||
/// Row::new(vec![
|
||||
/// Cell::from("Cell1"),
|
||||
/// Cell::from("Cell2").style(Style::default().fg(Color::Yellow)),
|
||||
@@ -78,7 +78,7 @@ where
|
||||
/// You can also construct a row from any type that can be converted into [`Text`]:
|
||||
/// ```rust
|
||||
/// # use std::borrow::Cow;
|
||||
/// # use tui::widgets::Row;
|
||||
/// # use ratatui::widgets::Row;
|
||||
/// Row::new(vec![
|
||||
/// Cow::Borrowed("hello"),
|
||||
/// Cow::Owned("world".to_uppercase()),
|
||||
@@ -86,7 +86,7 @@ where
|
||||
/// ```
|
||||
///
|
||||
/// By default, a row has a height of 1 but you can change this using [`Row::height`].
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct Row<'a> {
|
||||
cells: Vec<Cell<'a>>,
|
||||
height: u16,
|
||||
@@ -116,7 +116,7 @@ impl<'a> Row<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the [`Style`] of the entire row. This [`Style`] can be overriden by the [`Style`] of a
|
||||
/// Set the [`Style`] of the entire row. This [`Style`] can be overridden by the [`Style`] of a
|
||||
/// any individual [`Cell`] or event by their [`Text`] content.
|
||||
pub fn style(mut self, style: Style) -> Self {
|
||||
self.style = style;
|
||||
@@ -139,10 +139,10 @@ impl<'a> Row<'a> {
|
||||
///
|
||||
/// It is a collection of [`Row`]s, themselves composed of [`Cell`]s:
|
||||
/// ```rust
|
||||
/// # use tui::widgets::{Block, Borders, Table, Row, Cell};
|
||||
/// # use tui::layout::Constraint;
|
||||
/// # use tui::style::{Style, Color, Modifier};
|
||||
/// # use tui::text::{Text, Spans, Span};
|
||||
/// # use ratatui::widgets::{Block, Borders, Table, Row, Cell};
|
||||
/// # use ratatui::layout::Constraint;
|
||||
/// # use ratatui::style::{Style, Color, Modifier};
|
||||
/// # use ratatui::text::{Text, Spans, Span};
|
||||
/// Table::new(vec![
|
||||
/// // Row can be created from simple strings.
|
||||
/// Row::new(vec!["Row11", "Row12", "Row13"]),
|
||||
@@ -186,7 +186,7 @@ impl<'a> Row<'a> {
|
||||
/// // ...and potentially show a symbol in front of the selection.
|
||||
/// .highlight_symbol(">>");
|
||||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Table<'a> {
|
||||
/// A block to wrap the widget in
|
||||
block: Option<Block<'a>>,
|
||||
@@ -280,7 +280,7 @@ impl<'a> Table<'a> {
|
||||
if !self.widths.is_empty() {
|
||||
constraints.pop();
|
||||
}
|
||||
let mut chunks = Layout::default()
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints(constraints)
|
||||
.expand_to_fill(false)
|
||||
@@ -290,8 +290,9 @@ impl<'a> Table<'a> {
|
||||
width: max_width,
|
||||
height: 1,
|
||||
});
|
||||
let mut chunks = &chunks[..];
|
||||
if has_selection {
|
||||
chunks.remove(0);
|
||||
chunks = &chunks[1..];
|
||||
}
|
||||
chunks.iter().step_by(2).map(|c| c.width).collect()
|
||||
}
|
||||
@@ -352,6 +353,13 @@ impl TableState {
|
||||
self.offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a copy of the receiver's scroll offset.
|
||||
///
|
||||
/// This is useful, for example, if you need to "synchronize" the scrolling of a `Table` and a `Paragraph`.
|
||||
pub fn offset(&self) -> usize {
|
||||
self.offset
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> StatefulWidget for Table<'a> {
|
||||
|
||||
@@ -12,10 +12,10 @@ use crate::{
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use tui::widgets::{Block, Borders, Tabs};
|
||||
/// # use tui::style::{Style, Color};
|
||||
/// # use tui::text::{Spans};
|
||||
/// # use tui::symbols::{DOT};
|
||||
/// # use ratatui::widgets::{Block, Borders, Tabs};
|
||||
/// # use ratatui::style::{Style, Color};
|
||||
/// # use ratatui::text::{Spans};
|
||||
/// # use ratatui::symbols::{DOT};
|
||||
/// let titles = ["Tab1", "Tab2", "Tab3", "Tab4"].iter().cloned().map(Spans::from).collect();
|
||||
/// Tabs::new(titles)
|
||||
/// .block(Block::default().title("Tabs").borders(Borders::ALL))
|
||||
|
||||
@@ -6,7 +6,7 @@ fn backend_termion_should_only_write_diffs() -> Result<(), Box<dyn std::error::E
|
||||
let mut bytes = Vec::new();
|
||||
let mut stdout = Cursor::new(&mut bytes);
|
||||
{
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::TermionBackend, layout::Rect, widgets::Paragraph, Terminal, TerminalOptions,
|
||||
Viewport,
|
||||
};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::error::Error;
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::{Backend, TestBackend},
|
||||
layout::Rect,
|
||||
widgets::Paragraph,
|
||||
Terminal,
|
||||
};
|
||||
use std::error::Error;
|
||||
|
||||
#[test]
|
||||
fn terminal_buffer_size_should_be_limited() {
|
||||
@@ -20,15 +20,15 @@ fn terminal_draw_returns_the_completed_frame() -> Result<(), Box<dyn Error>> {
|
||||
let backend = TestBackend::new(10, 10);
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
let frame = terminal.draw(|f| {
|
||||
let paragrah = Paragraph::new("Test");
|
||||
f.render_widget(paragrah, f.size());
|
||||
let paragraph = Paragraph::new("Test");
|
||||
f.render_widget(paragraph, f.size());
|
||||
})?;
|
||||
assert_eq!(frame.buffer.get(0, 0).symbol, "T");
|
||||
assert_eq!(frame.area, Rect::new(0, 0, 10, 10));
|
||||
terminal.backend_mut().resize(8, 8);
|
||||
let frame = terminal.draw(|f| {
|
||||
let paragrah = Paragraph::new("test");
|
||||
f.render_widget(paragrah, f.size());
|
||||
let paragraph = Paragraph::new("test");
|
||||
f.render_widget(paragraph, f.size());
|
||||
})?;
|
||||
assert_eq!(frame.buffer.get(0, 0).symbol, "t");
|
||||
assert_eq!(frame.area, Rect::new(0, 0, 8, 8));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use tui::backend::TestBackend;
|
||||
use tui::buffer::Buffer;
|
||||
use tui::widgets::{BarChart, Block, Borders};
|
||||
use tui::Terminal;
|
||||
use ratatui::backend::TestBackend;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::widgets::{BarChart, Block, Borders};
|
||||
use ratatui::Terminal;
|
||||
|
||||
#[test]
|
||||
fn widgets_barchart_not_full_below_max_value() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::{Alignment, Rect},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
style::{Color, Style},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use tui::layout::Alignment;
|
||||
use tui::{
|
||||
use ratatui::layout::Alignment;
|
||||
use ratatui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::Rect,
|
||||
@@ -469,7 +469,7 @@ fn widgets_chart_can_have_a_legend() {
|
||||
"└──────────────────────────────────────────────────────────┘",
|
||||
]);
|
||||
|
||||
// Set expected backgound color
|
||||
// Set expected background color
|
||||
for row in 0..30 {
|
||||
for col in 0..60 {
|
||||
expected.get_mut(col, row).set_bg(Color::White);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::Rect,
|
||||
@@ -198,3 +198,30 @@ fn widgets_list_should_repeat_highlight_symbol() {
|
||||
}
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widget_list_should_not_ignore_empty_string_items() {
|
||||
let backend = TestBackend::new(6, 4);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let items = vec![
|
||||
ListItem::new("Item 1"),
|
||||
ListItem::new(""),
|
||||
ListItem::new(""),
|
||||
ListItem::new("Item 4"),
|
||||
];
|
||||
|
||||
let list = List::new(items)
|
||||
.style(Style::default())
|
||||
.highlight_style(Style::default());
|
||||
|
||||
f.render_widget(list, f.size());
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let expected = Buffer::with_lines(vec!["Item 1", "", "", "Item 4"]);
|
||||
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::Alignment,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::Constraint,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use tui::{
|
||||
use ratatui::{
|
||||
backend::TestBackend, buffer::Buffer, layout::Rect, symbols, text::Spans, widgets::Tabs,
|
||||
Terminal,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user