From d4067bb001b33fc27fb4ece19e12584a0dfb33dc Mon Sep 17 00:00:00 2001 From: Mahesh Asolkar Date: Wed, 30 Jul 2025 22:06:18 -0700 Subject: [PATCH] Had AI add code documentation/comments --- src/main.rs | 132 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 117 insertions(+), 15 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7d9d018..3276896 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,19 +16,38 @@ use ratatui::{ use ratatui::backend::CrosstermBackend; use std::{io, time::Duration}; -/// Application state +/// Main application state holding all the data needed for the TUI struct App { + /// MPD client connection for interacting with the music player daemon client: Client, + /// Currently playing song, if any current_song: Option, + /// List of songs in the current playlist, deduplicated by file path playlist: Vec, + /// Current MPD server status including playback state, volume, etc. status: mpd::Status, - selected_index: usize, // Currently selected song in the playlist - scroll_offset: usize, // Offset for playlist scrolling - show_help: bool, // Whether to show the help panel + /// Index of the currently selected song in the playlist (for UI highlighting) + selected_index: usize, + /// Number of items to skip from the start of playlist (for scrolling) + scroll_offset: usize, + /// Whether to display the help overlay + show_help: bool, } impl App { - /// Create a new App instance, connecting to MPD + /// Creates a new application instance and initializes the MPD connection + /// + /// This function: + /// 1. Connects to the MPD server at localhost:6600 + /// 2. Retrieves initial server status + /// 3. Gets the current playlist + /// 4. Gets the currently playing song + /// + /// # Errors + /// + /// Returns an error if: + /// - Cannot connect to MPD server + /// - Failed to retrieve initial state from server fn new() -> Result { let mut client = Client::connect("127.0.0.1:6600")?; let status = client.status()?; @@ -46,7 +65,22 @@ impl App { }) } - /// Refresh the application state from MPD + /// Updates the application state by fetching fresh data from the MPD server + /// + /// This function: + /// 1. Updates the server status (play state, volume, etc) + /// 2. Updates the currently playing song + /// 3. Refreshes the playlist, removing any duplicates + /// 4. Adjusts scroll position to keep selected item visible + /// + /// # Arguments + /// + /// * `playlist_height` - The number of playlist items that can be displayed at once + /// Used to adjust scrolling to keep selected item visible + /// + /// # Errors + /// + /// Returns an error if communication with MPD server fails fn refresh(&mut self, playlist_height: usize) -> Result<(), anyhow::Error> { self.status = self.client.status()?; self.current_song = self.client.currentsong()?; @@ -79,21 +113,33 @@ impl App { Ok(()) } - /// Move selection up, adjusting scroll if necessary + /// Moves the selection cursor up one item in the playlist + /// + /// Will not move past the first item (index 0) fn move_up(&mut self) { if self.selected_index > 0 { self.selected_index -= 1; } } - /// Move selection down, adjusting scroll if necessary + /// Moves the selection cursor down one item in the playlist + /// + /// Will not move past the last item in the playlist fn move_down(&mut self) { if self.selected_index + 1 < self.playlist.len() { self.selected_index += 1; } } - /// Update scroll offset to ensure selected item is visible + /// Adjusts the scroll offset to ensure the selected item remains visible + /// + /// This function handles two cases: + /// 1. Selected item is below visible area -> Scroll down to show it + /// 2. Selected item is above visible area -> Scroll up to show it + /// + /// # Arguments + /// + /// * `height` - Number of items that can be displayed at once fn update_scroll(&mut self, height: usize) { if self.selected_index >= self.scroll_offset + height { self.scroll_offset = self.selected_index.saturating_sub(height) + 1; @@ -103,8 +149,19 @@ impl App { } } +/// Main entry point for the Sonnet MPD client +/// +/// Sets up the terminal UI environment and runs the main application loop. +/// Handles cleanup when the application exits. +/// +/// # Error +/// +/// Returns an error if: +/// - Terminal setup fails +/// - MPD connection fails +/// - Terminal restoration fails fn main() -> anyhow::Result<()> { - // Setup terminal + // Setup terminal in raw mode and alternate screen enable_raw_mode()?; let mut stdout = io::stdout(); execute!(stdout, EnterAlternateScreen)?; @@ -127,9 +184,25 @@ fn main() -> anyhow::Result<()> { Ok(()) } +/// Main application loop handling user input and UI updates +/// +/// This function: +/// 1. Continuously updates the application state +/// 2. Redraws the terminal UI +/// 3. Handles keyboard input events +/// 4. Controls MPD playback based on user commands +/// +/// # Arguments +/// +/// * `terminal` - The terminal interface for rendering +/// * `app` - The application state +/// +/// # Type Parameters +/// +/// * `B` - The terminal backend type (allows for different terminal implementations) fn run_app(terminal: &mut Terminal, app: &mut App) -> anyhow::Result<()> { loop { - // Get the available height for the playlist + // Calculate available height for playlist display let height = terminal.size()?.height.saturating_sub(12) as usize; app.refresh(height)?; @@ -182,7 +255,20 @@ fn run_app(terminal: &mut Terminal, app: &mut App) -> anyhow::Res } } -/// Helper function to create a centered rect using up certain percentage of the available rect +/// Creates a centered rectangle for modal overlays like the help panel +/// +/// This function creates a rectangle that is centered both horizontally and vertically +/// within the given space. The size is specified as percentages of the available space. +/// +/// # Arguments +/// +/// * `percent_x` - Width of the rectangle as a percentage of parent width +/// * `percent_y` - Height of the rectangle as a percentage of parent height +/// * `r` - The parent rectangle within which to center the new rectangle +/// +/// # Returns +/// +/// A new rectangle centered within the parent, with the specified size fn centered_rect(percent_x: u16, percent_y: u16, r: ratatui::layout::Rect) -> ratatui::layout::Rect { // Calculate the width and height of the popup let popup_layout = Layout::default() @@ -204,13 +290,29 @@ fn centered_rect(percent_x: u16, percent_y: u16, r: ratatui::layout::Rect) -> ra .split(popup_layout[1])[1] } +/// Renders the terminal user interface +/// +/// The UI is composed of several sections: +/// - Header: Shows the application title +/// - Status: Displays current playback status and song info +/// - Playlist: Shows the list of songs with selection highlight +/// - Help Panel: Optional overlay showing keyboard shortcuts +/// +/// The layout is organized vertically with fixed heights for header and status, +/// and the playlist taking the remaining space. +/// +/// # Arguments +/// +/// * `f` - Frame for rendering UI elements +/// * `app` - Application state containing all the data to display pub(crate) fn ui(f: &mut Frame, app: &App) { + // Create the main vertical layout let chunks = Layout::default() .direction(Direction::Vertical) .constraints([ - Constraint::Length(3), // Header - Constraint::Length(10), // Status - Constraint::Min(0) // Playlist + Constraint::Length(3), // Header: Fixed 3 lines + Constraint::Length(10), // Status: Fixed 10 lines + Constraint::Min(0) // Playlist: All remaining space ].as_ref()) .split(f.size());