diff options
author | Ellie Huxtable <ellie@elliehuxtable.com> | 2023-03-31 22:57:37 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-31 22:57:37 +0100 |
commit | a515b06bcb556c1be2d0fc3095cd778d413fe40d (patch) | |
tree | 4b544de9aa53d6976177c08b91aa3943ef4d9e92 | |
parent | 3552c7e0d315f3c6d2b4b2043a3fabe7cc762e7a (diff) |
Vendor ratatui temporarily (#835)
* Vendor ratatui temporarily
Once https://github.com/tui-rs-revival/ratatui/pull/114 has been merged,
we can undo this! But otherwise we can't publish to crates.io with a git
dependency.
* make tests pass
* Shush.
* these literally just fail in nix, nowhere else
idk how to work with nix properly, and they're also not our tests
41 files changed, 14697 insertions, 21 deletions
@@ -77,6 +77,8 @@ dependencies = [ "atuin-common", "atuin-server", "base64 0.20.0", + "bitflags", + "cassowary", "chrono", "clap", "clap_complete", @@ -93,7 +95,6 @@ dependencies = [ "interim", "itertools", "log", - "ratatui", "rpassword", "runtime-format", "semver", @@ -102,6 +103,7 @@ dependencies = [ "tiny-bip39", "tokio", "tracing-subscriber", + "unicode-segmentation", "unicode-width", "whoami", ] @@ -1584,18 +1586,6 @@ dependencies = [ ] [[package]] -name = "ratatui" -version = "0.20.1" -source = "git+https://github.com/conradludgate/tui-rs-revival?branch=inline#6ed61959ecfc560e4e6a00a1410bb5fcbf0eda91" -dependencies = [ - "bitflags", - "cassowary", - "crossterm", - "unicode-segmentation", - "unicode-width", -] - -[[package]] name = "redox_syscall" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -73,15 +73,16 @@ semver = "1.0.14" runtime-format = "0.1.2" tiny-bip39 = "1" futures-util = "0.3" -ratatui = "0.20.1" fuzzy-matcher = "0.3.7" colored = "2.0.0" +# ratatui +bitflags = "1.3" +cassowary = "0.3" +unicode-segmentation = "1.2" + [dependencies.tracing-subscriber] version = "0.3" default-features = false features = ["ansi", "fmt", "registry", "env-filter"] optional = true - -[patch.crates-io] -ratatui = { git = "https://github.com/conradludgate/tui-rs-revival", branch = "inline" } diff --git a/src/command/client/search/history_list.rs b/src/command/client/search/history_list.rs index 928fe4c7..eedab1a5 100644 --- a/src/command/client/search/history_list.rs +++ b/src/command/client/search/history_list.rs @@ -1,12 +1,12 @@ use std::time::Duration; -use atuin_client::history::History; -use ratatui::{ +use crate::ratatui::{ buffer::Buffer, layout::Rect, style::{Color, Modifier, Style}, widgets::{Block, StatefulWidget, Widget}, }; +use atuin_client::history::History; use super::format_duration; diff --git a/src/command/client/search/interactive.rs b/src/command/client/search/interactive.rs index 5038fc83..a09cfb73 100644 --- a/src/command/client/search/interactive.rs +++ b/src/command/client/search/interactive.rs @@ -23,8 +23,7 @@ use super::{ engines::{SearchEngine, SearchState}, history_list::{HistoryList, ListState, PREFIX_LENGTH}, }; -use crate::{command::client::search::engines, VERSION}; -use ratatui::{ +use crate::ratatui::{ backend::{Backend, CrosstermBackend}, layout::{Alignment, Constraint, Direction, Layout}, style::{Color, Modifier, Style}, @@ -32,6 +31,7 @@ use ratatui::{ widgets::{Block, BorderType, Borders, Paragraph}, Frame, Terminal, TerminalOptions, Viewport, }; +use crate::{command::client::search::engines, VERSION}; const RETURN_ORIGINAL: usize = usize::MAX; const RETURN_QUERY: usize = usize::MAX - 1; diff --git a/src/main.rs b/src/main.rs index 2f81f4fc..9e570337 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,9 @@ use eyre::Result; use command::AtuinCmd; mod command; +#[allow(clippy::all)] +mod ratatui; + const VERSION: &str = env!("CARGO_PKG_VERSION"); static HELP_TEMPLATE: &str = "\ diff --git a/src/ratatui/.github/ISSUE_TEMPLATE/bug_report.md b/src/ratatui/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..0a0f4bc6 --- /dev/null +++ b/src/ratatui/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,60 @@ +--- +name: Bug report +about: Create an issue about a bug you encountered +title: '' +labels: bug +assignees: '' +--- + +<!-- +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. +--> + +## Description +<!-- +A clear and concise description of what the bug is. +--> + + +## To Reproduce +<!-- +Try to reduce the issue to a simple code sample exhibiting the problem. +Ideally, fork the project and add a test or an example. +--> + + +## Expected behavior +<!-- +A clear and concise description of what you expected to happen. +--> + + +## Screenshots +<!-- +If applicable, add screenshots, gifs or videos to help explain your problem. +--> + + +## Environment +<!-- +Add a description of the systems where you are observing the issue. For example: +- OS: Linux +- Terminal Emulator: xterm +- Font: Inconsolata (Patched) +- Crate version: 0.7 +- Backend: termion +--> + +- OS: +- Terminal Emulator: +- Font: +- Crate version: +- Backend: + +## Additional context +<!-- +Add any other context about the problem here. +If you already looked into the issue, include all the leads you have explored. +--> diff --git a/src/ratatui/.github/ISSUE_TEMPLATE/config.yml b/src/ratatui/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..3ba13e0c --- /dev/null +++ b/src/ratatui/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/src/ratatui/.github/ISSUE_TEMPLATE/feature_request.md b/src/ratatui/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..ae095edb --- /dev/null +++ b/src/ratatui/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,32 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +## Problem +<!-- +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] +--> + +## Solution +<!-- +A clear and concise description of what you want to happen. +Things to consider: +- backward compatibility +- ease of use of the API (https://rust-lang.github.io/api-guidelines/) +- consistency with the rest of the crate +--> + +## Alternatives +<!-- +A clear and concise description of any alternative solutions or features you've considered. +--> + +## Additional context +<!-- +Add any other context or screenshots about the feature request here. +--> diff --git a/src/ratatui/.github/workflows/cd.yml b/src/ratatui/.github/workflows/cd.yml new file mode 100644 index 00000000..f61e3603 --- /dev/null +++ b/src/ratatui/.github/workflows/cd.yml @@ -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 }} diff --git a/src/ratatui/.github/workflows/ci.yml b/src/ratatui/.github/workflows/ci.yml new file mode 100644 index 00000000..bfa363e9 --- /dev/null +++ b/src/ratatui/.github/workflows/ci.yml @@ -0,0 +1,76 @@ +on: + push: + branches: + - main + pull_request: + branches: + - main + +name: CI + +env: + CI_CARGO_MAKE_VERSION: 0.35.16 + +jobs: + 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 + steps: + - 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: + ref: ${{ github.event.pull_request.head.sha }} + - name: "Check conventional commits" + uses: crate-ci/committed@master + with: + args: "-vv" + commits: "HEAD" + - name: "Check typos" + uses: crate-ci/typos@master diff --git a/src/ratatui/.gitignore b/src/ratatui/.gitignore new file mode 100644 index 00000000..dcb33fbb --- /dev/null +++ b/src/ratatui/.gitignore @@ -0,0 +1,6 @@ +target +Cargo.lock +*.log +*.rs.rustfmt +.gdb_history +.idea/ diff --git a/src/ratatui/LICENSE b/src/ratatui/LICENSE new file mode 100644 index 00000000..7a0657cb --- /dev/null +++ b/src/ratatui/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Florian Dehau + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/ratatui/README.md b/src/ratatui/README.md new file mode 100644 index 00000000..05d4adb6 --- /dev/null +++ b/src/ratatui/README.md @@ -0,0 +1,136 @@ +# ratatui + +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"> + +# 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) + +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 +supposed to be part of the UI. While providing a great flexibility for rich and +interactive UI, this may introduce overhead for highly dynamic content. So, the +implementation try to minimize the number of ansi escapes sequences generated to +draw the updated UI. In practice, given the speed of `Rust` the overhead rather +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 + +Since version 0.17.0, `ratatui` requires **rustc version 1.59.0 or greater**. + +# Documentation + +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. + +``` +# crossterm +cargo run --example demo --release -- --tick-rate 200 +# termion +cargo run --example demo --no-default-features --features=termion --release -- --tick-rate 200 +``` + +where `tick-rate` is the UI refresh rate in ms. + +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: + +``` +cargo run --example demo --release -- --tick-rate 200 --enhanced-graphics false +``` + +# Widgets + +## Built in + +The library comes with the following list of widgets: + +- [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 +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 libraries, bootstrapping templates and widgets + +- [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 + +Check out the list of [close to 40 apps](./APPS.md) using `ratatui`! + +# Alternatives + +You might want to checkout [Cursive](https://github.com/gyscos/Cursive) for an +alternative solution to build text user interfaces in Rust. + +# License + +[MIT](LICENSE) + diff --git a/src/ratatui/backend/crossterm.rs b/src/ratatui/backend/crossterm.rs new file mode 100644 index 00000000..3dceb6ad --- /dev/null +++ b/src/ratatui/backend/crossterm.rs @@ -0,0 +1,241 @@ +use crate::ratatui::{ + backend::{Backend, ClearType}, + buffer::Cell, + layout::Rect, + style::{Color, Modifier}, +}; +use crossterm::{ + cursor::{Hide, MoveTo, Show}, + execute, queue, + style::{ + Attribute as CAttribute, Color as CColor, Print, SetAttribute, SetBackgroundColor, + SetForegroundColor, + }, + terminal::{self, Clear}, +}; +use std::io::{self, Write}; + +pub struct CrosstermBackend<W: Write> { + buffer: W, +} + +impl<W> CrosstermBackend<W> +where + W: Write, +{ + pub fn new(buffer: W) -> CrosstermBackend<W> { + CrosstermBackend { buffer } + } +} + +impl<W> Write for CrosstermBackend<W> +where + W: Write, +{ + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.buffer.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.buffer.flush() + } +} + +impl<W> Backend for CrosstermBackend<W> +where + W: Write, +{ + fn draw<'a, I>(&mut self, content: I) -> io::Result<()> + where + I: Iterator<Item = (u16, u16, &'a Cell)>, + { + let mut fg = Color::Reset; + let mut bg = Color::Reset; + let mut modifier = Modifier::empty(); + let mut last_pos: Option<(u16, u16)> = None; + for (x, y, cell) in content { + // Move the cursor if the previous location was not (x - 1, y) + if !matches!(last_pos, Some(p) if x == p.0 + 1 && y == p.1) { + map_error(queue!(self.buffer, MoveTo(x, y)))?; + } + last_pos = Some((x, y)); + if cell.modifier != modifier { + let diff = ModifierDiff { + from: modifier, + to: cell.modifier, + }; + diff.queue(&mut self.buffer)?; + modifier = cell.modifier; + } + if cell.fg != fg { + let color = CColor::from(cell.fg); + map_error(queue!(self.buffer, SetForegroundColor(color)))?; + fg = cell.fg; + } + if cell.bg != bg { + let color = CColor::from(cell.bg); + map_error(queue!(self.buffer, SetBackgroundColor(color)))?; + bg = cell.bg; + } + + map_error(queue!(self.buffer, Print(&cell.symbol)))?; + } + + map_error(queue!( + self.buffer, + SetForegroundColor(CColor::Reset), + SetBackgroundColor(CColor::Reset), + SetAttribute(CAttribute::Reset) + )) + } + + fn hide_cursor(&mut self) -> io::Result<()> { + map_error(execute!(self.buffer, Hide)) + } + + fn show_cursor(&mut self) -> io::Result<()> { + map_error(execute!(self.buffer, Show)) + } + + fn get_cursor(&mut self) -> io::Result<(u16, u16)> { + crossterm::cursor::position() + .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string())) + } + + fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> { + map_error(execute!(self.buffer, MoveTo(x, y))) + } + + fn clear(&mut self) -> io::Result<()> { + self.clear_region(ClearType::All) + } + + fn clear_region(&mut self, clear_type: ClearType) -> io::Result<()> { + map_error(execute!( + self.buffer, + Clear(match clear_type { + ClearType::All => crossterm::terminal::ClearType::All, + ClearType::AfterCursor => crossterm::terminal::ClearType::FromCursorDown, + ClearType::BeforeCursor => crossterm::terminal::ClearType::FromCursorUp, + ClearType::CurrentLine => crossterm::terminal::ClearType::CurrentLine, + ClearType::UntilNewLine => crossterm::terminal::ClearType::UntilNewLine, + }) + )) + } + + fn append_lines(&mut self, n: u16) -> io::Result<()> { + for _ in 0..n { + map_error(queue!(self.buffer, Print("\n")))?; + } + self.buffer.flush() + } + + fn size(&self) -> io::Result<Rect> { + let (width, height) = + terminal::size().map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; + + Ok(Rect::new(0, 0, width, height)) + } + + fn flush(&mut self) -> io::Result<()> { + self.buffer.flush() + } +} + +fn map_error(error: crossterm::Result<()>) -> io::Result<()> { + error.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string( |