Compare commits

...

59 Commits

Author SHA1 Message Date
Arijit Basu
343ec220b4 chore(release): prepare for 0.20.1 (#110) 2023-03-22 23:57:54 +05:30
Josh McKinney
2da4c10384 docs: fixup remaining tui references (#106) 2023-03-22 11:03:45 +05:30
acheronfail
829dfee9e5 Update APPS.md (#108) 2023-03-22 10:57:20 +05:30
UncleScientist
26c7bcfdd5 fix(style): bold needs a bit (#104) 2023-03-20 23:09:27 +05:30
todoesverso
cf1b05d16e docs(apps): add "logss" to apps (#105) 2023-03-20 18:20:22 +01:00
Orhun Parmaksız
cfa8b8042a chore(release): prepare for 0.20.0 (#97) 2023-03-19 18:11:15 +01:00
Orhun Parmaksız
f0c0985708 docs(readme): update crate status badge (#102) 2023-03-19 17:55:48 +01:00
Leon Sautour
73c937bc30 docs(readme): small edits before first release (#101) 2023-03-19 17:49:26 +01:00
Orhun Parmaksız
33e67abbe9 docs(canvas): add documentation for x_bounds, y_bounds (#35)
Co-authored-by: girvel <widauka@ya.ru>
Co-authored-by: Leon Sautour <leon1.sautour@epitech.eu>
Co-authored-by: Arijit Basu <sayanarijit@users.noreply.github.com>
2023-03-19 17:30:23 +01:00
Arijit Basu
c20fb723ef docs(readme): add install instruction and update title (#100) 2023-03-19 16:08:04 +01:00
Orhun Parmaksız
ccd142df97 docs(apps): move 'apps using ratatui' to dedicated file (#98) (#99) 2023-03-19 01:30:47 +01:00
Orhun Parmaksız
f6dbd1c0b5 docs(readme): add systeroid to application list (#92) 2023-03-18 08:11:44 +05:30
Orhun Parmaksız
d38d185d1c feat(cd): add continuous deployment workflow (#93) 2023-03-17 21:19:01 +01:00
Qichao Lan
ef79b72471 docs(readme): add glicol-cli to showcase list (#95) 2023-03-17 21:18:04 +01:00
Orhun Parmaksız
ed12ab16e0 chore(cargo): update project metadata (#94) 2023-03-17 17:03:49 +01:00
Orhun Parmaksız
24820cfcff chore(ci): integrate typos for checking typos (#91) 2023-03-16 15:00:52 +01:00
Kian-Meng Ang
e10f62663e docs: fix typos (#90) 2023-03-16 18:56:50 +05:30
Conrad Ludgate
02573b0ad2 better safe shared layout cache (#62) 2023-03-12 18:23:30 +05:30
Orhun Parmaksız
0dc39434c2 Fix: cassowary/layouts: add extra constraints for fixing Min(v)/Max(v) combination. (#31)
Co-authored-by: Simon Allen <simon@simonallen.org>
2023-03-11 17:11:13 +05:30
Linda_pp
33acfce083 fix(ci): Test MSRV compatibility on CI (#85) 2023-03-08 22:07:19 +05:30
Arijit Basu
79d0eadbd6 docs: update to build more backends (#81)
Co-authored-by: Doug Goldstein <cardoe@cardoe.com>
2023-03-05 13:25:36 +01:00
Orhun Parmaksız
73f7f16298 fix(ci): Bump Rust version to 1.63.0 (#80) 2023-03-02 07:41:06 +01:00
Orhun Parmaksız
66eb0e42fe chore(ci): Change the target branch to main (#79)
Co-authored-by: Leon Sautour <leon@sautour.net>
2023-03-01 11:06:14 +01:00
Orhun Parmaksız
052ae53b6e chore: Integrate committed for checking conventional commits (#77)
Closes #50
2023-02-25 14:36:49 +01:00
Orhun Parmaksız
1c0ed3268b fix(ci): use env for the cargo-make version (#76) 2023-02-22 13:40:04 +01:00
Orhun Parmaksız
0456abb327 fix(widget)!: List should not ignore empty string items (#42)
Fixes issue #680. Handles the case where a list item is created with an empty string, which is not split by the lines iterator.

Co-authored-by: Collin O'Connor <collinoconnor2@gmail.com>
Co-authored-by: Arijit Basu <sayanarijit@users.noreply.github.com>
Co-authored-by: Arijit Basu <sayanarijit@gmail.com>
2023-02-21 13:22:37 +01:00
Jack Wills
ec50458491 docs(readme): Add oxker to application list (#74) 2023-02-21 11:33:52 +01:00
牧心
b834ccaa2f docs(readme): Add app kubectl-watch which uses tui (#73) 2023-02-20 15:35:37 +01:00
Leon Sautour
ffb3de6c36 docs(github): remove pull request template (#68) 2023-02-20 14:32:38 +01:00
Leon Sautour
454c8459f2 docs(contributing): specify the use of unsafe for optimization (#67) 2023-02-20 14:28:49 +01:00
CK Aznable
94a0d09591 docs(readme): add poketex to 'apps using tui' in README (#64) 2023-02-19 12:42:09 +01:00
Orhun Parmaksız
9b7a6ed85d feat(widget): add offset() to TableState (#10)
Co-authored-by: Aaron Rennow <arennow@outlook.com>
2023-02-18 03:11:34 +01:00
Orhun Parmaksız
7e31035114 refactor(style): make bitflags smaller (#13)
Co-authored-by: Cédric Barreteau <cbarrete@users.noreply.github.com>
2023-02-18 03:10:40 +01:00
Orhun Parmaksız
e15a6146f8 feat(widget): add width() to ListItem (#17)
Co-authored-by: Nicholas Howard <nicholas.howard@novatechautomation.com>
2023-02-18 03:09:32 +01:00
Linda_pp
e49cb1126b fix(doc): add 3rd party libraries accidentally removed at #21 (#61) 2023-02-17 13:01:16 +01:00
Linda_pp
142bc5720e feat(ci): add MacOS to CI (#60) 2023-02-17 12:59:18 +01:00
Linda_pp
feaeb7870f fix(ci): fix deprecation warnings on CI (#58)
* fix(ci): fix deprecation warnings on CI

* fix(ci): remove unnecessary step in CI workflow
2023-02-17 06:25:51 +05:30
Linda_pp
9df0eefe49 chore(ci): re-enable clippy on CI (#59) 2023-02-16 18:51:54 +05:30
Linda_pp
8e89a9377a chore: update rust-version to 1.59 in Cargo.toml (#57) 2023-02-16 08:38:30 +05:30
Orhun Parmaksız
d3df8fe7ef fix: Fix user_input example double key press registered on windows
Co-authored-by: 朕与将军解战袍 <72246322+a1393323447@users.noreply.github.com>
2023-02-15 22:52:08 +01:00
Arijit Basu
9feda988a5 chore: Update deps (#51)
* Update deps

Also, temporarily disabled clippy check. Can be discussed in #49.

* Fix termion demo

* chore: fix all clippy warnings

* Call into_raw_mode()

* Update min supported rust version

---------

Co-authored-by: rhysd <lin90162@yahoo.co.jp>
2023-02-15 18:29:50 +05:30
Orhun Parmaksız
9534d533e3 fix: Ignore zero-width symbol on rendering Paragraph
This fixes out-of-bounds crash on rendering `Paragraph` when zero-width
character is at end of line.

fix #642

Co-authored-by: rhysd <lin90162@yahoo.co.jp>
2023-02-15 13:56:54 +01:00
Orhun Parmaksız
85eefe1d8b docs: Expand "Apps" and "Third-party" sections (#21)
* README.md/#Apps using tui: Sort lexically

* README.md/#Apps using tui: Remove Hoard.

Closes #569.

* README.md/#Apps using tui: Add a description to each app.

* README.md/#Apps using tui: Add some more apps.

This is a curated addition.

Here are the apps I chose not to add:

```md
* [Chatui](https://github.com/xaerru/chatui) — ChatApp made using the standard library net module and Tui-rs
* [Corona-rs](https://github.com/varjolintu/corona-rs) — Corona virus statistics with Tui-rs
* [HTTP Request Tool](https://github.com/Callum-Irving/http-request-tool) — HTTP request sending tool similar to Insomnia, but uses a text user interface (TUI)
* [KRTirtho/portfolio](https://github.com/KRTirtho/portfolio) — A TUI based personal portfolio created using Rust & Tui-rs
* [Picterm](https://github.com/ksk001100/picterm) — TUI image viewer
```

* README.md/#Third party: add more projects

* Undo the capitalization

---------

Co-authored-by: Nicolas Girard <girard.nicolas@gmail.com>
Co-authored-by: Arijit Basu <sayanarijit@gmail.com>
2023-02-15 13:55:44 +01:00
Orhun Parmaksız
3343270680 docs: add tui-input and update xplr in README.md
Also update xplr description.

Co-authored-by: Arijit Basu <sayanarijit@gmail.com>
2023-02-14 19:13:21 +01:00
Orhun Parmaksız
bf9d502742 Update README.md (#39)
Co-authored-by: 晧暐 <henryliking@gmail.com>
2023-02-14 19:09:25 +01:00
Orhun Parmaksız
85c0779ac0 Update README.md (#40)
Co-authored-by: Tin Chung <56880684+chungquantin@users.noreply.github.com>
Co-authored-by: Arijit Basu <sayanarijit@users.noreply.github.com>
2023-02-14 21:29:11 +05:30
Orhun Parmaksız
070de44069 docs: Add hncli to list of applications made with tui-rs (#41)
Co-authored-by: pierreyoda <pierreyoda@users.noreply.github.com>
2023-02-14 16:54:14 +01:00
Orhun Parmaksız
33087e3a99 Fix typos (#45)
Co-authored-by: Howard Halim <howardhalim@gmail.com>
2023-02-14 10:26:07 +01:00
UncleScientist
fe4eb5e771 fix typos (#47) 2023-02-14 10:23:14 +01:00
Owletti
2fead23556 Clarify README.md fork status update
Clarify README.md
2023-02-14 10:22:07 +01:00
Leon Sautour
bc5a9e4c06 doc: Updated readme and contributing guide with updates about the fork (#46)
* doc: Updated readme and contributing guide with updates about the fork

* doc: added missing discord invite link
2023-02-13 16:10:08 +01:00
davidhelbig
fafad6c961 chore: fix typo in layout.rs (#619) 2022-08-14 15:58:02 +02:00
Florian Dehau
a4de409235 chore: add apps using tui 2022-08-14 15:51:31 +02:00
Florian Dehau
a05fd45959 Release v0.19.0 2022-08-14 15:38:31 +02:00
Florian Dehau
24de2f8a96 chore: bump crossterm to v0.25 2022-08-14 15:19:48 +02:00
Florian Dehau
eee37011a5 chore: fix clippy warnings 2022-08-14 14:59:04 +02:00
Florian Dehau
a67706bea0 chore(ci): bump cargo-make to v0.35.16 2022-08-14 14:43:38 +02:00
Linda_pp
faa69b6cfe chore: explicitly set MSRV to 1.56.1 in Cargo.toml 2022-08-14 14:24:54 +02:00
Florian Dehau
ba5ea2deff chore: update README 2022-08-14 13:58:53 +02:00
61 changed files with 884 additions and 443 deletions

View File

@@ -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.
-->

View File

@@ -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
View 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 }}

View File

@@ -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
View 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) |

View File

@@ -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

View File

@@ -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.

View File

@@ -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
View File

@@ -1,19 +1,42 @@
# tui-rs
# ratatui
[![Build Status](https://github.com/fdehau/tui-rs/workflows/CI/badge.svg)](https://github.com/fdehau/tui-rs/actions?query=workflow%3ACI+)
[![Crate Status](https://img.shields.io/crates/v/tui.svg)](https://crates.io/crates/tui)
[![Docs Status](https://docs.rs/tui/badge.svg)](https://docs.rs/crate/tui/)
An actively maintained `tui`-rs fork.
[![Build Status](https://github.com/tui-rs-revival/ratatui/workflows/CI/badge.svg)](https://github.com/tui-rs-revival/ratatui/actions?query=workflow%3ACI+)
[![Crate Status](https://img.shields.io/crates/v/ratatui.svg)](https://crates.io/crates/ratatui)
[![Docs Status](https://docs.rs/ratatui/badge.svg)](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
View 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
View 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
View 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

View File

@@ -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)>,

View File

@@ -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

View File

@@ -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,

View File

@@ -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] = [

View File

@@ -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> {

View File

@@ -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",

View File

@@ -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

View File

@@ -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)?;

View File

@@ -1,5 +1,5 @@
use crate::app::App;
use tui::{
use ratatui::{
backend::Backend,
layout::{Constraint, Direction, Layout, Rect},
style::{Color, Modifier, Style},

View File

@@ -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,

View File

@@ -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

View File

@@ -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,

View File

@@ -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"),
];

View File

@@ -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,

View File

@@ -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},

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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>,

View File

@@ -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,

View File

@@ -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() {

View File

@@ -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 {

View File

@@ -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.
//!
//! ![](https://raw.githubusercontent.com/fdehau/tui-rs/master/assets/demo.gif)
//! ![](https://raw.githubusercontent.com/tui-rs-revival/ratatui/master/assets/demo.gif)
//!
//! # 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},

View File

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

View File

@@ -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();

View File

@@ -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);

View File

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

View File

@@ -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>>,

View File

@@ -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

View File

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

View File

@@ -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

View File

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

View File

@@ -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);

View File

@@ -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);

View File

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

View File

@@ -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() {

View File

@@ -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])

View File

@@ -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> {

View File

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

View File

@@ -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,
};

View File

@@ -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));

View File

@@ -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() {

View File

@@ -1,4 +1,4 @@
use tui::{
use ratatui::{
backend::TestBackend,
buffer::Buffer,
layout::{Alignment, Rect},

View File

@@ -1,4 +1,4 @@
use tui::{
use ratatui::{
backend::TestBackend,
buffer::Buffer,
style::{Color, Style},

View File

@@ -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);

View File

@@ -1,4 +1,4 @@
use tui::{
use ratatui::{
backend::TestBackend,
buffer::Buffer,
layout::{Constraint, Direction, Layout, Rect},

View File

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

View File

@@ -1,4 +1,4 @@
use tui::{
use ratatui::{
backend::TestBackend,
buffer::Buffer,
layout::Alignment,

View File

@@ -1,4 +1,4 @@
use tui::{
use ratatui::{
backend::TestBackend,
buffer::Buffer,
layout::Constraint,

View File

@@ -1,4 +1,4 @@
use tui::{
use ratatui::{
backend::TestBackend, buffer::Buffer, layout::Rect, symbols, text::Spans, widgets::Tabs,
Terminal,
};