summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEllie Huxtable <ellie@elliehuxtable.com>2023-03-31 22:57:37 +0100
committerGitHub <noreply@github.com>2023-03-31 22:57:37 +0100
commita515b06bcb556c1be2d0fc3095cd778d413fe40d (patch)
tree4b544de9aa53d6976177c08b91aa3943ef4d9e92
parent3552c7e0d315f3c6d2b4b2043a3fabe7cc762e7a (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
-rw-r--r--Cargo.lock16
-rw-r--r--Cargo.toml9
-rw-r--r--src/command/client/search/history_list.rs4
-rw-r--r--src/command/client/search/interactive.rs4
-rw-r--r--src/main.rs3
-rw-r--r--src/ratatui/.github/ISSUE_TEMPLATE/bug_report.md60
-rw-r--r--src/ratatui/.github/ISSUE_TEMPLATE/config.yml1
-rw-r--r--src/ratatui/.github/ISSUE_TEMPLATE/feature_request.md32
-rw-r--r--src/ratatui/.github/workflows/cd.yml19
-rw-r--r--src/ratatui/.github/workflows/ci.yml76
-rw-r--r--src/ratatui/.gitignore6
-rw-r--r--src/ratatui/LICENSE21
-rw-r--r--src/ratatui/README.md136
-rw-r--r--src/ratatui/backend/crossterm.rs241
-rw-r--r--src/ratatui/backend/mod.rs58
-rw-r--r--src/ratatui/backend/termion.rs275
-rw-r--r--src/ratatui/buffer.rs736
-rw-r--r--src/ratatui/layout.rs560
-rw-r--r--src/ratatui/mod.rs177
-rw-r--r--src/ratatui/style.rs310
-rw-r--r--src/ratatui/symbols.rs233
-rw-r--r--src/ratatui/terminal.rs487
-rw-r--r--src/ratatui/text.rs430
-rw-r--r--src/ratatui/widgets/barchart.rs219
-rw-r--r--src/ratatui/widgets/block.rs573
-rw-r--r--src/ratatui/widgets/canvas/line.rs95
-rw-r--r--src/ratatui/widgets/canvas/map.rs48
-rw-r--r--src/ratatui/widgets/canvas/mod.rs510
-rw-r--r--src/ratatui/widgets/canvas/points.rs30
-rw-r--r--src/ratatui/widgets/canvas/rectangle.rs52
-rw-r--r--src/ratatui/widgets/canvas/world.rs6299
-rw-r--r--src/ratatui/widgets/chart.rs660
-rw-r--r--src/ratatui/widgets/clear.rs37
-rw-r--r--src/ratatui/widgets/gauge.rs313
-rw-r--r--src/ratatui/widgets/list.rs268
-rw-r--r--src/ratatui/widgets/mod.rs184
-rw-r--r--src/ratatui/widgets/paragraph.rs214
-rw-r--r--src/ratatui/widgets/reflow.rs534
-rw-r--r--src/ratatui/widgets/sparkline.rs155
-rw-r--r--src/ratatui/widgets/table.rs504
-rw-r--r--src/ratatui/widgets/tabs.rs129
41 files changed, 14697 insertions, 21 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 264648bb..7fa24a1f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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"
diff --git a/Cargo.toml b/Cargo.toml
index af3867b7..9272dc68 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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(