Struct Readline

Source
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 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_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 SharedWriters.

§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():

  1. InputDevice which contains a resource that implements r3bl_core::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. OutputDevice which contains a resources that implements crate::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. 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 SharedWriters 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 SharedWriters 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:

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

Implementations§

Source§

impl Readline

Source

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:

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

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.

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 156)
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§

Source§

impl Drop for Readline

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

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> 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<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 underlined
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> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

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

Source§

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>,

Source§

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