Struct r3bl_terminal_async::readline_impl::readline::Readline
source · pub struct Readline {
pub safe_raw_terminal: SafeRawTerminal,
pub pinned_input_stream: PinnedInputStream,
pub safe_line_state: SafeLineState,
pub history_sender: UnboundedSender<String>,
pub history_receiver: UnboundedReceiver<String>,
pub safe_history: SafeHistory,
pub safe_is_paused: SafeBool,
pub safe_is_paused_buffer: SafePauseBuffer,
pub shutdown_sender: Sender<bool>,
}
Expand description
§Mental model and overview
This is a replacement for a std::io::BufRead::read_line function. It is async. It supports other tasks concurrently writing to the terminal output (via SharedWriters). It also supports being paused so that crate::Spinner can display an indeterminate progress spinner. Then it can be resumed so that the user can type in the terminal. Upon resumption, any queued output from the SharedWriters is printed out.
When you call Self::readline() it enters an infinite loop. During which you can type
things into the multiline editor, which also displays the prompt. You can press up,
down, left, right, etc. While in this loop other tasks can send messages to the
Readline
task via the line
channel, using the SharedWriter::line_sender
.
When you create a new Readline
instance, a task, is started via
pause_and_resume_support::spawn_task_to_monitor_line_channel()
. This task
monitors the line
channel, and processes any messages that are sent to it. This
allows the task to be paused, and resumed, and to flush the output from the
SharedWriter
s. When you Readline::close()
the instance or drop it, this task
is aborted.
§Inputs and dependency injection
There are 2 main resources that must be passed into Self::new()
:
PinnedInputStream
- This trait represents an async stream of events. It is typically implemented bycrossterm::event::EventStream
. This is used to get input from the user. However for testing you can provide your own implementation of this trait.SafeRawTerminal
- This trait represents a raw terminal. It is typically implemented bystd::io::Stdout
. This is used to write to the terminal. However for testing you can provide your own implementation of this trait.
§Support for testing
Almost all the fields of this struct contain Safe
in their names. This is because
they are wrapped in a Mutex
and Arc
, so that they can be shared between tasks.
This makes it easier to test this struct, because you can mock the terminal output,
and the input stream. You can also mock the history, and the pause buffer. This is all
possible because of the dependency injection that this struct uses. See the tests for
how this is used. If there are some fields that seem a bit uneconomic, in where they
come from, it is probably due to the requirement for every part of this system to be
testable (easily).
§Pause and resume
When the terminal is paused, then any output from the SharedWriter
s will not be
printed to the terminal. This is useful when you want to display a spinner, or some
other indeterminate progress indicator.
When the terminal is resumed, then the output from the SharedWriter
s will be
printed to the terminal by the pause_and_resume_support::flush_internal()
method,
which drains a buffer that holds any output that was generated while paused, of type
PauseBuffer
.
This is possible, because while paused, the
pause_and_resume_support::process_line_control_signal()
method doesn’t actually
print anything to the display. When resumed, the
pause_and_resume_support::flush_internal()
method is called, which drains the
PauseBuffer
(if there are any messages in it, and prints them out) so nothing is
lost!
§Usage details
Struct for reading lines of input from a terminal while lines are output to the terminal concurrently.
Terminal input is retrieved by calling Readline::readline()
, which returns each
complete line of input once the user presses Enter.
Each Readline
instance is associated with one or more SharedWriter
instances.
Lines written to an associated SharedWriter
are output:
- While retrieving input with
readline()
. - By calling
pause_and_resume_support::flush_internal()
.
You can provide your own implementation of SafeRawTerminal, via dependency
injection, so that you can mock terminal
output for testing. You can also extend this struct to adapt your own terminal output
using this mechanism. Essentially anything that complies with dyn std::io::Write + Send
trait bounds can be used.
Fields§
§safe_raw_terminal: SafeRawTerminal
Raw terminal implementation, you can supply this via dependency injection.
pinned_input_stream: PinnedInputStream
Stream of events.
safe_line_state: SafeLineState
Current line.
history_sender: UnboundedSender<String>
Use to send history updates.
history_receiver: UnboundedReceiver<String>
Use to receive history updates.
safe_history: SafeHistory
Manages the history.
safe_is_paused: SafeBool
Determines whether terminal is paused or not. When paused, concurrent output
via SharedWriter
s is not printed to the terminal.
safe_is_paused_buffer: SafePauseBuffer
Collects lines that are written to the terminal while the terminal is paused.
shutdown_sender: Sender<bool>
Shutdown broadcast channel that is used to stop both:
pause_and_resume_support::spawn_task_to_monitor_line_channel
.Readline::readline
if it is currently running.- Also see:
Readline::close
.
Implementations§
source§impl Readline
impl Readline
sourcepub fn new(
prompt: String,
safe_raw_terminal: SafeRawTerminal,
pinned_input_stream: PinnedInputStream
) -> Result<(Self, SharedWriter), ReadlineError>
pub fn new( prompt: String, safe_raw_terminal: SafeRawTerminal, pinned_input_stream: PinnedInputStream ) -> Result<(Self, SharedWriter), ReadlineError>
Create a new instance with an associated SharedWriter
. To customize the
behavior of this instance, you can use the following methods:
sourcepub fn update_prompt(&mut self, prompt: &str) -> Result<(), ReadlineError>
pub fn update_prompt(&mut self, prompt: &str) -> Result<(), ReadlineError>
Change the prompt.
sourcepub fn clear(&mut self) -> Result<(), ReadlineError>
pub fn clear(&mut self) -> Result<(), ReadlineError>
Clear the screen.
sourcepub fn set_max_history(&mut self, max_size: usize)
pub fn set_max_history(&mut self, max_size: usize)
Set maximum history length. The default length is crate::HISTORY_SIZE_MAX.
sourcepub fn should_print_line_on(&mut self, enter: bool, control_c: bool)
pub fn should_print_line_on(&mut self, enter: bool, control_c: bool)
Set whether the input line should remain on the screen after events.
If enter
is true, then when the user presses “Enter”, the prompt and the text
they entered will remain on the screen, and the cursor will move to the next line.
If enter
is false, the prompt & input will be erased instead.
control_c
similarly controls the behavior for when the user presses Ctrl-C.
The default value for both settings is true
.
Examples found in repository?
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
fn process_user_input(
user_input: String,
state: &mut State,
shared_writer: &mut SharedWriter,
readline: &mut Readline,
) -> miette::Result<ControlFlow<()>> {
// Add to history.
let line = user_input.trim();
readline.add_history_entry(line.to_string());
// Convert line to command. And process it.
let result_command = Command::from_str(&line.trim().to_lowercase());
match result_command {
Err(_) => {
writeln!(shared_writer, "Unknown command!").into_diagnostic()?;
return Ok(ControlFlow::Continue(()));
}
Ok(command) => match command {
Command::Exit => {
writeln!(shared_writer, "{}", "Exiting due to exit command...".red())
.into_diagnostic()?;
readline.close();
return Ok(ControlFlow::Break(()));
}
Command::StartTask1 => {
state.task_1_state.is_running = true;
writeln!(
shared_writer,
"First task started! This prints to SharedWriter."
)
.into_diagnostic()?;
}
Command::StopTask1 => {
state.task_1_state.is_running = false;
writeln!(shared_writer, "First task stopped!").into_diagnostic()?;
}
Command::StartTask2 => {
state.task_2_state.is_running = true;
writeln!(
shared_writer,
"Second task started! This generates logs which print to DisplayPreference (SharedWriter) and file."
)
.into_diagnostic()?;
}
Command::StopTask2 => {
state.task_2_state.is_running = false;
writeln!(shared_writer, "Second task stopped!").into_diagnostic()?;
}
Command::StartPrintouts => {
writeln!(shared_writer, "Printouts started!").into_diagnostic()?;
readline.should_print_line_on(true, true);
}
Command::StopPrintouts => {
writeln!(shared_writer, "Printouts stopped!").into_diagnostic()?;
readline.should_print_line_on(false, false);
}
Command::Info => {
writeln!(shared_writer, "{}", get_info_message()).into_diagnostic()?;
}
Command::Spinner => {
writeln!(shared_writer, "Spinner started! Pausing terminal...")
.into_diagnostic()?;
long_running_task::spawn_task_that_shows_spinner(
shared_writer,
"Spinner task",
Duration::from_millis(100),
);
}
Command::Tree => {
let mut shared_writer_clone = shared_writer.clone();
tokio::spawn(async move {
let mut_shared_writer = &mut shared_writer_clone;
match file_walker::get_current_working_directory() {
Ok((root_path, _)) => {
match file_walker::display_tree(root_path, mut_shared_writer, true)
.await
{
Ok(_) => {}
Err(_) => todo!(),
};
}
Err(_) => todo!(),
}
});
}
},
}
Ok(ControlFlow::Continue(()))
}
sourcepub async fn readline(&mut self) -> Result<ReadlineEvent, ReadlineError>
pub async fn readline(&mut self) -> Result<ReadlineEvent, ReadlineError>
Polling function for readline
, manages all input and output. Returns either an
ReadlineEvent or an ReadlineError.
sourcepub fn add_history_entry(&mut self, entry: String) -> Option<()>
pub fn add_history_entry(&mut self, entry: String) -> Option<()>
Add a line to the input history.
Examples found in repository?
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
async fn main() -> miette::Result<()> {
let maybe_terminal_async = TerminalAsync::try_new("> ").await?;
// If the terminal is not fully interactive, then return early.
let mut terminal_async = match maybe_terminal_async {
None => return Ok(()),
_ => maybe_terminal_async.unwrap(),
};
// Pre-populate the readline's history with some entries.
for command in Command::iter() {
terminal_async
.readline
.add_history_entry(command.to_string());
}
// Initialize tracing w/ the "async stdout" (SharedWriter), and file writer.
let display_preference = DisplayPreference::SharedWriter(terminal_async.shared_writer.clone());
let config = TracingConfig::new(display_preference);
tracing_setup::init(config)?;
// Start tasks.
let mut state = State::default();
let mut interval_1_task = interval(state.task_1_state.interval_delay);
let mut interval_2_task = interval(state.task_2_state.interval_delay);
terminal_async.println(get_info_message().to_string()).await;
loop {
select! {
_ = interval_1_task.tick() => {
task_1::tick(&mut state, &mut terminal_async.clone_shared_writer())?;
},
_ = interval_2_task.tick() => {
task_2::tick(&mut state, &mut terminal_async.clone_shared_writer())?;
},
user_input = terminal_async.get_readline_event() => match user_input {
Ok(readline_event) => {
let continuation = process_input_event::process_readline_event(
readline_event, &mut state, &mut terminal_async.clone_shared_writer(), &mut terminal_async.readline
)?;
if let ControlFlow::Break(_) = continuation { break }
},
Err(err) => {
let msg_1 = format!("Received err: {}", format!("{:?}",err).red());
let msg_2 = format!("{}", "Exiting...".red());
terminal_async.println(msg_1).await;
terminal_async.println(msg_2).await;
break;
},
}
}
}
// Flush all writers to stdout
let _ = terminal_async.flush().await;
Ok(())
}
/// This task simply uses [writeln] and [SharedWriter] to print to stdout.
mod task_1 {
use super::*;
pub fn tick(state: &mut State, stdout: &mut SharedWriter) -> miette::Result<()> {
if !state.task_1_state.is_running {
return Ok(());
};
let counter_1 = state.task_1_state.counter;
writeln!(stdout, "[{counter_1}] First interval went off!").into_diagnostic()?;
state.task_1_state.counter += 1;
Ok(())
}
}
/// This task uses [tracing] to log to stdout (via [SharedWriter]).
mod task_2 {
use super::*;
pub fn tick(state: &mut State, _stdout: &mut SharedWriter) -> miette::Result<()> {
if !state.task_2_state.is_running {
return Ok(());
};
let counter_2 = state.task_2_state.counter;
info!("[{counter_2}] Second interval went off!");
state.task_2_state.counter += 1;
Ok(())
}
}
mod process_input_event {
use std::str::FromStr;
use super::*;
pub fn process_readline_event(
readline_event: ReadlineEvent,
state: &mut State,
shared_writer: &mut SharedWriter,
readline: &mut Readline,
) -> miette::Result<ControlFlow<()>> {
match readline_event {
ReadlineEvent::Line(user_input) => {
process_user_input(user_input, state, shared_writer, readline)
}
ReadlineEvent::Eof => {
writeln!(shared_writer, "{}", "Exiting due to Eof...".red().bold())
.into_diagnostic()?;
Ok(ControlFlow::Break(()))
}
ReadlineEvent::Interrupted => {
writeln!(
shared_writer,
"{}",
"Exiting due to ^C pressed...".red().bold()
)
.into_diagnostic()?;
Ok(ControlFlow::Break(()))
}
ReadlineEvent::Resized => {
writeln!(shared_writer, "{}", "Terminal resized!".yellow()).into_diagnostic()?;
Ok(ControlFlow::Continue(()))
}
}
}
fn process_user_input(
user_input: String,
state: &mut State,
shared_writer: &mut SharedWriter,
readline: &mut Readline,
) -> miette::Result<ControlFlow<()>> {
// Add to history.
let line = user_input.trim();
readline.add_history_entry(line.to_string());
// Convert line to command. And process it.
let result_command = Command::from_str(&line.trim().to_lowercase());
match result_command {
Err(_) => {
writeln!(shared_writer, "Unknown command!").into_diagnostic()?;
return Ok(ControlFlow::Continue(()));
}
Ok(command) => match command {
Command::Exit => {
writeln!(shared_writer, "{}", "Exiting due to exit command...".red())
.into_diagnostic()?;
readline.close();
return Ok(ControlFlow::Break(()));
}
Command::StartTask1 => {
state.task_1_state.is_running = true;
writeln!(
shared_writer,
"First task started! This prints to SharedWriter."
)
.into_diagnostic()?;
}
Command::StopTask1 => {
state.task_1_state.is_running = false;
writeln!(shared_writer, "First task stopped!").into_diagnostic()?;
}
Command::StartTask2 => {
state.task_2_state.is_running = true;
writeln!(
shared_writer,
"Second task started! This generates logs which print to DisplayPreference (SharedWriter) and file."
)
.into_diagnostic()?;
}
Command::StopTask2 => {
state.task_2_state.is_running = false;
writeln!(shared_writer, "Second task stopped!").into_diagnostic()?;
}
Command::StartPrintouts => {
writeln!(shared_writer, "Printouts started!").into_diagnostic()?;
readline.should_print_line_on(true, true);
}
Command::StopPrintouts => {
writeln!(shared_writer, "Printouts stopped!").into_diagnostic()?;
readline.should_print_line_on(false, false);
}
Command::Info => {
writeln!(shared_writer, "{}", get_info_message()).into_diagnostic()?;
}
Command::Spinner => {
writeln!(shared_writer, "Spinner started! Pausing terminal...")
.into_diagnostic()?;
long_running_task::spawn_task_that_shows_spinner(
shared_writer,
"Spinner task",
Duration::from_millis(100),
);
}
Command::Tree => {
let mut shared_writer_clone = shared_writer.clone();
tokio::spawn(async move {
let mut_shared_writer = &mut shared_writer_clone;
match file_walker::get_current_working_directory() {
Ok((root_path, _)) => {
match file_walker::display_tree(root_path, mut_shared_writer, true)
.await
{
Ok(_) => {}
Err(_) => todo!(),
};
}
Err(_) => todo!(),
}
});
}
},
}
Ok(ControlFlow::Continue(()))
}
source§impl Readline
impl Readline
sourcepub fn close(&mut self)
pub fn close(&mut self)
Call this to shutdown:
pause_and_resume_support::spawn_task_to_monitor_line_channel()
.Readline::readline()
only if it is currently running.
Typically this happens when your CLI wants to exit, due to some user input requesting this. This will result in any awaiting tasks in various places to error out, which is the desired behavior, rather than just hanging, waiting on events that will never happen.
Examples found in repository?
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
fn process_user_input(
user_input: String,
state: &mut State,
shared_writer: &mut SharedWriter,
readline: &mut Readline,
) -> miette::Result<ControlFlow<()>> {
// Add to history.
let line = user_input.trim();
readline.add_history_entry(line.to_string());
// Convert line to command. And process it.
let result_command = Command::from_str(&line.trim().to_lowercase());
match result_command {
Err(_) => {
writeln!(shared_writer, "Unknown command!").into_diagnostic()?;
return Ok(ControlFlow::Continue(()));
}
Ok(command) => match command {
Command::Exit => {
writeln!(shared_writer, "{}", "Exiting due to exit command...".red())
.into_diagnostic()?;
readline.close();
return Ok(ControlFlow::Break(()));
}
Command::StartTask1 => {
state.task_1_state.is_running = true;
writeln!(
shared_writer,
"First task started! This prints to SharedWriter."
)
.into_diagnostic()?;
}
Command::StopTask1 => {
state.task_1_state.is_running = false;
writeln!(shared_writer, "First task stopped!").into_diagnostic()?;
}
Command::StartTask2 => {
state.task_2_state.is_running = true;
writeln!(
shared_writer,
"Second task started! This generates logs which print to DisplayPreference (SharedWriter) and file."
)
.into_diagnostic()?;
}
Command::StopTask2 => {
state.task_2_state.is_running = false;
writeln!(shared_writer, "Second task stopped!").into_diagnostic()?;
}
Command::StartPrintouts => {
writeln!(shared_writer, "Printouts started!").into_diagnostic()?;
readline.should_print_line_on(true, true);
}
Command::StopPrintouts => {
writeln!(shared_writer, "Printouts stopped!").into_diagnostic()?;
readline.should_print_line_on(false, false);
}
Command::Info => {
writeln!(shared_writer, "{}", get_info_message()).into_diagnostic()?;
}
Command::Spinner => {
writeln!(shared_writer, "Spinner started! Pausing terminal...")
.into_diagnostic()?;
long_running_task::spawn_task_that_shows_spinner(
shared_writer,
"Spinner task",
Duration::from_millis(100),
);
}
Command::Tree => {
let mut shared_writer_clone = shared_writer.clone();
tokio::spawn(async move {
let mut_shared_writer = &mut shared_writer_clone;
match file_walker::get_current_working_directory() {
Ok((root_path, _)) => {
match file_walker::display_tree(root_path, mut_shared_writer, true)
.await
{
Ok(_) => {}
Err(_) => todo!(),
};
}
Err(_) => todo!(),
}
});
}
},
}
Ok(ControlFlow::Continue(()))
}
Trait Implementations§
source§impl Drop for Readline
impl Drop for Readline
Exit raw mode when the instance is dropped.
source§fn drop(&mut self)
fn drop(&mut self)
There is no need to explicitly call Readline::close() if the instance is dropped, since it will close the shutdown channel and the task
pause_and_resume_support::spawn_task_to_monitor_line_channel
.Readline::readline
if it is currently running.- See also:
Readline::close
.
Auto Trait Implementations§
impl Freeze for Readline
impl !RefUnwindSafe for Readline
impl !Send for Readline
impl !Sync for Readline
impl Unpin for Readline
impl !UnwindSafe for Readline
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> FutureExt for T
impl<T> FutureExt for T
source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T
in a tonic::Request
source§impl<D> OwoColorize for D
impl<D> OwoColorize for D
source§fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>where
C: Color,
fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>where
C: Color,
source§fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>where
C: Color,
fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>where
C: Color,
source§fn black(&self) -> FgColorDisplay<'_, Black, Self>
fn black(&self) -> FgColorDisplay<'_, Black, Self>
source§fn on_black(&self) -> BgColorDisplay<'_, Black, Self>
fn on_black(&self) -> BgColorDisplay<'_, Black, Self>
source§fn red(&self) -> FgColorDisplay<'_, Red, Self>
fn red(&self) -> FgColorDisplay<'_, Red, Self>
source§fn on_red(&self) -> BgColorDisplay<'_, Red, Self>
fn on_red(&self) -> BgColorDisplay<'_, Red, Self>
source§fn green(&self) -> FgColorDisplay<'_, Green, Self>
fn green(&self) -> FgColorDisplay<'_, Green, Self>
source§fn on_green(&self) -> BgColorDisplay<'_, Green, Self>
fn on_green(&self) -> BgColorDisplay<'_, Green, Self>
source§fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>
fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>
source§fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>
fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>
source§fn blue(&self) -> FgColorDisplay<'_, Blue, Self>
fn blue(&self) -> FgColorDisplay<'_, Blue, Self>
source§fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>
fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>
source§fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>
fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>
source§fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>
fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>
source§fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>
fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>
source§fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>
fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>
source§fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>
fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>
source§fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>
fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>
source§fn white(&self) -> FgColorDisplay<'_, White, Self>
fn white(&self) -> FgColorDisplay<'_, White, Self>
source§fn on_white(&self) -> BgColorDisplay<'_, White, Self>
fn on_white(&self) -> BgColorDisplay<'_, White, Self>
source§fn default_color(&self) -> FgColorDisplay<'_, Default, Self>
fn default_color(&self) -> FgColorDisplay<'_, Default, Self>
source§fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>
fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>
source§fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>
fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>
source§fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>
fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>
source§fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>
fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>
source§fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>
fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>
source§fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>
fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>
source§fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>
fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>
source§fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>
fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>
source§fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>
fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>
source§fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>
fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>
source§fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>
fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>
source§fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
source§fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
source§fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
source§fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
source§fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>
fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>
source§fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>
fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>
source§fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>
fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>
source§fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>
fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>
source§fn bold(&self) -> BoldDisplay<'_, Self>
fn bold(&self) -> BoldDisplay<'_, Self>
source§fn dimmed(&self) -> DimDisplay<'_, Self>
fn dimmed(&self) -> DimDisplay<'_, Self>
source§fn italic(&self) -> ItalicDisplay<'_, Self>
fn italic(&self) -> ItalicDisplay<'_, Self>
source§fn underline(&self) -> UnderlineDisplay<'_, Self>
fn underline(&self) -> UnderlineDisplay<'_, Self>
source§fn blink(&self) -> BlinkDisplay<'_, Self>
fn blink(&self) -> BlinkDisplay<'_, Self>
source§fn blink_fast(&self) -> BlinkFastDisplay<'_, Self>
fn blink_fast(&self) -> BlinkFastDisplay<'_, Self>
source§fn reversed(&self) -> ReversedDisplay<'_, Self>
fn reversed(&self) -> ReversedDisplay<'_, Self>
source§fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>
fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>
source§fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
OwoColorize::fg
or
a color-specific method, such as OwoColorize::green
, Read moresource§fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
OwoColorize::bg
or
a color-specific method, such as OwoColorize::on_yellow
, Read more