summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Thiel <sebastian.thiel@icloud.com>2020-03-29 19:47:46 +0800
committerSebastian Thiel <sebastian.thiel@icloud.com>2020-03-29 19:48:04 +0800
commit584cc989cfdf37cd11a2e885e42ddabaccda7dec (patch)
tree4c02c6ea42bf4b47bd0ece1f821b2f93059bfedf
parent1f1c0ce5171ec691152954d3169a266e760ea873 (diff)
Import plenty of utilities from prodash into tui-reacttui-react-v0.2.2
-rw-r--r--Cargo.lock12
-rw-r--r--tui-react/Cargo.toml4
-rw-r--r--tui-react/src/lib.rs129
3 files changed, 138 insertions, 7 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 91e4ee1..bc7732a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -28,9 +28,9 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]]
name = "backtrace"
-version = "0.3.45"
+version = "0.3.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8"
+checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
dependencies = [
"backtrace-sys",
"cfg-if",
@@ -40,9 +40,9 @@ dependencies = [
[[package]]
name = "backtrace-sys"
-version = "0.1.34"
+version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69"
+checksum = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118"
dependencies = [
"cc",
"libc",
@@ -601,10 +601,12 @@ dependencies = [
[[package]]
name = "tui-react"
-version = "0.2.1"
+version = "0.2.2"
dependencies = [
"log",
"tui",
+ "unicode-segmentation",
+ "unicode-width",
]
[[package]]
diff --git a/tui-react/Cargo.toml b/tui-react/Cargo.toml
index 341bd41..d41605b 100644
--- a/tui-react/Cargo.toml
+++ b/tui-react/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "tui-react"
-version = "0.2.1"
+version = "0.2.2"
authors = ["Sebastian Thiel <sthiel@thoughtworks.com>"]
edition = "2018"
repository = "https://github.com/Byron/dua-cli"
@@ -11,3 +11,5 @@ license = "MIT"
[dependencies]
tui = "0.8.0"
log = "0.4.6"
+unicode-segmentation = "1.6.0"
+unicode-width = "0.1.7"
diff --git a/tui-react/src/lib.rs b/tui-react/src/lib.rs
index b7d5b94..de9fad1 100644
--- a/tui-react/src/lib.rs
+++ b/tui-react/src/lib.rs
@@ -7,7 +7,9 @@ pub use list::*;
pub use terminal::*;
use std::iter::repeat;
-use tui::{self, buffer::Buffer, layout::Rect, style::Color};
+use tui::{self, buffer::Buffer, layout::Rect, style::Color, style::Style};
+use unicode_segmentation::UnicodeSegmentation;
+use unicode_width::UnicodeWidthStr;
pub fn fill_background_to_right(mut s: String, entire_width: u16) -> String {
match (s.len(), entire_width as usize) {
@@ -27,3 +29,128 @@ pub fn fill_background(area: Rect, buf: &mut Buffer, color: Color) {
}
}
}
+
+pub fn draw_text_with_ellipsis_nowrap<'a>(
+ bound: Rect,
+ buf: &mut Buffer,
+ text: impl AsRef<str>,
+ style: impl Into<Option<Style>>,
+) -> u16 {
+ let s = style.into();
+ let t = text.as_ref();
+ let mut graphemes = t.graphemes(true);
+ let mut total_width = 0;
+ {
+ let mut ellipsis_candidate_x = None;
+ let mut x_offset = 0;
+ for (g, mut x) in graphemes.by_ref().zip(bound.left()..bound.right()) {
+ let width = g.width();
+ total_width += width;
+
+ x += x_offset;
+ let cell = buf.get_mut(x, bound.y);
+ if x + 1 == bound.right() {
+ ellipsis_candidate_x = Some(x);
+ }
+ cell.symbol = g.into();
+ if let Some(s) = s {
+ cell.style = s;
+ }
+
+ x_offset += width.saturating_sub(1) as u16;
+ if x + x_offset >= bound.right() {
+ break;
+ }
+ let x = x as usize;
+ for x in x + 1..x + width {
+ let i = buf.index_of(x as u16, bound.y);
+ buf.content[i].reset();
+ }
+ }
+ if let (Some(_), Some(x)) = (graphemes.next(), ellipsis_candidate_x) {
+ buf.get_mut(x, bound.y).symbol = "…".into();
+ }
+ }
+ total_width as u16
+}
+
+pub fn draw_text_nowrap_fn(
+ bound: Rect,
+ buf: &mut Buffer,
+ t: impl AsRef<str>,
+ mut s: impl FnMut(&str, u16, u16) -> Style,
+) {
+ if bound.width == 0 {
+ return;
+ }
+ for (g, x) in t.as_ref().graphemes(true).zip(bound.left()..bound.right()) {
+ let cell = buf.get_mut(x, bound.y);
+ cell.symbol = g.into();
+ cell.style = s(&cell.symbol, x, bound.y);
+ }
+}
+
+pub mod util {
+ use unicode_segmentation::UnicodeSegmentation;
+ use unicode_width::UnicodeWidthStr;
+
+ pub fn sanitize_offset(offset: u16, num_items: usize, num_displayable_lines: u16) -> u16 {
+ offset.min((num_items.saturating_sub(num_displayable_lines as usize)) as u16)
+ }
+
+ #[derive(Default)]
+ pub struct GraphemeCountWriter(pub usize);
+
+ impl std::io::Write for GraphemeCountWriter {
+ fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
+ self.0 += String::from_utf8_lossy(buf).graphemes(true).count();
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> Result<(), std::io::Error> {
+ Ok(())
+ }
+ }
+
+ pub fn block_width(s: &str) -> u16 {
+ s.graphemes(true).map(|g| g.width()).sum::<usize>() as u16
+ }
+
+ pub mod rect {
+ use tui::layout::Rect;
+
+ /// A safe version of Rect::intersection that doesn't suffer from underflows
+ pub fn intersect(lhs: Rect, rhs: Rect) -> Rect {
+ let x1 = lhs.x.max(rhs.x);
+ let y1 = lhs.y.max(rhs.y);
+ let x2 = lhs.right().min(rhs.right());
+ let y2 = lhs.bottom().min(rhs.bottom());
+ Rect {
+ x: x1,
+ y: y1,
+ width: x2.saturating_sub(x1),
+ height: y2.saturating_sub(y1),
+ }
+ }
+
+ pub fn offset_x(r: Rect, offset: u16) -> Rect {
+ Rect {
+ x: r.x + offset,
+ width: r.width.saturating_sub(offset),
+ ..r
+ }
+ }
+
+ pub fn snap_to_right(bound: Rect, new_width: u16) -> Rect {
+ offset_x(bound, bound.width.saturating_sub(new_width))
+ }
+
+ pub fn line_bound(bound: Rect, line: usize) -> Rect {
+ Rect {
+ y: bound.y + line as u16,
+ height: 1,
+ ..bound
+ }
+ }
+ }
+}