From be969ef3359eba48527ec0f6865c3bd2596541e6 Mon Sep 17 00:00:00 2001 From: Shaun Reed Date: Sun, 22 Feb 2026 10:09:53 -0500 Subject: [PATCH] Add macros for logging. --- .github/workflows/check.yaml | 12 ++++ Cargo.lock | 11 ++++ Cargo.toml | 11 ++-- libclide-macros/Cargo.toml | 12 ++++ libclide-macros/src/lib.rs | 27 +++++++++ libclide/Cargo.toml | 1 + libclide/src/lib.rs | 1 + libclide/src/log.rs | 5 ++ libclide/src/log/macros.rs | 106 +++++++++++++++++++++++++++++++++++ libclide/src/theme/colors.rs | 2 +- src/gui.rs | 3 +- src/gui/filesystem.rs | 3 +- src/tui.rs | 18 +++--- src/tui/about.rs | 7 +-- src/tui/app.rs | 29 +++++----- src/tui/component.rs | 5 +- src/tui/editor.rs | 17 +++--- src/tui/editor_tab.rs | 31 +++++----- src/tui/explorer.rs | 7 +-- src/tui/logger.rs | 8 +-- src/tui/menu_bar.rs | 9 ++- 21 files changed, 246 insertions(+), 79 deletions(-) create mode 100644 libclide-macros/Cargo.toml create mode 100644 libclide-macros/src/lib.rs create mode 100644 libclide/src/log.rs create mode 100644 libclide/src/log/macros.rs diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index 958fd3c..dbd9991 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -26,6 +26,9 @@ jobs: - name: Build libclide run: | cargo b -p libclide --release + - name: Build libclide-macros + run: | + cargo b -p libclide-macros --release - name: Build clide run: | cargo b --release @@ -44,6 +47,9 @@ jobs: - name: Test libclide run: | cargo test -p libclide + - name: Test libclide-macros + run: | + cargo test -p libclide-macros - name: Test clide run: | cargo test @@ -62,6 +68,9 @@ jobs: - name: Lint libclide run: | cargo clippy -p libclide -- -D warnings + - name: Lint libclide-macros + run: | + cargo clippy -p libclide-macros -- -D warnings - name: Lint clide run: | cargo clippy -- -D warnings @@ -80,6 +89,9 @@ jobs: - name: Format libclide run: | cargo fmt -p libclide --verbose -- --check + - name: Format libclide-macros + run: | + cargo fmt -p libclide-macros -- --check - name: Format clide run: | cargo fmt --verbose -- --check diff --git a/Cargo.lock b/Cargo.lock index ac98bd2..fecb64b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -299,6 +299,7 @@ dependencies = [ "dirs", "edtui", "libclide", + "libclide-macros", "log", "ratatui", "strum", @@ -1169,9 +1170,19 @@ name = "libclide" version = "0.1.0" dependencies = [ "anyhow", + "log", "strum", ] +[[package]] +name = "libclide-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "libredox" version = "0.1.12" diff --git a/Cargo.toml b/Cargo.toml index 6176c2d..f07c71a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,20 +5,17 @@ edition = "2024" [workspace] resolver = "3" -members = [ - ".", - "libclide", -] +members = [".", "libclide", "libclide-macros", ] [workspace.dependencies] anyhow = "1.0.100" strum = "0.27.2" +log = { version = "0.4.27", features = [] } [dependencies] cxx = "1.0.95" cxx-qt = "0.8.0" cxx-qt-lib = { version = "0.8.0", features = ["qt_full", "qt_gui", "qt_qml"] } -log = { version = "0.4.27", features = [] } dirs = "6.0.0" syntect = "5.2.0" clap = { version = "4.5.54", features = ["derive"] } @@ -28,9 +25,11 @@ tui-logger = "0.18.1" edtui = "0.11.1" devicons = "0.6.12" libclide = { path = "./libclide" } +libclide-macros = { path = "./libclide-macros" } anyhow = { workspace = true } strum = { workspace = true } +log = { workspace = true } [build-dependencies] # The link_qt_object_files feature is required for statically linking Qt 6. -cxx-qt-build = { version = "0.8.0", features = ["link_qt_object_files"] } \ No newline at end of file +cxx-qt-build = { version = "0.8.0", features = ["link_qt_object_files"] } diff --git a/libclide-macros/Cargo.toml b/libclide-macros/Cargo.toml new file mode 100644 index 0000000..bf6d860 --- /dev/null +++ b/libclide-macros/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "libclide-macros" +version = "0.1.0" +edition = "2024" + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "2", features = ["full"] } +quote = "1" +proc-macro2 = "1" \ No newline at end of file diff --git a/libclide-macros/src/lib.rs b/libclide-macros/src/lib.rs new file mode 100644 index 0000000..9f69c0b --- /dev/null +++ b/libclide-macros/src/lib.rs @@ -0,0 +1,27 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{ItemStruct, parse_macro_input}; + +#[proc_macro_attribute] +pub fn log_id(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as ItemStruct); + + let struct_name = &input.ident; + let generics = &input.generics; + + // This is the important part + let (impl_generics, type_generics, where_clause) = generics.split_for_impl(); + + let struct_name_str = struct_name.to_string(); + + let expanded = quote! { + #input + + impl #impl_generics #struct_name #type_generics #where_clause { + #[allow(unused)] + pub const ID: &'static str = #struct_name_str; + } + }; + + TokenStream::from(expanded) +} diff --git a/libclide/Cargo.toml b/libclide/Cargo.toml index 33434a0..7c037f0 100644 --- a/libclide/Cargo.toml +++ b/libclide/Cargo.toml @@ -6,3 +6,4 @@ edition = "2024" [dependencies] anyhow = { workspace = true } strum = { workspace = true } +log = { workspace = true } diff --git a/libclide/src/lib.rs b/libclide/src/lib.rs index baf3411..400e3b7 100644 --- a/libclide/src/lib.rs +++ b/libclide/src/lib.rs @@ -3,4 +3,5 @@ // SPDX-License-Identifier: GNU General Public License v3.0 or later pub mod fs; +pub mod log; pub mod theme; diff --git a/libclide/src/log.rs b/libclide/src/log.rs new file mode 100644 index 0000000..dbb82f2 --- /dev/null +++ b/libclide/src/log.rs @@ -0,0 +1,5 @@ +// SPDX-FileCopyrightText: 2026, Shaun Reed +// +// SPDX-License-Identifier: GNU General Public License v3.0 or later + +pub mod macros; diff --git a/libclide/src/log/macros.rs b/libclide/src/log/macros.rs new file mode 100644 index 0000000..50baf84 --- /dev/null +++ b/libclide/src/log/macros.rs @@ -0,0 +1,106 @@ +//! Logging targets allow filtering of log messages by their source. By default, the log crate sets +//! the target to the module path where the log macro was invoked if no target is provided. +//! +//! These macros essentially disable using the default target and instead require the target to be +//! explicitly set. This is to avoid implicit pooling of log messages under the same default target, +//! which can make it difficult to filter log messages by their source. + +#[macro_export] +macro_rules! info { + // The target argument can be overridden using one of the following macros. + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + log::info!(logger: $logger, target: $target, $($arg)+) + }); + + (target: $target:expr, $($arg:tt)+) => ({ + log::info!(target: $target, $($arg)+) + }); + + // The target argument will default to Self::ID if not provided. + // Obviously, this is an error if Self::ID is not defined, forcing you to use the explicit form. + (logger: $logger:expr, $($arg:tt)+) => ({ + log::info!(logger: $logger, target: Self::ID, $($arg)+) + }); + + ($($arg:tt)+) => (log::info!(target: Self::ID, $($arg)+)) +} + +#[macro_export] +macro_rules! debug { + // The target argument can be overridden using one of the following macros. + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + log::debug!(logger: $logger, target: $target, $($arg)+) + }); + + (target: $target:expr, $($arg:tt)+) => ({ + log::debug!(target: $target, $($arg)+) + }); + + // The target argument will default to Self::ID if not provided. + // Obviously, this is an error if Self::ID is not defined, forcing you to use the explicit form. + (logger: $logger:expr, $($arg:tt)+) => ({ + log::debug!(logger: $logger, target: Self::ID, $($arg)+) + }); + + ($($arg:tt)+) => (log::debug!(target: Self::ID, $($arg)+)) +} + +#[macro_export] +macro_rules! warn { + // The target argument can be overridden using one of the following macros. + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + log::warn!(logger: $logger, target: $target, $($arg)+) + }); + + (target: $target:expr, $($arg:tt)+) => ({ + log::warn!(target: $target, $($arg)+) + }); + + // The target argument will default to Self::ID if not provided. + // Obviously, this is an error if Self::ID is not defined, forcing you to use the explicit form. + (logger: $logger:expr, $($arg:tt)+) => ({ + log::warn!(logger: $logger, target: Self::ID, $($arg)+) + }); + + ($($arg:tt)+) => (log::warn!(target: Self::ID, $($arg)+)) +} + +#[macro_export] +macro_rules! error { + // The target argument can be overridden using one of the following macros. + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + log::error!(logger: $logger, target: $target, $($arg)+) + }); + + (target: $target:expr, $($arg:tt)+) => ({ + log::error!(target: $target, $($arg)+) + }); + + // The target argument will default to Self::ID if not provided. + // Obviously, this is an error if Self::ID is not defined, forcing you to use the explicit form. + (logger: $logger:expr, $($arg:tt)+) => ({ + log::error!(logger: $logger, target: Self::ID, $($arg)+) + }); + + ($($arg:tt)+) => (log::error!(target: Self::ID, $($arg)+)) +} + +#[macro_export] +macro_rules! trace { + // The target argument can be overridden using one of the following macros. + (logger: $logger:expr, target: $target:expr, $($arg:tt)+) => ({ + log::trace!(logger: $logger, target: $target, $($arg)+) + }); + + (target: $target:expr, $($arg:tt)+) => ({ + log::trace!(target: $target, $($arg)+) + }); + + // The target argument will default to Self::ID if not provided. + // Obviously, this is an error if Self::ID is not defined, forcing you to use the explicit form. + (logger: $logger:expr, $($arg:tt)+) => ({ + log::trace!(logger: $logger, target: Self::ID, $($arg)+) + }); + + ($($arg:tt)+) => (log::trace!(target: Self::ID, $($arg)+)) +} diff --git a/libclide/src/theme/colors.rs b/libclide/src/theme/colors.rs index 4f52bc1..c019f15 100644 --- a/libclide/src/theme/colors.rs +++ b/libclide/src/theme/colors.rs @@ -41,7 +41,7 @@ impl Colors { let hex_full = match hex.len() { 3 => hex .chars() - .map(|c| std::iter::repeat(c).take(2).collect::()) + .map(|c| std::iter::repeat_n(c, 2).collect::()) .collect::(), 6 => hex.to_string(), _ => panic!("Invalid hex color length: {hex:?}"), diff --git a/src/gui.rs b/src/gui.rs index 48b1e0b..9ca92c7 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -5,13 +5,12 @@ use crate::AppContext; use anyhow::Result; use cxx_qt_lib::{QMapPair, QMapPair_QString_QVariant, QString, QVariant}; -use log::trace; pub mod colors; pub mod filesystem; pub fn run(app_context: AppContext) -> Result<()> { - trace!(target:"gui::run()", "Starting the GUI editor at {:?}", app_context.path); + libclide::trace!(target:"gui::run()", "Starting the GUI editor at {:?}", app_context.path); use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QUrl}; diff --git a/src/gui/filesystem.rs b/src/gui/filesystem.rs index 4f64599..12dc077 100644 --- a/src/gui/filesystem.rs +++ b/src/gui/filesystem.rs @@ -5,7 +5,6 @@ use cxx_qt_lib::{QModelIndex, QString}; use devicons::FileIcon; use dirs; -use log::warn; use std::fs; use std::path::Path; use syntect::easy::HighlightLines; @@ -78,7 +77,7 @@ impl qobject::FileSystem { let meta = fs::metadata(path.to_string()) .unwrap_or_else(|_| panic!("Failed to get file metadata {path:?}")); if !meta.is_file() { - warn!(target:"FileSystem", "Attempted to open file {path:?} that is not a valid file"); + libclide::warn!(target:"FileSystem", "Attempted to open file {path:?} that is not a valid file"); return QString::default(); } let path_str = path.to_string(); diff --git a/src/tui.rs b/src/tui.rs index 2652ca7..88a55d7 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -13,7 +13,8 @@ mod menu_bar; use crate::AppContext; use anyhow::{Context, Result}; -use log::{LevelFilter, debug, info, trace}; +use libclide_macros::log_id; +use log::LevelFilter; use ratatui::Terminal; use ratatui::backend::CrosstermBackend; use ratatui::crossterm::event::{ @@ -28,24 +29,23 @@ use tui_logger::{ TuiLoggerFile, TuiLoggerLevelOutput, init_logger, set_default_level, set_log_file, }; +#[log_id] struct Tui { terminal: Terminal>, root_path: std::path::PathBuf, } pub fn run(app_context: AppContext) -> Result<()> { - trace!(target:Tui::ID, "Starting TUI"); + libclide::trace!(target:Tui::ID, "Starting TUI"); Tui::new(app_context)?.start() } impl Tui { - pub const ID: &str = "Tui"; - fn new(app_context: AppContext) -> Result { - trace!(target:Self::ID, "Building {}", Self::ID); + libclide::trace!("Building {}", Self::ID); init_logger(LevelFilter::Trace)?; set_default_level(LevelFilter::Trace); - debug!(target:Self::ID, "Logging initialized"); + libclide::debug!("Logging initialized"); let mut dir = env::temp_dir(); dir.push("clide.log"); @@ -57,7 +57,7 @@ impl Tui { .output_file(false) .output_separator(':'); set_log_file(file_options); - debug!(target:Self::ID, "Logging to file: {dir:?}"); + libclide::debug!("Logging to file: {dir:?}"); Ok(Self { terminal: Terminal::new(CrosstermBackend::new(stdout()))?, @@ -66,7 +66,7 @@ impl Tui { } fn start(self) -> Result<()> { - info!(target:Self::ID, "Starting the TUI editor at {:?}", self.root_path); + libclide::info!("Starting the TUI editor at {:?}", self.root_path); ratatui::crossterm::execute!( stdout(), EnterAlternateScreen, @@ -83,7 +83,7 @@ impl Tui { } fn stop() -> Result<()> { - info!(target:Self::ID, "Stopping the TUI editor"); + libclide::info!("Stopping the TUI editor"); disable_raw_mode()?; ratatui::crossterm::execute!( stdout(), diff --git a/src/tui/about.rs b/src/tui/about.rs index 878d6d8..f5334f4 100644 --- a/src/tui/about.rs +++ b/src/tui/about.rs @@ -2,19 +2,18 @@ // // SPDX-License-Identifier: GNU General Public License v3.0 or later +use libclide_macros::log_id; use ratatui::buffer::Buffer; use ratatui::layout::{Constraint, Direction, Layout, Rect}; use ratatui::text::{Line, Span}; use ratatui::widgets::{Block, Borders, Clear, Padding, Paragraph, Widget, Wrap}; +#[log_id] pub struct About {} impl About { - #[allow(unused)] - pub const ID: &str = "About"; - pub fn new() -> Self { - // trace!(target:Self::id(), "Building {}", Self::id()); + // libclide::trace!("Building {}", Self::id()); Self {} } } diff --git a/src/tui/app.rs b/src/tui/app.rs index 190420c..3e02c82 100644 --- a/src/tui/app.rs +++ b/src/tui/app.rs @@ -9,7 +9,7 @@ use crate::tui::explorer::Explorer; use crate::tui::logger::Logger; use crate::tui::menu_bar::MenuBar; use anyhow::{Context, Result}; -use log::{error, info, trace}; +use libclide_macros::log_id; use ratatui::DefaultTerminal; use ratatui::buffer::Buffer; use ratatui::crossterm::event; @@ -30,6 +30,7 @@ pub enum AppComponent { MenuBar, } +#[log_id] pub struct App<'a> { editor_tab: EditorTab, explorer: Explorer<'a>, @@ -40,10 +41,8 @@ pub struct App<'a> { } impl<'a> App<'a> { - pub const ID: &'static str = "App"; - pub fn new(root_path: PathBuf) -> Result { - trace!(target:Self::ID, "Building {}", Self::ID); + libclide::trace!(target:Self::ID, "Building {}", Self::ID); let app = Self { editor_tab: EditorTab::new(), explorer: Explorer::new(&root_path)?, @@ -57,13 +56,13 @@ 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"); + libclide::trace!(target:Self::ID, "Starting App"); Ok(()) } pub fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> { self.start()?; - trace!(target:Self::ID, "Entering App run loop"); + libclide::trace!(target:Self::ID, "Entering App run loop"); loop { terminal.draw(|f| { f.render_widget(&mut self, f.area()); @@ -89,7 +88,7 @@ impl<'a> App<'a> { Some(editor) => editor.component_state.help_text.clone(), None => { if !self.editor_tab.is_empty() { - error!(target:Self::ID, "Failed to get Editor while drawing bottom status bar"); + libclide::error!(target:Self::ID, "Failed to get Editor while drawing bottom status bar"); } "Failed to get current Editor while getting widget help text".to_string() } @@ -113,26 +112,26 @@ impl<'a> App<'a> { } fn clear_focus(&mut self) { - info!(target:Self::ID, "Clearing all widget focus"); + libclide::info!(target:Self::ID, "Clearing all widget focus"); self.explorer.component_state.set_focus(Focus::Inactive); self.explorer.component_state.set_focus(Focus::Inactive); self.logger.component_state.set_focus(Focus::Inactive); self.menu_bar.component_state.set_focus(Focus::Inactive); match self.editor_tab.current_editor_mut() { None => { - error!(target:Self::ID, "Failed to get current Editor while clearing focus") + libclide::error!(target:Self::ID, "Failed to get current Editor while clearing focus") } Some(editor) => editor.component_state.set_focus(Focus::Inactive), } } fn change_focus(&mut self, focus: AppComponent) { - info!(target:Self::ID, "Changing widget focus to {:?}", focus); + libclide::info!(target:Self::ID, "Changing widget focus to {:?}", focus); self.clear_focus(); match focus { AppComponent::Editor => match self.editor_tab.current_editor_mut() { None => { - error!(target:Self::ID, "Failed to get current Editor while changing focus") + libclide::error!(target:Self::ID, "Failed to get current Editor while changing focus") } Some(editor) => editor.component_state.set_focus(Focus::Active), }, @@ -275,13 +274,13 @@ impl<'a> Component for App<'a> { Action::Quit | Action::Handled => Ok(action), Action::Save => match self.editor_tab.current_editor_mut() { None => { - error!(target:Self::ID, "Failed to get current editor while handling App Action::Save"); + libclide::error!(target:Self::ID, "Failed to get current editor while handling App Action::Save"); Ok(Action::Noop) } Some(editor) => match editor.save() { Ok(_) => Ok(Action::Handled), Err(e) => { - error!(target:Self::ID, "Failed to save editor contents: {e}"); + libclide::error!(target:Self::ID, "Failed to save editor contents: {e}"); Ok(Action::Noop) } }, @@ -300,14 +299,14 @@ impl<'a> Component for App<'a> { Err(_) => Ok(Action::Noop), }, Action::ReloadFile => { - trace!(target:Self::ID, "Reloading file for current editor"); + libclide::trace!(target:Self::ID, "Reloading file for current editor"); if let Some(editor) = self.editor_tab.current_editor_mut() { editor .reload_contents() .map(|_| Action::Handled) .context("Failed to handle Action::ReloadFile") } else { - error!(target:Self::ID, "Failed to get current editor while handling App Action::ReloadFile"); + libclide::error!(target:Self::ID, "Failed to get current editor while handling App Action::ReloadFile"); Ok(Action::Noop) } } diff --git a/src/tui/component.rs b/src/tui/component.rs index ee6e844..30ffd47 100644 --- a/src/tui/component.rs +++ b/src/tui/component.rs @@ -8,7 +8,7 @@ use crate::tui::component::Focus::Inactive; use Focus::Active; use anyhow::Result; use libclide::theme::colors::Colors; -use log::trace; +use libclide_macros::log_id; use ratatui::crossterm::event::{Event, KeyEvent, MouseEvent}; use ratatui::style::Color; @@ -63,6 +63,7 @@ pub trait Component { } #[derive(Debug, Clone, Default)] +#[log_id] pub struct ComponentState { pub(crate) focus: Focus, pub(crate) vis: Visibility, @@ -75,7 +76,7 @@ impl ComponentState { } fn new() -> Self { - trace!(target:Self::id(), "Building {}", Self::id()); + libclide::trace!(target:Self::id(), "Building {}", Self::id()); Self { focus: Active, vis: Visibility::Visible, diff --git a/src/tui/editor.rs b/src/tui/editor.rs index 99c07b6..42adcb1 100644 --- a/src/tui/editor.rs +++ b/src/tui/editor.rs @@ -7,7 +7,7 @@ use anyhow::{Context, Result, bail}; use edtui::{ EditorEventHandler, EditorState, EditorTheme, EditorView, LineNumbers, Lines, SyntaxHighlighter, }; -use log::{error, trace}; +use libclide_macros::log_id; use ratatui::buffer::Buffer; use ratatui::crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; use ratatui::layout::{Alignment, Rect}; @@ -16,6 +16,7 @@ use ratatui::widgets::{Block, Borders, Padding, Widget}; use std::path::PathBuf; use syntect::parsing::SyntaxSet; +#[log_id] pub struct Editor { pub state: EditorState, pub event_handler: EditorEventHandler, @@ -25,10 +26,8 @@ pub struct Editor { } impl Editor { - pub const ID: &str = "Editor"; - pub fn new(path: &std::path::Path) -> Self { - trace!(target:Self::ID, "Building {}", Self::ID); + libclide::trace!(target:Self::ID, "Building {}", Self::ID); Editor { state: EditorState::default(), event_handler: EditorEventHandler::default(), @@ -42,10 +41,10 @@ impl Editor { } pub fn reload_contents(&mut self) -> Result<()> { - trace!(target:Self::ID, "Reloading editor file contents {:?}", self.file_path); + libclide::trace!(target:Self::ID, "Reloading editor file contents {:?}", self.file_path); match self.file_path.clone() { None => { - error!(target:Self::ID, "Failed to reload editor contents with None file_path"); + libclide::error!(target:Self::ID, "Failed to reload editor contents with None file_path"); bail!("Failed to reload editor contents with None file_path") } Some(path) => self.set_contents(&path), @@ -53,7 +52,7 @@ impl Editor { } pub fn set_contents(&mut self, path: &std::path::Path) -> Result<()> { - trace!(target:Self::ID, "Setting Editor contents from path {:?}", path); + libclide::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() @@ -69,10 +68,10 @@ impl Editor { pub fn save(&self) -> Result<()> { if let Some(path) = &self.file_path { - trace!(target:Self::ID, "Saving Editor contents {:?}", path); + libclide::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"); + libclide::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 21d8112..ec7da9e 100644 --- a/src/tui/editor_tab.rs +++ b/src/tui/editor_tab.rs @@ -5,7 +5,7 @@ use crate::tui::component::{Action, Component, Focus, FocusState}; use crate::tui::editor::Editor; use anyhow::{Context, Result, anyhow}; -use log::{error, info, trace, warn}; +use libclide_macros::log_id; use ratatui::buffer::Buffer; use ratatui::crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; use ratatui::layout::Rect; @@ -16,6 +16,7 @@ use std::collections::HashMap; // Render the tabs with keys as titles // Tab keys can be file names. // Render the editor using the key as a reference for lookup +#[log_id] pub struct EditorTab { pub(crate) editors: HashMap, tab_order: Vec, @@ -23,10 +24,8 @@ pub struct EditorTab { } impl EditorTab { - pub const ID: &str = "EditorTab"; - pub fn new() -> Self { - trace!(target:Self::ID, "Building {}", Self::ID); + libclide::trace!(target:Self::ID, "Building {}", Self::ID); Self { editors: HashMap::new(), tab_order: Vec::new(), @@ -36,7 +35,7 @@ impl EditorTab { pub fn next_editor(&mut self) { 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); + libclide::trace!(target:Self::ID, "Moving from {} to next editor tab at {}", self.current_editor, next); self.set_tab_focus(Focus::Active, next); self.current_editor = next; } @@ -46,7 +45,7 @@ impl EditorTab { .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); + libclide::trace!(target:Self::ID, "Moving from {} to previous editor tab at {}", self.current_editor, prev); self.set_tab_focus(Focus::Active, prev); self.current_editor = prev; } @@ -55,7 +54,7 @@ impl EditorTab { match self.tab_order.get(index) { None => { if !self.tab_order.is_empty() { - error!(target:Self::ID, "Failed to get editor tab key with invalid index {index}"); + libclide::error!(target:Self::ID, "Failed to get editor tab key with invalid index {index}"); } None } @@ -73,15 +72,15 @@ impl EditorTab { } pub fn set_current_tab_focus(&mut self, focus: Focus) { - trace!(target:Self::ID, "Setting current tab {} focus to {:?}", self.current_editor, focus); + libclide::trace!(target:Self::ID, "Setting current tab {} focus to {:?}", self.current_editor, focus); self.set_tab_focus(focus, self.current_editor) } pub fn set_tab_focus(&mut self, focus: Focus, index: usize) { - trace!(target:Self::ID, "Setting tab {} focus to {:?}", index, focus); + libclide::trace!(target:Self::ID, "Setting tab {} focus to {:?}", index, focus); if focus == Focus::Active && index != self.current_editor { // If we are setting another tab to active, disable the current one. - trace!( + libclide::trace!( target:Self::ID, "New tab {} focus set to Active; Setting current tab {} to Inactive", index, @@ -91,11 +90,11 @@ impl EditorTab { } match self.get_editor_key(index) { None => { - error!(target:Self::ID, "Failed setting tab focus for invalid key {index}"); + libclide::error!(target:Self::ID, "Failed setting tab focus for invalid key {index}"); } Some(key) => match self.editors.get_mut(&key) { None => { - error!( + libclide::error!( target:Self::ID, "Failed to update tab focus at index {} with invalid key: {}", self.current_editor, @@ -108,12 +107,12 @@ impl EditorTab { } pub fn open_tab(&mut self, path: &std::path::Path) -> Result<()> { - trace!(target:Self::ID, "Opening new EditorTab with path {:?}", path); + libclide::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"); + libclide::warn!(target:Self::ID, "EditorTab already opened with this file"); return Ok(()); } @@ -138,12 +137,12 @@ impl EditorTab { .to_owned(); match self.editors.remove(&key) { None => { - error!(target:Self::ID, "Failed to remove editor tab {key} with invalid index {index}") + libclide::error!(target:Self::ID, "Failed to remove editor tab {key} with invalid index {index}") } Some(_) => { self.prev_editor(); self.tab_order.remove(index); - info!(target:Self::ID, "Closed editor tab {key} at index {index}") + libclide::info!(target:Self::ID, "Closed editor tab {key} at index {index}") } } Ok(()) diff --git a/src/tui/explorer.rs b/src/tui/explorer.rs index 9ac817e..4bb63f0 100644 --- a/src/tui/explorer.rs +++ b/src/tui/explorer.rs @@ -5,7 +5,7 @@ use crate::tui::component::{Action, Component, ComponentState, Focus, FocusState}; use anyhow::{Context, Result, bail}; use libclide::fs::entry_meta::EntryMeta; -use log::trace; +use libclide_macros::log_id; use ratatui::buffer::Buffer; use ratatui::crossterm::event::{Event, KeyCode, KeyEvent, MouseEvent, MouseEventKind}; use ratatui::layout::{Alignment, Position, Rect}; @@ -17,6 +17,7 @@ use std::path::{Path, PathBuf}; use tui_tree_widget::{Tree, TreeItem, TreeState}; #[derive(Debug)] +#[log_id] pub struct Explorer<'a> { root_path: EntryMeta, tree_items: TreeItem<'a, String>, @@ -25,10 +26,8 @@ pub struct Explorer<'a> { } impl<'a> Explorer<'a> { - pub const ID: &'static str = "Explorer"; - pub fn new(path: &PathBuf) -> Result { - trace!(target:Self::ID, "Building {}", Self::ID); + libclide::trace!("Building {}", Self::ID); let explorer = Explorer { root_path: EntryMeta::new(path)?, tree_items: Self::build_tree_from_path(path)?, diff --git a/src/tui/logger.rs b/src/tui/logger.rs index d88cf68..122d5fc 100644 --- a/src/tui/logger.rs +++ b/src/tui/logger.rs @@ -3,7 +3,8 @@ // SPDX-License-Identifier: GNU General Public License v3.0 or later use crate::tui::component::{Action, Component, ComponentState, Focus, FocusState}; -use log::{LevelFilter, trace}; +use libclide_macros::log_id; +use log::LevelFilter; use ratatui::buffer::Buffer; use ratatui::crossterm::event::{Event, KeyCode, KeyEvent}; use ratatui::layout::Rect; @@ -13,16 +14,15 @@ use tui_logger::{TuiLoggerLevelOutput, TuiLoggerSmartWidget, TuiWidgetEvent, Tui /// Any log written as info!(target:self.id(), "message") will work with this logger. /// The logger is bound to info!, debug!, error!, trace! macros within Tui::new(). +#[log_id] pub struct Logger { state: TuiWidgetState, pub(crate) component_state: ComponentState, } impl Logger { - pub const ID: &str = "Logger"; - pub fn new() -> Self { - trace!(target:Self::ID, "Building {}", Self::ID); + libclide::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 f872584..a197188 100644 --- a/src/tui/menu_bar.rs +++ b/src/tui/menu_bar.rs @@ -7,7 +7,7 @@ use crate::tui::menu_bar::MenuBarItemOption::{ About, CloseTab, Exit, Reload, Save, ShowHideExplorer, ShowHideLogger, }; use anyhow::Context; -use log::trace; +use libclide_macros::log_id; use ratatui::buffer::Buffer; use ratatui::crossterm::event::{KeyCode, KeyEvent}; use ratatui::layout::Rect; @@ -80,6 +80,7 @@ impl MenuBarItem { } } +#[log_id] pub struct MenuBar { selected: MenuBarItem, opened: Option, @@ -88,11 +89,9 @@ pub struct MenuBar { } impl MenuBar { - pub const ID: &str = "MenuBar"; - const DEFAULT_HELP: &str = "(←/h)/(→/l): Select option | Enter: Choose selection"; pub fn new() -> Self { - trace!(target:Self::ID, "Building {}", Self::ID); + libclide::trace!("Building {}", Self::ID); Self { selected: MenuBarItem::File, opened: None, @@ -157,7 +156,7 @@ impl MenuBar { height, } // TODO: X offset for item option? It's fine as-is, but it might look nicer. - // trace!(target:Self::ID, "Building Rect under MenuBar popup {}", rect); + // trace!("Building Rect under MenuBar popup {}", rect); } }