Add masked property while rendering text-(like) objects

pull/648/head
sudipghimire533 2 years ago committed by Sudip Ghimire
parent a6b25a4877
commit aeb75a8be7

@ -100,7 +100,7 @@ fn ui<B: Backend>(f: &mut Frame<B>, app: &App) {
let chunks = Layout::default()
.direction(Direction::Vertical)
.margin(5)
.margin(2)
.constraints(
[
Constraint::Percentage(25),
@ -123,9 +123,14 @@ fn ui<B: Backend>(f: &mut Frame<B>, app: &App) {
Style::default().bg(Color::Blue),
)),
Spans::from(Span::styled(
"This is a longer line",
"Text below this is masked 😃",
Style::default().add_modifier(Modifier::CROSSED_OUT),
)),
Spans::from(Span::masked(
"This is masked text 😃",
Style::default().bg(Color::Black).fg(Color::LightGreen),
'*',
)),
Spans::from(Span::styled(&long_line, Style::default().bg(Color::Green))),
Spans::from(Span::styled(
"This is a line",

@ -56,6 +56,7 @@ use unicode_width::UnicodeWidthStr;
pub struct StyledGrapheme<'a> {
pub symbol: &'a str,
pub style: Style,
pub mask: Option<char>,
}
/// A string where all graphemes have the same style.
@ -63,6 +64,7 @@ pub struct StyledGrapheme<'a> {
pub struct Span<'a> {
pub content: Cow<'a, str>,
pub style: Style,
pub mask: Option<char>,
}
impl<'a> Span<'a> {
@ -82,6 +84,7 @@ impl<'a> Span<'a> {
Span {
content: content.into(),
style: Style::default(),
mask: None,
}
}
@ -103,6 +106,18 @@ impl<'a> Span<'a> {
Span {
content: content.into(),
style,
mask: None,
}
}
pub fn masked<T>(content: T, style: Style, mask: char) -> Span<'a>
where
T: Into<Cow<'a, str>>,
{
Span {
content: content.into(),
mask: Some(mask),
style,
}
}
@ -176,6 +191,7 @@ impl<'a> Span<'a> {
.map(move |g| StyledGrapheme {
symbol: g,
style: base_style.patch(self.style),
mask: self.mask,
})
.filter(|s| s.symbol != "\n")
}

@ -159,6 +159,7 @@ impl<'a> Widget for Paragraph<'a> {
.chain(iter::once(StyledGrapheme {
symbol: "\n",
style: self.style,
mask: None,
}))
});
@ -175,16 +176,29 @@ impl<'a> Widget for Paragraph<'a> {
while let Some((current_line, current_line_width)) = line_composer.next_line() {
if y >= self.scroll.0 {
let mut x = get_line_offset(current_line_width, text_area.width, self.alignment);
for StyledGrapheme { symbol, style } in current_line {
for StyledGrapheme { symbol, style, mask } in current_line {
let to_render_symbol = if symbol.is_empty() {
// If the symbol is empty, the last char which rendered last time will
// leave on the line. It's a quick fix.
String::from(" ")
} else {
match mask {
None => symbol.to_string(),
Some(masker) => if false {
// FIXME:
// TODO: Only one of if/else branch is to be left
// should we do:
// - masker.repeat(symbol.len()) or,
// - makser
std::iter::repeat(masker)
.take(symbol.len())
.collect()
} else { String::from(*masker) },
}
};
buf.get_mut(text_area.left() + x, text_area.top() + y - self.scroll.0)
.set_symbol(if symbol.is_empty() {
// If the symbol is empty, the last char which rendered last time will
// leave on the line. It's a quick fix.
" "
} else {
symbol
})
.set_style(*style);
.set_symbol(to_render_symbol.as_str()).set_style(*style);
x += symbol.width() as u16;
}
}

@ -55,7 +55,7 @@ impl<'a, 'b> LineComposer<'a> for WordWrapper<'a, 'b> {
let mut width_to_last_word_end: u16 = 0;
let mut prev_whitespace = false;
let mut symbols_exhausted = true;
for StyledGrapheme { symbol, style } in &mut self.symbols {
for StyledGrapheme { symbol, style, mask } in &mut self.symbols {
symbols_exhausted = false;
let symbol_whitespace = symbol.chars().all(&char::is_whitespace) && symbol != NBSP;
@ -82,7 +82,7 @@ impl<'a, 'b> LineComposer<'a> for WordWrapper<'a, 'b> {
width_to_last_word_end = current_line_width;
}
self.current_line.push(StyledGrapheme { symbol, style });
self.current_line.push(StyledGrapheme { symbol, style, mask });
current_line_width += symbol.width() as u16;
if current_line_width > self.max_line_width {
@ -161,7 +161,7 @@ impl<'a, 'b> LineComposer<'a> for LineTruncator<'a, 'b> {
let mut skip_rest = false;
let mut symbols_exhausted = true;
let mut horizontal_offset = self.horizontal_offset as usize;
for StyledGrapheme { symbol, style } in &mut self.symbols {
for StyledGrapheme { symbol, style, mask } in &mut self.symbols {
symbols_exhausted = false;
// Ignore characters wider that the total max width.
@ -194,7 +194,7 @@ impl<'a, 'b> LineComposer<'a> for LineTruncator<'a, 'b> {
}
};
current_line_width += symbol.width() as u16;
self.current_line.push(StyledGrapheme { symbol, style });
self.current_line.push(StyledGrapheme { symbol, style, mask });
}
if skip_rest {
@ -241,8 +241,9 @@ mod test {
fn run_composer(which: Composer, text: &str, text_area_width: u16) -> (Vec<String>, Vec<u16>) {
let style = Default::default();
let mask = None;
let mut styled =
UnicodeSegmentation::graphemes(text, true).map(|g| StyledGrapheme { symbol: g, style });
UnicodeSegmentation::graphemes(text, true).map(|g| StyledGrapheme { symbol: g, style, mask });
let mut composer: Box<dyn LineComposer> = match which {
Composer::WordWrapper { trim } => {
Box::new(WordWrapper::new(&mut styled, text_area_width, trim))

Loading…
Cancel
Save