diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index a468c02..8eb3ebc 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -1,4 +1,9 @@ //! Virtual text console. +//! +//! The [`Console`] works as a virtual shell that renders on screen all output of `stdout`. As such, it is useful as a basic interface to show info to the user, +//! such as in simple "Hello World" applications or more complex software that does not need much user interaction. +//! +//! Have a look at [`Soc::redirect_to_3dslink()`](crate::services::soc::Soc::redirect_to_3dslink) for a better alternative when debugging applications. use std::cell::RefMut; use std::default::Default; @@ -9,10 +14,10 @@ use crate::services::gfx::Screen; static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintConsole) }; -/// Virtual printable console. +/// Virtual text console. /// /// [`Console`] lets the application redirect `stdout` to a simple text displayer on the 3DS screen. -/// This means that any text written to `stdout` (e.g. using [`println!`] or [`dbg!`]) will become visible in the area taken by the console. +/// This means that any text written to `stdout` (e.g. using `println!` or `dbg!`) will become visible in the area taken by the console. /// /// # Notes /// @@ -20,7 +25,7 @@ static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintC /// /// # Alternatives /// -/// If you'd like to see live `stdout` output while running the application but can't/don't want to show the text on the 3DS itself, +/// If you'd like to see live `stdout` output while running the application but cannnot/do not want to show the text on the 3DS itself, /// you can try using [`Soc::redirect_to_3dslink`](crate::services::soc::Soc::redirect_to_3dslink) while activating the `--server` flag for `3dslink` (also supported by `cargo-3ds`). /// More info in the `cargo-3ds` docs. #[doc(alias = "PrintConsole")] @@ -30,13 +35,37 @@ pub struct Console<'screen> { } impl<'screen> Console<'screen> { - /// Initialize a console on the chosen screen, overwriting whatever was on the screen - /// previously (including other consoles). The new console is automatically selected for - /// printing. + /// Initialize a console on the chosen screen. /// /// # Notes /// + /// This operation overwrites whatever was on the screen before the inizialization (including other [`Console`]s) + /// and changes the [`FramebufferFormat`](crate::services::gspgpu::FramebufferFormat) of the selected screen to better suit the [`Console`]. + /// + /// The new console is automatically selected for printing. + /// /// [`Console`] automatically takes care of flushing and swapping buffers for its screen when printing. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// use ctru::services::gfx::Gfx; + /// use ctru::console::Console; + /// + /// // Initialize graphics. + /// let gfx = Gfx::new()?; + /// + /// // Create a `Console` that takes control of the upper LCD screen. + /// let top_console = Console::new(gfx.top_screen.borrow_mut()); + /// + /// println!("I'm on the top screen!"); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "consoleInit")] pub fn new(screen: RefMut<'screen, dyn Screen>) -> Self { let mut context = Box::::default(); @@ -49,7 +78,35 @@ impl<'screen> Console<'screen> { } } - /// Returns true if a valid Console to print on is selected + /// Returns `true` if a valid [`Console`] to print on is currently selected. + /// + /// # Notes + /// + /// This function is used to check whether one of the two screens has an existing (and selected) [`Console`], + /// so that the program can be sure its output will be shown *somewhere*. + /// + /// The main use of this is within the [`ctru::use_panic_handler()`](crate::use_panic_handler()) hook, + /// since it will only stop the program's execution if the user is able to see the panic information output on screen. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// # use ctru::services::gfx::Gfx; + /// # // Initialize graphics. + /// # let gfx = Gfx::new()?; + /// # + /// use ctru::console::Console; + /// let top_console = Console::new(gfx.top_screen.borrow_mut()); + /// + /// // There is at least one selected `Console`. + /// assert!(Console::exists()); + /// # + /// # Ok(()) + /// # } + /// ``` pub fn exists() -> bool { unsafe { let current_console = ctru_sys::consoleSelect(&mut EMPTY_CONSOLE); @@ -62,7 +119,39 @@ impl<'screen> Console<'screen> { } } - /// Select this console as the current target for stdout + /// Select this console as the current target for `stdout`. + /// + /// # Notes + /// + /// Any previously selected console will be unhooked and will not show the `stdout` output. + /// + /// # Example + /// + /// ```no_run + /// # use std::error::Error; + /// # fn main() -> Result<(), Box> { + /// # + /// # use ctru::services::gfx::Gfx; + /// # let gfx = Gfx::new()?; + /// # + /// use ctru::console::Console; + /// + /// // Create a `Console` that takes control of the upper LCD screen. + /// let top_console = Console::new(gfx.top_screen.borrow_mut()); + /// + /// // Create a `Console` that takes control of the lower LCD screen. + /// let bottom_console = Console::new(gfx.bottom_screen.borrow_mut()); + /// + /// // Remember that `Console::new` automatically selects the new `Console` for ouput. + /// println!("I'm on the bottom screen!"); + /// + /// top_console.select(); + /// + /// println!("Being on the upper screen is much better!"); + /// # + /// # Ok(()) + /// # } + /// ``` #[doc(alias = "consoleSelect")] pub fn select(&self) { unsafe { @@ -70,20 +159,24 @@ impl<'screen> Console<'screen> { } } - /// Clears all text from the console + /// Clear all text from the console. #[doc(alias = "consoleClear")] pub fn clear(&self) { unsafe { consoleClear() } } - /// Resizes the active console to fit in a smaller portion of the screen. + /// Resize the console to fit in a smaller portion of the screen. + /// + /// # Notes /// /// The first two arguments are the desired coordinates of the top-left corner - /// of the console, and the second pair is the new width and height + /// of the console, and the second pair is the new width and height. /// /// # Safety - /// This function is unsafe because it does not validate that the input will produce - /// a console that actually fits on the screen + /// + /// This function is unsafe because it does not validate whether the input will produce + /// a console that actually fits on the screen. + // TODO: Wrap this safely. #[doc(alias = "consoleSetWindow")] pub unsafe fn set_window(&mut self, x: i32, y: i32, width: i32, height: i32) { consoleSetWindow(self.context.as_mut(), x, y, width, height); diff --git a/ctru-rs/src/services/soc.rs b/ctru-rs/src/services/soc.rs index f9cc258..00a7a5c 100644 --- a/ctru-rs/src/services/soc.rs +++ b/ctru-rs/src/services/soc.rs @@ -113,7 +113,10 @@ impl Soc { Ipv4Addr::from(raw_id.to_ne_bytes()) } - /// Redirect output streams (i.e. `println` and `eprintln`) to the `3dslink` server. + /// Redirect output streams (i.e. `stdout` and `stderr`) to the `3dslink` server. + /// + /// With this redirection it is possible to send (and view in real time) the output of `stdout` operations, + /// such as `println!` or `dbg!`. /// /// Requires `3dslink` >= 0.6.1 and `new-hbmenu` >= 2.3.0 and the use of the `--server` flag. /// The `--server` flag is also availble to use via `cargo-3ds` if the requirements are met.