summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSebastian Thiel <sthiel@thoughtworks.com>2019-06-07 12:48:22 +0530
committerSebastian Thiel <sthiel@thoughtworks.com>2019-06-07 12:51:31 +0530
commit0994466c45e4a46769c6998d87cf532e80108af3 (patch)
tree59dc34514a13b79dbdf65f1b263d676b268c1fa0 /src
parent28d84fc18f3efc7cfd4aa1728656998e652e934b (diff)
Grapheme handling when truncating long filenames
Diffstat (limited to 'src')
-rw-r--r--src/interactive/app/common.rs61
-rw-r--r--src/interactive/widgets/mark.rs34
2 files changed, 87 insertions, 8 deletions
diff --git a/src/interactive/app/common.rs b/src/interactive/app/common.rs
index e542faa..937276a 100644
--- a/src/interactive/app/common.rs
+++ b/src/interactive/app/common.rs
@@ -2,6 +2,7 @@ use dua::path_of;
use dua::traverse::{EntryData, Tree, TreeIndex};
use itertools::Itertools;
use petgraph::Direction;
+use unicode_segmentation::UnicodeSegmentation;
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq)]
pub enum SortMode {
@@ -52,3 +53,63 @@ pub fn sorted_entries(tree: &Tree, node_idx: TreeIndex, sorting: SortMode) -> Ve
})
.collect()
}
+
+pub fn fit_string_graphemes_with_ellipsis(
+ s: impl Into<String>,
+ path_graphemes_count: usize,
+ mut desired_graphemes: usize,
+) -> (String, usize) {
+ const ELLIPSIS: usize = 1;
+ const MIN_GRAPHEMES_ON_SIDE: usize = 1;
+ const MIN_LEN: usize = ELLIPSIS + MIN_GRAPHEMES_ON_SIDE;
+ const USE_EXTENDED: bool = true;
+
+ let s = s.into();
+ desired_graphemes = desired_graphemes.max(MIN_LEN);
+
+ debug_assert!(
+ path_graphemes_count == s.graphemes(USE_EXTENDED).count(),
+ "input grapheme count is actually correct"
+ );
+
+ let gc = path_graphemes_count;
+ if gc <= desired_graphemes {
+ return (s, gc);
+ }
+
+ let mut n = String::with_capacity(desired_graphemes);
+ let to_be_removed = gc - desired_graphemes + ELLIPSIS;
+ let gmi = s.graphemes(USE_EXTENDED);
+
+ n.push('…');
+ n.extend(gmi.skip(to_be_removed));
+ (n, desired_graphemes)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn fit_string_inputs() {
+ assert_eq!(
+ ("aaa".into(), 3),
+ fit_string_graphemes_with_ellipsis("aaa", 3, 4)
+ );
+ assert_eq!(
+ ("…a".to_string(), 2),
+ fit_string_graphemes_with_ellipsis("abbbba", 6, 1),
+ "even amount of chars, desired too small"
+ );
+ assert_eq!(
+ ("…ca".to_string(), 3),
+ fit_string_graphemes_with_ellipsis("abbbbca", 7, 3),
+ "uneven amount of chars, desired too small"
+ );
+ assert_eq!(
+ ("… a".to_string(), 3),
+ fit_string_graphemes_with_ellipsis("a a", 6, 3),
+ "spaces are counted as graphemes, too"
+ );
+ }
+}
diff --git a/src/interactive/widgets/mark.rs b/src/interactive/widgets/mark.rs
index 9c93a3d..077eff2 100644
--- a/src/interactive/widgets/mark.rs
+++ b/src/interactive/widgets/mark.rs
@@ -1,20 +1,25 @@
-use crate::interactive::{widgets::COLOR_MARKED_LIGHT, CursorDirection};
-use dua::traverse::{Tree, TreeIndex};
-use dua::{path_of, ByteFormat};
+use crate::interactive::{
+ fit_string_graphemes_with_ellipsis, widgets::COLOR_MARKED_LIGHT, CursorDirection,
+};
+use dua::{
+ path_of,
+ traverse::{Tree, TreeIndex},
+ ByteFormat,
+};
use itertools::Itertools;
-use std::collections::btree_map::Entry;
-use std::{borrow::Borrow, collections::BTreeMap, path::PathBuf};
+use std::{borrow::Borrow, collections::btree_map::Entry, collections::BTreeMap, path::PathBuf};
use termion::{event::Key, event::Key::*};
-use tui::style::Color;
use tui::{
buffer::Buffer,
layout::Rect,
+ style::Color,
style::{Modifier, Style},
widgets::Block,
widgets::Borders,
widgets::Text,
};
use tui_react::{List, ListProps};
+use unicode_segmentation::UnicodeSegmentation;
pub type EntryMarkMap = BTreeMap<TreeIndex, EntryMark>;
pub struct EntryMark {
@@ -127,8 +132,21 @@ impl MarkPane {
Some(selected) if idx == selected => Modifier::BOLD,
_ => Modifier::empty(),
};
- let path = format!(" {}", v.path.display());
- let path_len = path.len();
+ let (path, path_len) = {
+ let path = format!(" {} ", v.path.display());
+ let num_path_graphemes = path.graphemes(true).count();
+ match num_path_graphemes + format.total_width() {
+ n if n > area.width as usize => {
+ let desired_size = num_path_graphemes - (n - area.width as usize);
+ fit_string_graphemes_with_ellipsis(
+ path,
+ num_path_graphemes,
+ desired_size,
+ )
+ }
+ _ => (path, num_path_graphemes),
+ }
+ };
let path = Text::Styled(
path.into(),
Style {