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 SharedWriters. 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():

  1. PinnedInputStream - This trait represents an async stream of events. It is typically implemented by crossterm::event::EventStream. This is used to get input from the user. However for testing you can provide your own implementation of this trait.
  2. SafeRawTerminal - This trait represents a raw terminal. It is typically implemented by std::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 SharedWriters 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 SharedWriters 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:

  1. While retrieving input with readline().
  2. 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 SharedWriters 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:

  1. pause_and_resume_support::spawn_task_to_monitor_line_channel.
  2. Readline::readline if it is currently running.
  3. Also see: Readline::close.

Implementations§

source§

impl Readline

source

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:

source

pub fn update_prompt(&mut self, prompt: &str) -> Result<(), ReadlineError>

Change the prompt.

source

pub fn clear(&mut self) -> Result<(), ReadlineError>

Clear the screen.

source

pub fn set_max_history(&mut self, max_size: usize)

Set maximum history length. The default length is crate::HISTORY_SIZE_MAX.

source

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?
examples/terminal_async.rs (line 305)
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(()))
    }
source

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.

source

pub fn add_history_entry(&mut self, entry: String) -> Option<()>

Add a line to the input history.

Examples found in repository?
examples/terminal_async.rs (line 138)
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

source

pub fn close(&mut self)

Call this to shutdown:

  1. pause_and_resume_support::spawn_task_to_monitor_line_channel().
  2. 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?
examples/terminal_async.rs (line 276)
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

Exit raw mode when the instance is dropped.

source§

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

  1. pause_and_resume_support::spawn_task_to_monitor_line_channel.
  2. Readline::readline if it is currently running.
  3. See also: Readline::close.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> FutureExt for T

source§

fn with_context(self, otel_cx: Context) -> WithContext<Self>

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
source§

fn with_current_context(self) -> WithContext<Self>

Attaches the current Context to this type, returning a WithContext wrapper. Read more
source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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 more
source§

impl<T> IntoRequest<T> for T

source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
source§

impl<D> OwoColorize for D

source§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where C: Color,

Set the foreground color generically Read more
source§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where C: Color,

Set the background color generically. Read more
source§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
source§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
source§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
source§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
source§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
source§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
source§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
source§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
source§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
source§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
source§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
source§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
source§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
source§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
source§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
source§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
source§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
source§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
source§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
source§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
source§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
source§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
source§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
source§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
source§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
source§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
source§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
source§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
source§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
source§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
source§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
source§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
source§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
source§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
source§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
source§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
source§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
source§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
source§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
source§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
source§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
source§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text italicized
Make the text blink
Make the text blink (but fast!)
source§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
source§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
source§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
source§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at compile-time. If the color is constant, use either OwoColorize::fg or a color-specific method, such as OwoColorize::green, Read more
source§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at compile-time. If the color is constant, use either OwoColorize::bg or a color-specific method, such as OwoColorize::on_yellow, Read more
source§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( &self ) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
source§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( &self ) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
source§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
source§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
source§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

source§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more