1use std::fmt::{Display, Formatter, Error, Alignment};
25
26use unicode_width::UnicodeWidthStr;
27
28pub struct CJKAlign<'a>(pub &'a str);
29impl<'a> Display for CJKAlign<'a> {
30 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
31 StringWidth::fmt(self, f)
32 }
33}
34
35pub struct CJKAlignWide<'a>(pub &'a str);
36impl<'a> Display for CJKAlignWide<'a> {
37 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
38 StringWidth::fmt(self, f)
39 }
40}
41
42trait StringWidth {
43 fn width(&self) -> usize;
44 fn str(&self) -> &str;
45
46 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
47 let w = f.width().unwrap_or(0);
48 if w == 0 {
49 write!(f, "{}", self.str())
50 } else {
51 let self_width = self.width();
52 let pad = w.saturating_sub(self_width);
53 match f.align() {
54 Some(Alignment::Left) | None => write!(f, "{}{}", self.str(), " ".repeat(pad)),
55 Some(Alignment::Right) => write!(f, "{}{}", " ".repeat(pad), self.str()),
56 Some(Alignment::Center) => {
57 write!(f, "{}{}{}", " ".repeat(pad - pad / 2), self.str(), " ".repeat(pad / 2))
58 },
59 }
60 }
61 }
62}
63
64impl<'a> StringWidth for CJKAlign<'a> {
65 fn width(&self) -> usize {
66 UnicodeWidthStr::width(self.0)
67 }
68
69 fn str(&self) -> &str {
70 self.0
71 }
72}
73
74impl<'a> StringWidth for CJKAlignWide<'a> {
75 fn width(&self) -> usize {
76 UnicodeWidthStr::width_cjk(self.0)
77 }
78
79 fn str(&self) -> &str {
80 self.0
81 }
82}