summaryrefslogtreecommitdiffstats
path: root/src/display/crop.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/display/crop.rs')
-rw-r--r--src/display/crop.rs66
1 files changed, 53 insertions, 13 deletions
diff --git a/src/display/crop.rs b/src/display/crop.rs
index 38a1ad0..c060739 100644
--- a/src/display/crop.rs
+++ b/src/display/crop.rs
@@ -1,22 +1,62 @@
use {
+ super::TAB_REPLACEMENT,
unicode_width::UnicodeWidthChar,
};
-// return the counts in bytes and columns of the longest substring
-// fitting the given number of columns
-pub fn count_fitting(s: &str, columns_max: usize) -> (usize, usize) {
- let mut count_bytes = 0;
- let mut str_width = 0;
- for (idx, c) in s.char_indices() {
- let char_width = UnicodeWidthChar::width(c).unwrap_or(0);
- let next_str_width = str_width + char_width;
- if next_str_width > columns_max {
- break;
+
+#[derive(Debug, Clone, Copy)]
+pub struct StrFit {
+ bytes_count: usize,
+ cols_count: usize,
+ has_tab: bool,
+}
+
+impl StrFit {
+ pub fn from(s: &str, cols_max: usize) -> Self {
+ let mut bytes_count = 0;
+ let mut cols_count = 0;
+ let mut has_tab = false;
+ for (idx, c) in s.char_indices() {
+ let char_width = if '\t' == c {
+ has_tab = true;
+ TAB_REPLACEMENT.len()
+ } else {
+ UnicodeWidthChar::width(c).unwrap_or(0)
+ };
+ let next_str_width = cols_count + char_width;
+ if next_str_width > cols_max {
+ break;
+ }
+ cols_count = next_str_width;
+ bytes_count = idx + c.len_utf8();
}
- str_width = next_str_width;
- count_bytes = idx + c.len_utf8();
+ Self {
+ bytes_count,
+ cols_count,
+ has_tab,
+ }
+ }
+}
+
+/// return the counts in bytes and columns of the longest substring
+/// fitting the given number of columns
+pub fn count_fitting(s: &str, cols_max: usize) -> (usize, usize) {
+ let fit = StrFit::from(s, cols_max);
+ (fit.bytes_count, fit.cols_count)
+}
+
+/// return both the longest fitting string and the number of cols
+/// it takes on screen.
+/// We don't build a string around the whole str, which could be costly
+/// if it's very big
+pub fn make_string(s: &str, cols_max: usize) -> (String, usize) {
+ let fit = StrFit::from(s, cols_max);
+ if fit.has_tab {
+ let string = (&s[0..fit.bytes_count]).replace('\t', TAB_REPLACEMENT);
+ (string, fit.cols_count)
+ } else {
+ (s[0..fit.bytes_count].to_string(), fit.cols_count)
}
- (count_bytes, str_width)
}
#[cfg(test)]