mirror of
https://github.com/Llewellynvdm/starship.git
synced 2024-11-05 04:47:58 +00:00
fix(explain): align table correctly (#1482)
* fix(explain): align table correctly * iterate over lines directly * calculate desc_width with the actual space available * custom unicode-aware textwrapping * fix clippy error * better width estimination * explain +6 * move padding width into a constant
This commit is contained in:
parent
0be9ffc0a1
commit
8b0f589486
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -195,7 +195,7 @@ dependencies = [
|
|||||||
"atty",
|
"atty",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"strsim",
|
"strsim",
|
||||||
"textwrap 0.11.0",
|
"textwrap",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
"vec_map",
|
"vec_map",
|
||||||
]
|
]
|
||||||
@ -1110,7 +1110,6 @@ dependencies = [
|
|||||||
"sysinfo",
|
"sysinfo",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"term_size",
|
"term_size",
|
||||||
"textwrap 0.12.1",
|
|
||||||
"toml",
|
"toml",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
@ -1202,15 +1201,6 @@ dependencies = [
|
|||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "textwrap"
|
|
||||||
version = "0.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -56,7 +56,6 @@ os_info = "2.0.7"
|
|||||||
urlencoding = "1.1.1"
|
urlencoding = "1.1.1"
|
||||||
open = "1.4.0"
|
open = "1.4.0"
|
||||||
unicode-width = "0.1.8"
|
unicode-width = "0.1.8"
|
||||||
textwrap = "0.12.1"
|
|
||||||
term_size = "0.3.2"
|
term_size = "0.3.2"
|
||||||
quick-xml = "0.18.1"
|
quick-xml = "0.18.1"
|
||||||
|
|
||||||
|
88
src/print.rs
88
src/print.rs
@ -4,6 +4,7 @@ use rayon::prelude::*;
|
|||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::fmt::{self, Debug, Write as FmtWrite};
|
use std::fmt::{self, Debug, Write as FmtWrite};
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
use unicode_width::UnicodeWidthChar;
|
use unicode_width::UnicodeWidthChar;
|
||||||
|
|
||||||
use crate::configs::PROMPT_ORDER;
|
use crate::configs::PROMPT_ORDER;
|
||||||
@ -104,50 +105,72 @@ pub fn explain(args: ArgMatches) {
|
|||||||
let value = module.get_segments().join("");
|
let value = module.get_segments().join("");
|
||||||
ModuleInfo {
|
ModuleInfo {
|
||||||
value: ansi_term::ANSIStrings(&module.ansi_strings()).to_string(),
|
value: ansi_term::ANSIStrings(&module.ansi_strings()).to_string(),
|
||||||
value_len: value.chars().count() + count_wide_chars(&value),
|
value_len: better_width(value.as_str()),
|
||||||
desc: module.get_description().to_owned(),
|
desc: module.get_description().to_owned(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<ModuleInfo>>();
|
.collect::<Vec<ModuleInfo>>();
|
||||||
|
|
||||||
let mut max_ansi_module_width = 0;
|
let max_module_width = modules.iter().map(|i| i.value_len).max().unwrap_or(0);
|
||||||
let mut max_module_width = 0;
|
|
||||||
|
|
||||||
for info in &modules {
|
// In addition to the module width itself there are also 6 padding characters in each line.
|
||||||
max_ansi_module_width = std::cmp::max(
|
// Overall a line looks like this: " {module name} - {description}".
|
||||||
max_ansi_module_width,
|
const PADDING_WIDTH: usize = 6;
|
||||||
info.value.chars().count() + count_wide_chars(&info.value),
|
|
||||||
);
|
|
||||||
max_module_width = std::cmp::max(max_module_width, info.value_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
let desc_width = term_size::dimensions()
|
let desc_width = term_size::dimensions()
|
||||||
.map(|(w, _)| w)
|
.map(|(w, _)| w)
|
||||||
.map(|width| width - std::cmp::min(width, max_ansi_module_width));
|
// Add padding length to module length to avoid text overflow. This line also assures desc_width >= 0.
|
||||||
|
.map(|width| width - std::cmp::min(width, max_module_width + PADDING_WIDTH));
|
||||||
|
|
||||||
println!("\n Here's a breakdown of your prompt:");
|
println!("\n Here's a breakdown of your prompt:");
|
||||||
for info in modules {
|
for info in modules {
|
||||||
let wide_chars = count_wide_chars(&info.value);
|
|
||||||
|
|
||||||
if let Some(desc_width) = desc_width {
|
if let Some(desc_width) = desc_width {
|
||||||
let wrapped = textwrap::fill(&info.desc, desc_width);
|
// Custom Textwrapping!
|
||||||
let mut lines = wrapped.split('\n');
|
let mut current_pos = 0;
|
||||||
println!(
|
let mut escaping = false;
|
||||||
" {:width$} - {}",
|
// Print info
|
||||||
|
print!(
|
||||||
|
" {}{} - ",
|
||||||
info.value,
|
info.value,
|
||||||
lines.next().unwrap(),
|
" ".repeat(max_module_width - info.value_len)
|
||||||
width = max_ansi_module_width - wide_chars
|
|
||||||
);
|
);
|
||||||
|
for g in info.desc.graphemes(true) {
|
||||||
for line in lines {
|
// Handle ANSI escape sequnces
|
||||||
println!("{}{}", " ".repeat(max_module_width + 6), line.trim());
|
if g == "\x1B" {
|
||||||
|
escaping = true;
|
||||||
}
|
}
|
||||||
|
if escaping {
|
||||||
|
print!("{}", g);
|
||||||
|
escaping = !("a" <= g && "z" >= g || "A" <= g && "Z" >= g);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle normal wrapping
|
||||||
|
current_pos += grapheme_width(g);
|
||||||
|
// Wrap when hitting max width or newline
|
||||||
|
if g == "\n" || current_pos > desc_width {
|
||||||
|
// trim spaces on linebreak
|
||||||
|
if g == " " && desc_width > 1 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
print!("\n{}", " ".repeat(max_module_width + PADDING_WIDTH));
|
||||||
|
if g == "\n" {
|
||||||
|
current_pos = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_pos = 1;
|
||||||
|
}
|
||||||
|
print!("{}", g);
|
||||||
|
}
|
||||||
|
println!();
|
||||||
} else {
|
} else {
|
||||||
println!(
|
println!(
|
||||||
" {:width$} - {}",
|
" {}{} - {}",
|
||||||
info.value,
|
info.value,
|
||||||
|
" ".repeat(max_module_width - info.value_len),
|
||||||
info.desc,
|
info.desc,
|
||||||
width = max_ansi_module_width - wide_chars
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -266,6 +289,19 @@ fn should_add_implicit_custom_module(
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count_wide_chars(value: &str) -> usize {
|
fn better_width(s: &str) -> usize {
|
||||||
value.chars().filter(|c| c.width().unwrap_or(0) > 1).count()
|
s.graphemes(true).map(grapheme_width).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume that graphemes have width of the first character in the grapheme
|
||||||
|
fn grapheme_width(g: &str) -> usize {
|
||||||
|
g.chars().next().and_then(|i| i.width()).unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_grapheme_aware_better_width() {
|
||||||
|
// UnicodeWidthStr::width would return 8
|
||||||
|
assert_eq!(2, better_width("👩👩👦👦"));
|
||||||
|
assert_eq!(1, better_width("Ü"));
|
||||||
|
assert_eq!(11, better_width("normal text"));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user