refactor: use derive macro

This commit is contained in:
2025-07-07 21:06:38 +03:00
parent 41b3a03e80
commit 7d58d1b74c
19 changed files with 573 additions and 91 deletions

View File

@@ -20,8 +20,9 @@ impl Torrents {
self.client
.torrent_action(action, vec![id])
.await
.map_err(|e| color_eyre::eyre::eyre!("Transmission RPC error: {}", e.to_string()))?;
.map_err(|e| {
color_eyre::eyre::eyre!("Transmission RPC error: {}", e.to_string())
})?;
}
}
Ok(())
@@ -48,7 +49,9 @@ impl Torrents {
self.client
.torrent_action(action, vec![id])
.await
.map_err(|e| color_eyre::eyre::eyre!("Transmission RPC error: {}", e.to_string()))?;
.map_err(|e| {
color_eyre::eyre::eyre!("Transmission RPC error: {}", e.to_string())
})?;
}
Ok(())
}
@@ -71,12 +74,18 @@ impl Torrents {
self.client
.torrent_set_location(vec![id], location.to_string_lossy().into(), move_from)
.await
.map_err(|e| color_eyre::eyre::eyre!("Transmission RPC error: {}", e.to_string()))?;
.map_err(|e| {
color_eyre::eyre::eyre!("Transmission RPC error: {}", e.to_string())
})?;
}
Ok(())
}
pub async fn delete(&mut self, ids: Selected, delete_local_data: bool) -> color_eyre::eyre::Result<()> {
pub async fn delete(
&mut self,
ids: Selected,
delete_local_data: bool,
) -> color_eyre::eyre::Result<()> {
self.client
.torrent_remove(ids.into(), delete_local_data)
.await
@@ -89,7 +98,9 @@ impl Torrents {
self.client
.torrent_rename_path(vec![id], old_name, name.to_string_lossy().into())
.await
.map_err(|e| color_eyre::eyre::eyre!("Transmission RPC error: {}", e.to_string()))?;
.map_err(|e| {
color_eyre::eyre::eyre!("Transmission RPC error: {}", e.to_string())
})?;
}
Ok(())
}

View File

@@ -1,8 +1,9 @@
use crate::merge_fields;
use crate::merge::Merge;
use derive_macro::Merge;
use ratatui::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Deserialize, Serialize, Merge)]
pub struct ColorsConfig {
pub highlight_background: Option<String>,
pub highlight_foreground: Option<String>,
@@ -32,18 +33,6 @@ impl ColorsConfig {
None => Color::Reset,
}
}
pub fn merge(&mut self, other: Self) {
merge_fields!(
self,
other,
highlight_background,
highlight_foreground,
warning_foreground,
info_foreground,
error_foreground
);
}
}
impl Default for ColorsConfig {

View File

@@ -1,7 +1,8 @@
use crate::merge::Merge;
use derive_macro::Merge;
use serde::{Deserialize, Serialize};
use crate::merge_fields;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Deserialize, Serialize, Merge)]
pub struct KeybindsConfig {
pub quit: Option<String>,
pub next_tab: Option<String>,
@@ -19,29 +20,6 @@ pub struct KeybindsConfig {
pub toggle_help: Option<String>,
}
impl KeybindsConfig {
pub fn merge(&mut self, other: Self) {
merge_fields!(
self,
other,
quit,
next_tab,
prev_tab,
next_torrent,
prev_torrent,
switch_tab_1,
switch_tab_2,
switch_tab_3,
toggle_torrent,
toggle_all,
delete,
delete_force,
select,
toggle_help
);
}
}
impl Default for KeybindsConfig {
fn default() -> Self {
Self {

View File

@@ -1,24 +1,15 @@
mod colors;
mod keybinds;
use crate::merge::Merge;
use color_eyre::Result;
use colors::ColorsConfig;
use derive_macro::Merge;
use keybinds::KeybindsConfig;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[macro_export]
macro_rules! merge_fields {
($self:ident, $other:ident, $($field:ident),*) => {
$(
if let Some($field) = $other.$field {
$self.$field = Some($field);
}
)*
};
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[derive(Debug, Default, Deserialize, Serialize, Merge)]
pub struct Config {
pub keybinds: KeybindsConfig,
pub colors: ColorsConfig,
@@ -64,9 +55,4 @@ impl Config {
});
Ok(config_dir.join("traxor").join("config.toml"))
}
pub fn merge(&mut self, other: Self) {
self.keybinds.merge(other.keybinds);
self.colors.merge(other.colors);
}
}

View File

@@ -72,8 +72,12 @@ pub fn get_action(key_event: KeyEvent, app: &App) -> Option<Action> {
_ if matches_keybind(&key_event, &config_keybinds.quit) => Some(Action::Quit),
_ if matches_keybind(&key_event, &config_keybinds.next_tab) => Some(Action::NextTab),
_ if matches_keybind(&key_event, &config_keybinds.prev_tab) => Some(Action::PrevTab),
_ if matches_keybind(&key_event, &config_keybinds.next_torrent) => Some(Action::NextTorrent),
_ if matches_keybind(&key_event, &config_keybinds.prev_torrent) => Some(Action::PrevTorrent),
_ if matches_keybind(&key_event, &config_keybinds.next_torrent) => {
Some(Action::NextTorrent)
}
_ if matches_keybind(&key_event, &config_keybinds.prev_torrent) => {
Some(Action::PrevTorrent)
}
_ if matches_keybind(&key_event, &config_keybinds.switch_tab_1) => {
Some(Action::SwitchTab(0))
}

View File

@@ -1,7 +1,8 @@
pub mod config;
pub mod app;
pub mod config;
pub mod event;
pub mod handler;
pub mod log;
pub mod merge;
pub mod tui;
pub mod ui;
pub mod ui;

View File

@@ -53,4 +53,3 @@ async fn main() -> Result<()> {
tui.exit()?;
Ok(())
}

21
src/merge.rs Normal file
View File

@@ -0,0 +1,21 @@
pub trait Merge {
fn merge(&mut self, other: Self);
}
impl Merge for String {
fn merge(&mut self, other: Self) {
*self = other;
}
}
impl Merge for u32 {
fn merge(&mut self, other: Self) {
*self = other;
}
}
impl Merge for bool {
fn merge(&mut self, other: Self) {
*self = other;
}
}

View File

@@ -1,5 +1,5 @@
use ratatui::{prelude::*, widgets::*};
use crate::app::App;
use ratatui::{prelude::*, widgets::*};
pub fn render_help(frame: &mut Frame, app: &App) {
let block = Block::default()
@@ -11,23 +11,62 @@ pub fn render_help(frame: &mut Frame, app: &App) {
let keybinds = &app.config.keybinds;
let rows = vec![
Row::new(vec![Cell::from(keybinds.toggle_help.as_deref().unwrap_or("?")), Cell::from("Show help")]),
Row::new(vec![Cell::from(keybinds.quit.as_deref().unwrap_or("q")), Cell::from("Quit")]),
Row::new(vec![Cell::from(keybinds.prev_tab.as_deref().unwrap_or("h")), Cell::from("Left")]),
Row::new(vec![Cell::from(keybinds.next_tab.as_deref().unwrap_or("l")), Cell::from("Right")]),
Row::new(vec![Cell::from(keybinds.next_torrent.as_deref().unwrap_or("j")), Cell::from("Down")]),
Row::new(vec![Cell::from(keybinds.prev_torrent.as_deref().unwrap_or("k")), Cell::from("Up")]),
Row::new(vec![Cell::from(keybinds.switch_tab_1.as_deref().unwrap_or("1")), Cell::from("Switch to All tab")]),
Row::new(vec![Cell::from(keybinds.switch_tab_2.as_deref().unwrap_or("2")), Cell::from("Switch to Active tab")]),
Row::new(vec![
Cell::from(keybinds.toggle_help.as_deref().unwrap_or("?")),
Cell::from("Show help"),
]),
Row::new(vec![
Cell::from(keybinds.quit.as_deref().unwrap_or("q")),
Cell::from("Quit"),
]),
Row::new(vec![
Cell::from(keybinds.prev_tab.as_deref().unwrap_or("h")),
Cell::from("Left"),
]),
Row::new(vec![
Cell::from(keybinds.next_tab.as_deref().unwrap_or("l")),
Cell::from("Right"),
]),
Row::new(vec![
Cell::from(keybinds.next_torrent.as_deref().unwrap_or("j")),
Cell::from("Down"),
]),
Row::new(vec![
Cell::from(keybinds.prev_torrent.as_deref().unwrap_or("k")),
Cell::from("Up"),
]),
Row::new(vec![
Cell::from(keybinds.switch_tab_1.as_deref().unwrap_or("1")),
Cell::from("Switch to All tab"),
]),
Row::new(vec![
Cell::from(keybinds.switch_tab_2.as_deref().unwrap_or("2")),
Cell::from("Switch to Active tab"),
]),
Row::new(vec![
Cell::from(keybinds.switch_tab_3.as_deref().unwrap_or("3")),
Cell::from("Switch to Downloading tab"),
]),
Row::new(vec![Cell::from(keybinds.toggle_torrent.as_deref().unwrap_or("t")), Cell::from("Toggle torrent")]),
Row::new(vec![Cell::from(keybinds.toggle_all.as_deref().unwrap_or("a")), Cell::from("Toggle all torrents")]),
Row::new(vec![Cell::from(keybinds.delete.as_deref().unwrap_or("d")), Cell::from("Delete torrent")]),
Row::new(vec![Cell::from(keybinds.delete_force.as_deref().unwrap_or("D")), Cell::from("Delete torrent and data")]),
Row::new(vec![Cell::from(keybinds.select.as_deref().unwrap_or(" ")), Cell::from("Select torrent")]),
Row::new(vec![
Cell::from(keybinds.toggle_torrent.as_deref().unwrap_or("t")),
Cell::from("Toggle torrent"),
]),
Row::new(vec![
Cell::from(keybinds.toggle_all.as_deref().unwrap_or("a")),
Cell::from("Toggle all torrents"),
]),
Row::new(vec![
Cell::from(keybinds.delete.as_deref().unwrap_or("d")),
Cell::from("Delete torrent"),
]),
Row::new(vec![
Cell::from(keybinds.delete_force.as_deref().unwrap_or("D")),
Cell::from("Delete torrent and data"),
]),
Row::new(vec![
Cell::from(keybinds.select.as_deref().unwrap_or(" ")),
Cell::from("Select torrent"),
]),
];
let table = Table::new(
@@ -35,7 +74,12 @@ pub fn render_help(frame: &mut Frame, app: &App) {
&[Constraint::Percentage(20), Constraint::Percentage(80)],
)
.block(block)
.style(Style::default().fg(app.config.colors.get_color(&app.config.colors.info_foreground)));
.style(
Style::default().fg(app
.config
.colors
.get_color(&app.config.colors.info_foreground)),
);
let area = frame.area();
let height = 15; // Desired height for the help menu
@@ -51,4 +95,3 @@ pub fn render_help(frame: &mut Frame, app: &App) {
frame.render_widget(Clear, popup_area);
frame.render_widget(table, popup_area);
}

View File

@@ -32,8 +32,18 @@ pub fn render(app: &mut App, frame: &mut Frame) {
.border_type(BorderType::Rounded),
)
.select(app.index())
.style(Style::default().fg(app.config.colors.get_color(&app.config.colors.info_foreground)))
.highlight_style(Style::default().fg(app.config.colors.get_color(&app.config.colors.warning_foreground)))
.style(
Style::default().fg(app
.config
.colors
.get_color(&app.config.colors.info_foreground)),
)
.highlight_style(
Style::default().fg(app
.config
.colors
.get_color(&app.config.colors.warning_foreground)),
)
.divider("|");
frame.render_widget(tabs, chunks[0]); // renders tab

View File

@@ -10,8 +10,14 @@ pub fn render_table<'a>(app: &mut App, tab: Tab) -> Table<'a> {
let selected = &app.torrents.selected.clone();
let torrents = &app.torrents.set_fields(None).torrents;
let highlight_bg = app.config.colors.get_color(&app.config.colors.highlight_background);
let highlight_fg = app.config.colors.get_color(&app.config.colors.highlight_foreground);
let highlight_bg = app
.config
.colors
.get_color(&app.config.colors.highlight_background);
let highlight_fg = app
.config
.colors
.get_color(&app.config.colors.highlight_foreground);
let highlight_style = Style::default().bg(highlight_bg).fg(highlight_fg);
let rows: Vec<Row<'_>> = torrents
@@ -38,7 +44,10 @@ pub fn render_table<'a>(app: &mut App, tab: Tab) -> Table<'a> {
.map(|&field| Constraint::Length(field.width()))
.collect::<Vec<_>>();
let header_fg = app.config.colors.get_color(&app.config.colors.warning_foreground);
let header_fg = app
.config
.colors
.get_color(&app.config.colors.warning_foreground);
let header = Row::new(
fields
.iter()
@@ -47,8 +56,14 @@ pub fn render_table<'a>(app: &mut App, tab: Tab) -> Table<'a> {
)
.style(Style::default().fg(header_fg));
let row_highlight_bg = app.config.colors.get_color(&app.config.colors.info_foreground);
let row_highlight_fg = app.config.colors.get_color(&app.config.colors.highlight_foreground);
let row_highlight_bg = app
.config
.colors
.get_color(&app.config.colors.info_foreground);
let row_highlight_fg = app
.config
.colors
.get_color(&app.config.colors.highlight_foreground);
let row_highlight_style = Style::default().bg(row_highlight_bg).fg(row_highlight_fg);
Table::new(rows, widths)