pub struct Readline {
pub output_device: OutputDevice,
pub input_device: InputDevice,
pub safe_line_state: SafeLineState,
pub history_sender: UnboundedSender<String>,
pub history_receiver: UnboundedReceiver<String>,
pub safe_history: SafeHistory,
pub safe_is_paused_buffer: SafePauseBuffer,
pub safe_spinner_is_active: Arc<StdMutex<Option<Sender<()>>>>,
}
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
SharedWriter
s). 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 SharedWriter
s 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_state_control_channel_sender
.
When you create a new Readline
instance, a task, is started via
manage_shared_writer_output::spawn_task_to_monitor_line_state_signals()
. 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 to terminate the session
There is no close()
function on Readline
. You simply drop it. This will cause
the the terminal to come out of raw mode. And all the buffers will be flushed.
However, there are 2 ways to use this Readline::readline()
in a loop or just as a
one off. Each time this function is called, you have to await
it to return the user
input or Interrupted
or Eof
signal.
When creating a new crate::TerminalAsync
instance, you can use this repeatedly
before dropping it. This is because the r3bl_core::SharedWriter
is cloned, and the
terminal is kept in raw mode until the associated crate::Readline
is dropped.
§Inputs and dependency injection
There are 2 main resources that must be passed into Self::new()
:
InputDevice
which contains a resource that implementsr3bl_core::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.OutputDevice
which contains a resources that implementscrate::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. The user input from the terminal is not going
to be accepted either. Only Ctrl+C, and Ctrl+D are accepted while paused. This ensures
that the user can’t enter any input while the terminal is paused. And output from a
crate::Spinner
won’t clobber the output from the SharedWriter
s or from the
user input prompt while crate::Readline::readline()
(or
crate::TerminalAsync::get_readline_event
) is being awaited.
When the terminal is resumed, then the output from the SharedWriter
s will be
printed to the terminal by the manage_shared_writer_output::flush_internal()
method, which drains a buffer that holds any output that was generated while paused,
of type PauseBuffer
. The user input prompt will be displayed again, and the user
can enter input.
This is possible, because while paused, the
manage_shared_writer_output::process_line_control_signal()
method doesn’t actually
print anything to the display. When resumed, the
manage_shared_writer_output::flush_internal()
method is called, which drains the
PauseBuffer
(if there are any messages in it, and prints them out) so nothing is
lost!
See the crate::LineState
for more information on exactly how the terminal is
paused and resumed, when it comes to accepting or rejecting user input, and rendering
output or not.
See the crate::TerminalAsync
module docs for more information on the mental mode
and architecture of this.
§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
manage_shared_writer_output::flush_internal()
.
You can provide your own implementation of crate::SafeRawTerminal
, like
OutputDevice
, 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
compiles with dyn std::io::Write + Send
trait bounds can be used.
Fields§
§output_device: OutputDevice
Device used to write rendered display output to (usually stdout
).
input_device: InputDevice
Device used to get stream of events from user (usually stdin
).
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_buffer: SafePauseBuffer
Collects lines that are written to the terminal while the terminal is paused.
safe_spinner_is_active: Arc<StdMutex<Option<Sender<()>>>>
- Is Some if a crate::Spinner is currently active. This works with the signal LineStateControlSignal::SpinnerActive; this is used to set the crate::Spinner::shutdown_sender. Also works with the LineStateControlSignal::Pause signal.
- Is None if no crate::Spinner is active. Also works with the LineStateControlSignal::Resume signal.
Implementations§
Source§impl Readline
impl Readline
Sourcepub fn new(
prompt: String,
output_device: OutputDevice,
input_device: InputDevice,
) -> Result<(Self, SharedWriter), ReadlineError>
pub fn new( prompt: String, output_device: OutputDevice, input_device: InputDevice, ) -> 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.
The default value for this is true
.
control_c
similarly controls the behavior for when the user presses Ctrl-C.
The default value for this is false
.
Examples found in repository?
262 pub fn process(
263 user_input: String,
264 state: &mut State,
265 shared_writer: &mut SharedWriter,
266 readline: &mut Readline,
267 ) -> miette::Result<ControlFlow<()>> {
268 // Add to history.
269 let line = user_input.trim();
270 readline.add_history_entry(line.to_string());
271
272 // Convert line to command. And process it.
273 let result_command = Command::from_str(&line.trim().to_lowercase());
274 match result_command {
275 Err(_) => {
276 writeln!(shared_writer, "Unknown command!").into_diagnostic()?;
277 return Ok(ControlFlow::Continue(()));
278 }
279 Ok(command) => match command {
280 Command::Exit => {
281 return Ok(ControlFlow::Break(()));
282 }
283 Command::StartTask1 => {
284 state.task_1_state.is_running = true;
285 writeln!(
286 shared_writer,
287 "First task started! This prints to SharedWriter."
288 )
289 .into_diagnostic()?;
290 }
291 Command::StopTask1 => {
292 state.task_1_state.is_running = false;
293 writeln!(shared_writer, "First task stopped!").into_diagnostic()?;
294 }
295 Command::StartTask2 => {
296 state.task_2_state.is_running = true;
297 writeln!(
298 shared_writer,
299 "Second task started! This generates logs which print to DisplayPreference (SharedWriter) and file."
300 )
301 .into_diagnostic()?;
302 }
303 Command::StopTask2 => {
304 state.task_2_state.is_running = false;
305 writeln!(shared_writer, "Second task stopped!").into_diagnostic()?;
306 }
307 Command::StartPrintouts => {
308 writeln!(shared_writer, "Printouts started!").into_diagnostic()?;
309 readline.should_print_line_on(true, true);
310 }
311 Command::StopPrintouts => {
312 writeln!(shared_writer, "Printouts stopped!").into_diagnostic()?;
313 readline.should_print_line_on(false, false);
314 }
315 Command::Info => {
316 writeln!(shared_writer, "{}", get_info_message())
317 .into_diagnostic()?;
318 }
319 Command::Spinner => {
320 writeln!(shared_writer, "Spinner started! Pausing terminal...")
321 .into_diagnostic()?;
322 long_running_task::spawn_task_that_shows_spinner(
323 shared_writer,
324 readline,
325 "Spinner task",
326 Duration::from_millis(100),
327 );
328 }
329 Command::Tree => {
330 let mut shared_writer_clone = shared_writer.clone();
331 tokio::spawn(async move {
332 let mut_shared_writer = &mut shared_writer_clone;
333 match file_walker::get_current_working_directory() {
334 Ok((root_path, _)) => {
335 match file_walker::display_tree(
336 root_path,
337 mut_shared_writer,
338 true,
339 )
340 .await
341 {
342 Ok(_) => {}
343 Err(_) => todo!(),
344 };
345 }
346 Err(_) => todo!(),
347 }
348 });
349 }
350 },
351 }
352
353 Ok(ControlFlow::Continue(()))
354 }
Sourcepub async fn readline(&mut self) -> Result<ReadlineEvent, ReadlineError>
pub async fn readline(&mut self) -> Result<ReadlineEvent, ReadlineError>
This function returns when Ctrl+D, Ctrl+C, or Enter is pressed with some user input.
Note that this function can be called repeatedly in a loop. It will return each line of input as it is entered (and return / exit). The crate::TerminalAsync can be re-used, since the r3bl_core::SharedWriter is cloned and the terminal is kept in raw mode until the associated crate::Readline is dropped.
Polling function for Self::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?
138async fn main() -> miette::Result<()> {
139 let prompt = {
140 let prompt_seg_1 = "╭>╮".magenta().on_dark_grey().to_string();
141 let prompt_seg_2 = " ".to_string();
142 format!("{}{}", prompt_seg_1, prompt_seg_2)
143 };
144
145 let maybe_terminal_async = TerminalAsync::try_new(prompt.as_str()).await?;
146
147 // If the terminal is not fully interactive, then return early.
148 let Some(mut terminal_async) = maybe_terminal_async else {
149 return Ok(());
150 };
151
152 // Pre-populate the readline's history with some entries.
153 for command in Command::iter() {
154 terminal_async
155 .readline
156 .add_history_entry(command.to_string());
157 }
158
159 // Initialize tracing w/ the "async stdout" (SharedWriter), and file writer.
160 TracingConfig::new_file_and_display(
161 None,
162 DisplayPreference::SharedWriter(terminal_async.clone_shared_writer()),
163 )
164 .install_global()?;
165
166 // Start tasks.
167 let mut state = State::default();
168 let mut interval_1_task = interval(state.task_1_state.interval_delay);
169 let mut interval_2_task = interval(state.task_2_state.interval_delay);
170
171 terminal_async.println(get_info_message().to_string()).await;
172
173 loop {
174 select! {
175 _ = interval_1_task.tick() => {
176 task_1::tick(&mut state, &mut terminal_async.clone_shared_writer())?;
177 },
178 _ = interval_2_task.tick() => {
179 task_2::tick(&mut state, &mut terminal_async.clone_shared_writer())?;
180 },
181 result_readline_event = terminal_async.get_readline_event() => {
182 match result_readline_event {
183 Ok(readline_event) => {
184 match readline_event {
185 // User input event.
186 ReadlineEvent::Line(user_input) => {
187 let mut_state = &mut state;
188 let shared_writer = &mut terminal_async.clone_shared_writer();
189 let readline = &mut terminal_async.readline;
190 let control_flow = process_input_event::process(
191 user_input, mut_state, shared_writer, readline)?;
192 if let ControlFlow::Break(_) = control_flow {
193 break;
194 }
195 }
196 // Resize event.
197 ReadlineEvent::Resized => {
198 let shared_writer = &mut terminal_async.clone_shared_writer();
199 writeln!(shared_writer, "{}", "Terminal resized!".yellow()).into_diagnostic()?;
200 }
201 // Ctrl+D, Ctrl+C.
202 ReadlineEvent::Eof | ReadlineEvent::Interrupted => {
203 break;
204 }
205 }
206 },
207 Err(err) => {
208 let msg_1 = format!("Received err: {}", format!("{:?}",err).red());
209 let msg_2 = format!("{}", "Exiting...".red());
210 terminal_async.println(msg_1).await;
211 terminal_async.println(msg_2).await;
212 break;
213 },
214 }
215 }
216 }
217 }
218
219 // There's no need to close terminal_async or readline. Drop will take care of
220 // cleaning up (closing raw mode).
221
222 Ok(())
223}
224
225/// This task simply uses [writeln] and [SharedWriter] to print to stdout.
226mod task_1 {
227 use super::*;
228
229 pub fn tick(state: &mut State, stdout: &mut SharedWriter) -> miette::Result<()> {
230 if !state.task_1_state.is_running {
231 return Ok(());
232 };
233
234 let counter_1 = state.task_1_state.counter;
235 writeln!(stdout, "[{counter_1}] First interval went off!").into_diagnostic()?;
236 state.task_1_state.counter += 1;
237
238 Ok(())
239 }
240}
241
242/// This task uses [tracing] to log to stdout (via [SharedWriter]).
243mod task_2 {
244 use super::*;
245
246 pub fn tick(state: &mut State, _stdout: &mut SharedWriter) -> miette::Result<()> {
247 if !state.task_2_state.is_running {
248 return Ok(());
249 };
250
251 let counter_2 = state.task_2_state.counter;
252 info!("[{counter_2}] Second interval went off!");
253 state.task_2_state.counter += 1;
254
255 Ok(())
256 }
257}
258
259mod process_input_event {
260 use super::*;
261
262 pub fn process(
263 user_input: String,
264 state: &mut State,
265 shared_writer: &mut SharedWriter,
266 readline: &mut Readline,
267 ) -> miette::Result<ControlFlow<()>> {
268 // Add to history.
269 let line = user_input.trim();
270 readline.add_history_entry(line.to_string());
271
272 // Convert line to command. And process it.
273 let result_command = Command::from_str(&line.trim().to_lowercase());
274 match result_command {
275 Err(_) => {
276 writeln!(shared_writer, "Unknown command!").into_diagnostic()?;
277 return Ok(ControlFlow::Continue(()));
278 }
279 Ok(command) => match command {
280 Command::Exit => {
281 return Ok(ControlFlow::Break(()));
282 }
283 Command::StartTask1 => {
284 state.task_1_state.is_running = true;
285 writeln!(
286 shared_writer,
287 "First task started! This prints to SharedWriter."
288 )
289 .into_diagnostic()?;
290 }
291 Command::StopTask1 => {
292 state.task_1_state.is_running = false;
293 writeln!(shared_writer, "First task stopped!").into_diagnostic()?;
294 }
295 Command::StartTask2 => {
296 state.task_2_state.is_running = true;
297 writeln!(
298 shared_writer,
299 "Second task started! This generates logs which print to DisplayPreference (SharedWriter) and file."
300 )
301 .into_diagnostic()?;
302 }
303 Command::StopTask2 => {
304 state.task_2_state.is_running = false;
305 writeln!(shared_writer, "Second task stopped!").into_diagnostic()?;
306 }
307 Command::StartPrintouts => {
308 writeln!(shared_writer, "Printouts started!").into_diagnostic()?;
309 readline.should_print_line_on(true, true);
310 }
311 Command::StopPrintouts => {
312 writeln!(shared_writer, "Printouts stopped!").into_diagnostic()?;
313 readline.should_print_line_on(false, false);
314 }
315 Command::Info => {
316 writeln!(shared_writer, "{}", get_info_message())
317 .into_diagnostic()?;
318 }
319 Command::Spinner => {
320 writeln!(shared_writer, "Spinner started! Pausing terminal...")
321 .into_diagnostic()?;
322 long_running_task::spawn_task_that_shows_spinner(
323 shared_writer,
324 readline,
325 "Spinner task",
326 Duration::from_millis(100),
327 );
328 }
329 Command::Tree => {
330 let mut shared_writer_clone = shared_writer.clone();
331 tokio::spawn(async move {
332 let mut_shared_writer = &mut shared_writer_clone;
333 match file_walker::get_current_working_directory() {
334 Ok((root_path, _)) => {
335 match file_walker::display_tree(
336 root_path,
337 mut_shared_writer,
338 true,
339 )
340 .await
341 {
342 Ok(_) => {}
343 Err(_) => todo!(),
344 };
345 }
346 Err(_) => todo!(),
347 }
348 });
349 }
350 },
351 }
352
353 Ok(ControlFlow::Continue(()))
354 }
Trait Implementations§
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> 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<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