зеркало из
https://github.com/glebtv/tui-textarea.git
synced 2026-09-08 00:15:50 +03:00
change 'password' to more generic 'mask'. Fix tab behavior
Этот коммит содержится в:
@@ -21,8 +21,8 @@ fn main() -> io::Result<()> {
|
|||||||
|
|
||||||
let mut textarea = TextArea::default();
|
let mut textarea = TextArea::default();
|
||||||
textarea.set_cursor_line_style(Style::default());
|
textarea.set_cursor_line_style(Style::default());
|
||||||
textarea.set_password_mode(true);
|
textarea.set_mask_char('\u{2022}'); //U+2022 BULLET (•)
|
||||||
textarea.set_placeholder_text("please enter your password");
|
textarea.set_placeholder_text("Please enter your password");
|
||||||
let layout =
|
let layout =
|
||||||
Layout::default().constraints([Constraint::Length(3), Constraint::Min(1)].as_slice());
|
Layout::default().constraints([Constraint::Length(3), Constraint::Min(1)].as_slice());
|
||||||
textarea.set_style(Style::default().fg(Color::LightGreen));
|
textarea.set_style(Style::default().fg(Color::LightGreen));
|
||||||
|
|||||||
@@ -48,28 +48,39 @@ impl Boundary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_tabs(s: &str, tab_len: u8, mask: bool) -> Cow<'_, str> {
|
fn prepare_line(s: &str, tab_len: u8, mask: Option<char>) -> Cow<'_, str> {
|
||||||
let tab = spaces(tab_len);
|
// two tasks performed here
|
||||||
let mut buf = String::new();
|
// - mask out chars if mask is Some
|
||||||
for (i, c) in s.char_indices() {
|
// - replace hard tabs by the correct number of spaces
|
||||||
if buf.is_empty() {
|
// (soft tabs were done earlier in 'insert_tab')
|
||||||
if c == '\t' {
|
match mask {
|
||||||
buf.reserve(s.len());
|
Some(ch) => {
|
||||||
buf.push_str(&s[..i]);
|
// no tab processing in the mask case
|
||||||
buf.push_str(tab);
|
return Cow::Owned(s.chars().map(|_| ch).collect());
|
||||||
}
|
|
||||||
} else if c == '\t' {
|
|
||||||
buf.push_str(tab);
|
|
||||||
} else {
|
|
||||||
buf.push(c);
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
match (buf.is_empty(), mask) {
|
let tab = spaces(tab_len);
|
||||||
(true, true) => Cow::Owned(s.chars().map(|_| '*').collect()),
|
let mut buf = String::new();
|
||||||
(true, false) => Cow::Borrowed(s),
|
for (i, c) in s.char_indices() {
|
||||||
(false, true) => Cow::Owned(buf.chars().map(|_| '*').collect()),
|
if buf.is_empty() {
|
||||||
(false, false) => Cow::Owned(buf),
|
if c == '\t' {
|
||||||
}
|
buf.reserve(s.len());
|
||||||
|
buf.push_str(&s[..i]);
|
||||||
|
buf.push_str(tab);
|
||||||
|
}
|
||||||
|
} else if c == '\t' {
|
||||||
|
buf.push_str(tab);
|
||||||
|
} else {
|
||||||
|
buf.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !buf.is_empty() {
|
||||||
|
return Cow::Owned(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// drop through in the case of no mask and no tabs
|
||||||
|
return Cow::Borrowed(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LineHighlighter<'a> {
|
pub struct LineHighlighter<'a> {
|
||||||
@@ -122,7 +133,7 @@ impl<'a> LineHighlighter<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_spans(self, mask: bool) -> Spans<'a> {
|
pub fn into_spans(self, mask: Option<char>) -> Spans<'a> {
|
||||||
let Self {
|
let Self {
|
||||||
line,
|
line,
|
||||||
mut spans,
|
mut spans,
|
||||||
@@ -134,7 +145,7 @@ impl<'a> LineHighlighter<'a> {
|
|||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
if boundaries.is_empty() {
|
if boundaries.is_empty() {
|
||||||
spans.push(Span::styled(replace_tabs(line, tab_len, mask), style_begin));
|
spans.push(Span::styled(prepare_line(line, tab_len, mask), style_begin));
|
||||||
if cursor_at_end {
|
if cursor_at_end {
|
||||||
spans.push(Span::styled(" ", cursor_style));
|
spans.push(Span::styled(" ", cursor_style));
|
||||||
}
|
}
|
||||||
@@ -155,7 +166,7 @@ impl<'a> LineHighlighter<'a> {
|
|||||||
if let Some((next_boundary, end)) = boundaries.next() {
|
if let Some((next_boundary, end)) = boundaries.next() {
|
||||||
if start < end {
|
if start < end {
|
||||||
spans.push(Span::styled(
|
spans.push(Span::styled(
|
||||||
replace_tabs(&line[start..end], tab_len, mask),
|
prepare_line(&line[start..end], tab_len, mask),
|
||||||
style,
|
style,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -170,7 +181,7 @@ impl<'a> LineHighlighter<'a> {
|
|||||||
} else {
|
} else {
|
||||||
if start != line.len() {
|
if start != line.len() {
|
||||||
spans.push(Span::styled(
|
spans.push(Span::styled(
|
||||||
replace_tabs(&line[start..], tab_len, mask),
|
prepare_line(&line[start..], tab_len, mask),
|
||||||
style,
|
style,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ pub struct TextArea<'a> {
|
|||||||
alignment: Alignment,
|
alignment: Alignment,
|
||||||
pub(crate) placeholder: String,
|
pub(crate) placeholder: String,
|
||||||
pub(crate) placeholder_style: Style,
|
pub(crate) placeholder_style: Style,
|
||||||
password_mode: bool,
|
mask: Option<char>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert any iterator whose elements can be converted into [`String`] into [`TextArea`]. Each [`String`] element is
|
/// Convert any iterator whose elements can be converted into [`String`] into [`TextArea`]. Each [`String`] element is
|
||||||
@@ -163,7 +163,7 @@ impl<'a> TextArea<'a> {
|
|||||||
alignment: Alignment::Left,
|
alignment: Alignment::Left,
|
||||||
placeholder: String::new(),
|
placeholder: String::new(),
|
||||||
placeholder_style: Style::default().fg(Color::DarkGray),
|
placeholder_style: Style::default().fg(Color::DarkGray),
|
||||||
password_mode: false,
|
mask: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1007,7 +1007,7 @@ impl<'a> TextArea<'a> {
|
|||||||
hl.search(matches, self.search.style);
|
hl.search(matches, self.search.style);
|
||||||
}
|
}
|
||||||
|
|
||||||
hl.into_spans(self.password_mode)
|
hl.into_spans(self.mask)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a tui-rs widget to render the current state of the textarea. The widget instance returned from this
|
/// Build a tui-rs widget to render the current state of the textarea. The widget instance returned from this
|
||||||
@@ -1306,11 +1306,18 @@ impl<'a> TextArea<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a flag indicating if the text should be masked with * characters
|
/// Specifies that the text should be masked with the specified character
|
||||||
///
|
///
|
||||||
pub fn set_password_mode(&mut self, value: bool) {
|
pub fn set_mask_char(&mut self, mask: char) {
|
||||||
self.password_mode = value;
|
self.mask = Some(mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clear the previously set masking character
|
||||||
|
///
|
||||||
|
pub fn clear_mask_char(&mut self) {
|
||||||
|
self.mask = None;
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the style of cursor. By default, a cursor is rendered in the reversed color. Setting the same style as
|
/// Set the style of cursor. By default, a cursor is rendered in the reversed color. Setting the same style as
|
||||||
/// cursor line hides a cursor.
|
/// cursor line hides a cursor.
|
||||||
/// ```
|
/// ```
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user