diff --git a/src/tui.rs b/src/tui.rs index c78579f..3199e70 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -7,7 +7,7 @@ mod logger; mod menu_bar; use anyhow::{Context, Result}; -use log::{LevelFilter, debug, info}; +use log::{LevelFilter, debug, info, trace}; use ratatui::Terminal; use ratatui::backend::CrosstermBackend; use ratatui::crossterm::event::{ @@ -28,10 +28,15 @@ pub struct Tui { } impl Tui { + pub fn id() -> &'static str { + "Tui" + } + pub fn new(root_path: std::path::PathBuf) -> Result { + trace!(target:Self::id(), "Building {}", Self::id()); init_logger(LevelFilter::Trace)?; set_default_level(LevelFilter::Trace); - debug!(target:"Tui", "Logging initialized"); + debug!(target:Self::id(), "Logging initialized"); let mut dir = env::temp_dir(); dir.push("clide.log"); @@ -43,7 +48,7 @@ impl Tui { .output_file(false) .output_separator(':'); set_log_file(file_options); - debug!(target:"Tui", "Logging to file: {dir:?}"); + debug!(target:Self::id(), "Logging to file: {dir:?}"); Ok(Self { terminal: Terminal::new(CrosstermBackend::new(stdout()))?, @@ -52,7 +57,7 @@ impl Tui { } pub fn start(self) -> Result<()> { - info!(target:"Tui", "Starting the TUI editor at {:?}", self.root_path); + info!(target:Self::id(), "Starting the TUI editor at {:?}", self.root_path); ratatui::crossterm::execute!( stdout(), EnterAlternateScreen, @@ -69,7 +74,7 @@ impl Tui { } fn stop() -> Result<()> { - info!(target:"Tui", "Stopping the TUI editor"); + info!(target:Self::id(), "Stopping the TUI editor"); disable_raw_mode()?; ratatui::crossterm::execute!( stdout(), diff --git a/src/tui/app.rs b/src/tui/app.rs index 51250c5..661e6ac 100644 --- a/src/tui/app.rs +++ b/src/tui/app.rs @@ -6,7 +6,7 @@ use crate::tui::logger::Logger; use crate::tui::menu_bar::MenuBar; use AppComponent::AppMenuBar; use anyhow::{Context, Result}; -use log::error; +use log::{error, info, trace, warn}; use ratatui::DefaultTerminal; use ratatui::buffer::Buffer; use ratatui::crossterm::event; @@ -22,7 +22,7 @@ use std::time::Duration; // TODO: Need a way to dynamically run Widget::render on all widgets. // TODO: + Need a way to map Rect to Component::id() to position each widget? // TODO: Need a good way to dynamically run Component methods on all widgets. -#[derive(PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum AppComponent { AppEditor, AppExplorer, @@ -44,6 +44,7 @@ impl<'a> App<'a> { } pub fn new(root_path: PathBuf) -> Result { + trace!(target:Self::id(), "Building {}", Self::id()); let app = Self { editor_tabs: EditorTab::new(&root_path), explorer: Explorer::new(&root_path)?, @@ -56,6 +57,7 @@ impl<'a> App<'a> { /// Logic that should be executed once on application startup. pub fn start(&mut self) -> Result<()> { + trace!(target:Self::id(), "Starting App"); let root_path = self.explorer.root_path.clone(); let editor = self .editor_tabs @@ -72,10 +74,8 @@ impl<'a> App<'a> { pub fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> { self.start()?; + trace!(target:Self::id(), "Entering App run loop"); loop { - self.refresh_editor_contents() - .context("Failed to refresh editor contents.")?; - terminal.draw(|f| { f.render_widget(&mut self, f.area()); })?; @@ -122,6 +122,7 @@ impl<'a> App<'a> { } fn change_focus(&mut self, focus: AppComponent) { + info!(target:Self::id(), "Changing widget focus to {:?}", focus); match focus { AppEditor => match self.editor_tabs.current_editor_mut() { None => { @@ -138,6 +139,7 @@ impl<'a> App<'a> { /// Refresh the contents of the editor to match the selected TreeItem in the file Explorer. /// If the selected item is not a file, this does nothing. + #[allow(unused)] fn refresh_editor_contents(&mut self) -> Result<()> { // TODO: This may be useful for a preview mode of the selected file prior to opening a tab. // Use the currently selected TreeItem or get an absolute path to this source file. @@ -242,8 +244,8 @@ impl<'a> Component for App<'a> { Action::Quit | Action::Handled => Ok(action), Action::Save => match editor.save() { Ok(_) => Ok(Action::Handled), - Err(_) => { - error!(target:Self::id(), "Failed to save editor contents"); + Err(e) => { + error!(target:Self::id(), "Failed to save editor contents: {e}"); Ok(Action::Noop) } }, diff --git a/src/tui/component.rs b/src/tui/component.rs index 3e07f9d..8eca3ed 100644 --- a/src/tui/component.rs +++ b/src/tui/component.rs @@ -1,6 +1,7 @@ #![allow(dead_code, unused_variables)] use anyhow::Result; +use log::trace; use ratatui::crossterm::event::{Event, KeyEvent, MouseEvent}; pub enum Action { @@ -55,7 +56,12 @@ pub struct ComponentState { } impl ComponentState { + pub fn id() -> &'static str { + "ComponentState" + } + fn new() -> Self { + trace!(target:Self::id(), "Building {}", Self::id()); Self { focus: Focus::Active, help_text: String::new(), diff --git a/src/tui/editor.rs b/src/tui/editor.rs index b500de8..f927f75 100644 --- a/src/tui/editor.rs +++ b/src/tui/editor.rs @@ -3,6 +3,7 @@ use anyhow::{Context, Result, bail}; use edtui::{ EditorEventHandler, EditorState, EditorTheme, EditorView, LineNumbers, Lines, SyntaxHighlighter, }; +use log::{error, trace}; use ratatui::buffer::Buffer; use ratatui::crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; use ratatui::layout::{Alignment, Rect}; @@ -25,6 +26,7 @@ impl Editor { // TODO: You shouldnt be able to construct the editor without a path? pub fn new() -> Self { + trace!(target:Self::id(), "Building {}", Self::id()); Editor { state: EditorState::default(), event_handler: EditorEventHandler::default(), @@ -38,6 +40,7 @@ impl Editor { } pub fn set_contents(&mut self, path: &std::path::PathBuf) -> Result<()> { + trace!(target:Self::id(), "Setting Editor contents from path {:?}", path); if let Ok(contents) = std::fs::read_to_string(path) { let lines: Vec<_> = contents .lines() @@ -53,8 +56,10 @@ impl Editor { pub fn save(&self) -> Result<()> { if let Some(path) = &self.file_path { + trace!(target:Self::id(), "Saving Editor contents {:?}", path); return std::fs::write(path, self.state.lines.to_string()).map_err(|e| e.into()); }; + error!(target:Self::id(), "Failed saving Editor contents; file_path was None"); bail!("File not saved. No file path set.") } } diff --git a/src/tui/editor_tab.rs b/src/tui/editor_tab.rs index d06d2bc..8cc309a 100644 --- a/src/tui/editor_tab.rs +++ b/src/tui/editor_tab.rs @@ -1,7 +1,7 @@ use crate::tui::component::{Action, Component}; use crate::tui::editor::Editor; use anyhow::{Context, Result}; -use log::trace; +use log::{trace, warn}; use ratatui::buffer::Buffer; use ratatui::crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; use ratatui::layout::Rect; @@ -24,7 +24,7 @@ impl EditorTab { } pub fn new(path: &std::path::PathBuf) -> Self { - trace!(target:Self::id(), "Building EditorTab with path '{path:?}'"); + trace!(target:Self::id(), "Building EditorTab with path {path:?}"); let tab_order = vec![path.to_string_lossy().to_string()]; Self { editors: HashMap::from([(tab_order.first().unwrap().to_owned(), Editor::new())]), @@ -34,14 +34,18 @@ impl EditorTab { } pub fn next_editor(&mut self) { - self.current_editor = (self.current_editor + 1) % self.tab_order.len(); + let next = (self.current_editor + 1) % self.tab_order.len(); + trace!(target:Self::id(), "Moving from {} to next editor tab at {}", self.current_editor, next); + self.current_editor = next; } pub fn prev_editor(&mut self) { - self.current_editor = self + let prev = self .current_editor .checked_sub(1) .unwrap_or(self.tab_order.len() - 1); + trace!(target:Self::id(), "Moving from {} to previous editor tab at {}", self.current_editor, prev); + self.current_editor = prev; } pub fn current_editor(&self) -> Option<&Editor> { @@ -53,10 +57,12 @@ impl EditorTab { } pub fn open_tab(&mut self, path: &std::path::PathBuf) -> Result<()> { + trace!(target:Self::id(), "Opening new EditorTab with path {:?}", path); if self .editors .contains_key(&path.to_string_lossy().to_string()) { + warn!(target:Self::id(), "EditorTab already opened with this file"); return Ok(()); } diff --git a/src/tui/explorer.rs b/src/tui/explorer.rs index a44b9b0..a1e10c0 100644 --- a/src/tui/explorer.rs +++ b/src/tui/explorer.rs @@ -1,5 +1,6 @@ use crate::tui::component::{Action, Component, ComponentState, Focus}; use anyhow::{Context, Result, bail}; +use log::trace; use ratatui::buffer::Buffer; use ratatui::crossterm::event::{Event, KeyCode, KeyEvent, MouseEvent, MouseEventKind}; use ratatui::layout::{Alignment, Position, Rect}; @@ -24,6 +25,7 @@ impl<'a> Explorer<'a> { } pub fn new(path: &PathBuf) -> Result { + trace!(target:Self::id(), "Building {}", Self::id()); let explorer = Explorer { root_path: path.to_owned(), tree_items: Self::build_tree_from_path(path.to_owned())?, diff --git a/src/tui/logger.rs b/src/tui/logger.rs index 809f072..44ad0f3 100644 --- a/src/tui/logger.rs +++ b/src/tui/logger.rs @@ -1,4 +1,5 @@ use crate::tui::component::{Action, Component, ComponentState, Focus}; +use log::trace; use ratatui::buffer::Buffer; use ratatui::crossterm::event::{Event, KeyCode, KeyEvent}; use ratatui::layout::Rect; @@ -19,6 +20,7 @@ impl Logger { } pub fn new() -> Self { + trace!(target:Self::id(), "Building {}", Self::id()); let state = TuiWidgetState::new(); state.transition(TuiWidgetEvent::HideKey); Self { diff --git a/src/tui/menu_bar.rs b/src/tui/menu_bar.rs index aa96009..b3ee35d 100644 --- a/src/tui/menu_bar.rs +++ b/src/tui/menu_bar.rs @@ -2,6 +2,7 @@ use crate::tui::component::{Action, Component, ComponentState}; use crate::tui::menu_bar::MenuBarItemOption::{ About, Exit, Reload, Save, ShowHideExplorer, ShowHideLogger, }; +use log::trace; use ratatui::buffer::Buffer; use ratatui::crossterm::event::{KeyCode, KeyEvent}; use ratatui::layout::Rect; @@ -80,8 +81,13 @@ pub struct MenuBar { } impl MenuBar { + pub fn id() -> &'static str { + "MenuBar" + } + const DEFAULT_HELP: &str = "(←/h)/(→/l): Select option | Enter: Choose selection"; pub fn new() -> Self { + trace!(target:Self::id(), "Building {}", Self::id()); Self { selected: MenuBarItem::File, opened: None, @@ -136,12 +142,14 @@ impl MenuBar { fn rect_under_option(anchor: Rect, area: Rect, width: u16, height: u16) -> Rect { // TODO: X offset for item option? It's fine as-is, but it might look nicer. - Rect { + let rect = Rect { x: anchor.x, y: anchor.y + anchor.height, width: width.min(area.width), height, - } + }; + trace!(target:Self::id(), "Building Rect under MenuBar popup {}", rect); + rect } }