зеркало из
https://github.com/glebtv/tui-textarea.git
synced 2026-09-08 00:15:50 +03:00
password - second go
Этот коммит содержится в:
@@ -63,6 +63,10 @@ required-features = ["crossterm"]
|
|||||||
name = "single_line"
|
name = "single_line"
|
||||||
required-features = ["crossterm"]
|
required-features = ["crossterm"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "password"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "variable"
|
name = "variable"
|
||||||
required-features = ["crossterm"]
|
required-features = ["crossterm"]
|
||||||
|
|||||||
62
examples/password.rs
Обычный файл
62
examples/password.rs
Обычный файл
@@ -0,0 +1,62 @@
|
|||||||
|
use crossterm::event::{DisableMouseCapture, EnableMouseCapture};
|
||||||
|
use crossterm::terminal::{
|
||||||
|
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
|
||||||
|
};
|
||||||
|
use std::io;
|
||||||
|
use tui::backend::CrosstermBackend;
|
||||||
|
use tui::layout::{Constraint, Layout};
|
||||||
|
use tui::style::{Color, Style};
|
||||||
|
use tui::widgets::{Block, Borders};
|
||||||
|
use tui::Terminal;
|
||||||
|
use tui_textarea::{Input, Key, TextArea};
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let stdout = io::stdout();
|
||||||
|
let mut stdout = stdout.lock();
|
||||||
|
|
||||||
|
enable_raw_mode()?;
|
||||||
|
crossterm::execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
|
||||||
|
let backend = CrosstermBackend::new(stdout);
|
||||||
|
let mut term = Terminal::new(backend)?;
|
||||||
|
|
||||||
|
let mut textarea = TextArea::default();
|
||||||
|
textarea.set_cursor_line_style(Style::default());
|
||||||
|
textarea.set_password_mode(true);
|
||||||
|
textarea.set_placeholder_text("please enter your password");
|
||||||
|
let layout =
|
||||||
|
Layout::default().constraints([Constraint::Length(3), Constraint::Min(1)].as_slice());
|
||||||
|
textarea.set_style(Style::default().fg(Color::LightGreen));
|
||||||
|
textarea.set_block(Block::default().borders(Borders::ALL).title("Password"));
|
||||||
|
loop {
|
||||||
|
term.draw(|f| {
|
||||||
|
let chunks = layout.split(f.size());
|
||||||
|
let widget = textarea.widget();
|
||||||
|
f.render_widget(widget, chunks[0]);
|
||||||
|
})?;
|
||||||
|
|
||||||
|
match crossterm::event::read()?.into() {
|
||||||
|
Input { key: Key::Esc, .. } => break,
|
||||||
|
Input {
|
||||||
|
key: Key::Enter, ..
|
||||||
|
} => break,
|
||||||
|
|
||||||
|
input => {
|
||||||
|
// TextArea::input returns if the input modified its text
|
||||||
|
if textarea.input(input) {
|
||||||
|
// is_valid = validate(&mut textarea);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disable_raw_mode()?;
|
||||||
|
crossterm::execute!(
|
||||||
|
term.backend_mut(),
|
||||||
|
LeaveAlternateScreen,
|
||||||
|
DisableMouseCapture
|
||||||
|
)?;
|
||||||
|
term.show_cursor()?;
|
||||||
|
|
||||||
|
println!("Input: {:?}", textarea.lines()[0]);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ use crate::tui::style::Style;
|
|||||||
feature = "ratatui-your-backend",
|
feature = "ratatui-your-backend",
|
||||||
))]
|
))]
|
||||||
use crate::tui::text::Line as Spans;
|
use crate::tui::text::Line as Spans;
|
||||||
|
|
||||||
use crate::tui::text::Span;
|
use crate::tui::text::Span;
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(
|
||||||
feature = "ratatui-crossterm",
|
feature = "ratatui-crossterm",
|
||||||
@@ -12,6 +13,7 @@ use crate::tui::text::Span;
|
|||||||
feature = "ratatui-your-backend",
|
feature = "ratatui-your-backend",
|
||||||
)))]
|
)))]
|
||||||
use crate::tui::text::Spans;
|
use crate::tui::text::Spans;
|
||||||
|
|
||||||
use crate::util::{num_digits, spaces};
|
use crate::util::{num_digits, spaces};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
@@ -46,7 +48,7 @@ impl Boundary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_tabs(s: &str, tab_len: u8) -> Cow<'_, str> {
|
fn replace_tabs(s: &str, tab_len: u8, mask: bool) -> Cow<'_, str> {
|
||||||
let tab = spaces(tab_len);
|
let tab = spaces(tab_len);
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
for (i, c) in s.char_indices() {
|
for (i, c) in s.char_indices() {
|
||||||
@@ -62,10 +64,11 @@ fn replace_tabs(s: &str, tab_len: u8) -> Cow<'_, str> {
|
|||||||
buf.push(c);
|
buf.push(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if buf.is_empty() {
|
match (buf.is_empty(), mask) {
|
||||||
Cow::Borrowed(s)
|
(true, true) => Cow::Owned(s.chars().map(|_| '*').collect()),
|
||||||
} else {
|
(true, false) => Cow::Borrowed(s),
|
||||||
Cow::Owned(buf)
|
(false, true) => Cow::Owned(buf.chars().map(|_| '*').collect()),
|
||||||
|
(false, false) => Cow::Owned(buf),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +122,7 @@ impl<'a> LineHighlighter<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_spans(self) -> Spans<'a> {
|
pub fn into_spans(self, mask: bool) -> Spans<'a> {
|
||||||
let Self {
|
let Self {
|
||||||
line,
|
line,
|
||||||
mut spans,
|
mut spans,
|
||||||
@@ -131,7 +134,7 @@ impl<'a> LineHighlighter<'a> {
|
|||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
if boundaries.is_empty() {
|
if boundaries.is_empty() {
|
||||||
spans.push(Span::styled(replace_tabs(line, tab_len), style_begin));
|
spans.push(Span::styled(replace_tabs(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));
|
||||||
}
|
}
|
||||||
@@ -152,7 +155,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),
|
replace_tabs(&line[start..end], tab_len, mask),
|
||||||
style,
|
style,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -166,7 +169,10 @@ impl<'a> LineHighlighter<'a> {
|
|||||||
start = end;
|
start = end;
|
||||||
} else {
|
} else {
|
||||||
if start != line.len() {
|
if start != line.len() {
|
||||||
spans.push(Span::styled(replace_tabs(&line[start..], tab_len), style));
|
spans.push(Span::styled(
|
||||||
|
replace_tabs(&line[start..], tab_len, mask),
|
||||||
|
style,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
if cursor_at_end {
|
if cursor_at_end {
|
||||||
spans.push(Span::styled(" ", cursor_style));
|
spans.push(Span::styled(" ", cursor_style));
|
||||||
|
|||||||
@@ -63,6 +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,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
@@ -162,6 +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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1005,7 +1007,7 @@ impl<'a> TextArea<'a> {
|
|||||||
hl.search(matches, self.search.style);
|
hl.search(matches, self.search.style);
|
||||||
}
|
}
|
||||||
|
|
||||||
hl.into_spans()
|
hl.into_spans(self.password_mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
@@ -1304,6 +1306,11 @@ impl<'a> TextArea<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets a flag indicating if the text should be masked with * characters
|
||||||
|
///
|
||||||
|
pub fn set_password_mode(&mut self, value: bool) {
|
||||||
|
self.password_mode = value;
|
||||||
|
}
|
||||||
/// 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