Commit Diff


commit - f61649b9fb73b5e7718ec70b146d07b8608bb99d
commit + 40cb58189a29d8b347ced25f731c5de194405bf8
blob - f916ab07c7da1caa5aadd08957dbdea1788a8fed
blob + e8e915a1027fed98278a434fd194720909dc6ba5
--- README.md
+++ README.md
@@ -30,8 +30,8 @@ cargo build --release
 *   `-s`, `--standings`: Show league standings/table.
 *   `-t`, `--token <TOKEN>`: API token from football-data.org (required).
 *   `-f`, `--filter <TEAM>`: Filter by team name or abbreviation.
-*   `--all`: Show all matches (past and future).
-*   `-l`, `--league <LEAGUE>`: League to display (default: epl).
+*   `-a`, `--all`: List all matches across every competition (ignores `--league`). This is the default when no `--league` is given.
+*   `-l`, `--league <LEAGUE>`: League to display. When omitted, all competitions are shown.
 
 ### Leagues
 
@@ -43,17 +43,20 @@ cargo build --release
 ### Example
 
 ```sh
-# Show upcoming Premier League matches
+# List all matches across every competition (default)
 ./target/release/scores -t <TOKEN>
 
+# Show upcoming Premier League matches
+./target/release/scores -l epl -t <TOKEN>
+
 # Show Premier League table
 ./target/release/scores -s -t <TOKEN>
 
-# Show upcoming Arsenal matches
+# List all matches involving Arsenal across every competition
 ./target/release/scores -f arsenal -t <TOKEN>
 
-# Show all Arsenal matches this season
-./target/release/scores -l epl -f ars -a -t <TOKEN>
+# Show upcoming Arsenal matches in the Premier League
+./target/release/scores -l epl -f arsenal -t <TOKEN>
 
 # Show La Liga standings
 ./target/release/scores -s -l laliga -t <TOKEN>
blob - 74302d576466f2cc19cb76084c57b14ea4e002b0
blob + 331ce3a69004bdec2f44ca1c1e3c5afd7ba36f5d
--- src/api.rs
+++ src/api.rs
@@ -15,8 +15,8 @@ impl ApiClient {
         }
     }
 
-    async fn fetch<T: for<'de> serde::Deserialize<'de>>(&self, endpoint: &str) -> Result<T> {
-        let url = format!("https://api.football-data.org/v4/competitions/{endpoint}");
+    async fn fetch<T: for<'de> serde::Deserialize<'de>>(&self, path: &str) -> Result<T> {
+        let url = format!("https://api.football-data.org/v4/{path}");
 
         let response = self
             .client
@@ -33,10 +33,17 @@ impl ApiClient {
     }
 
     pub async fn fetch_matches(&self, league: League) -> Result<MatchesResponse> {
-        self.fetch(&format!("{}/matches", league.code())).await
+        self.fetch(&format!("competitions/{}/matches", league.code()))
+            .await
     }
 
     pub async fn fetch_standings(&self, league: League) -> Result<StandingsResponse> {
-        self.fetch(&format!("{}/standings", league.code())).await
+        self.fetch(&format!("competitions/{}/standings", league.code()))
+            .await
     }
+
+    /// Fetch all matches across every available competition (`GET /v4/matches`).
+    pub async fn fetch_all_matches(&self) -> Result<MatchesResponse> {
+        self.fetch("matches").await
+    }
 }
blob - a8b65c5ed9f1937c3e1892d3ceb6c04fa015e7f5
blob + 5897e9be4594d4f9c867423ddb314c8f960e0657
--- src/config.rs
+++ src/config.rs
@@ -17,7 +17,7 @@ pub struct Cli {
     #[arg(long, short = 's')]
     pub standings: bool,
 
-    /// Show all matches (past and future)
+    /// List all matches across every competition (default; ignores --league)
     #[arg(long, short = 'a')]
     pub all: bool,
 
@@ -25,9 +25,9 @@ pub struct Cli {
     #[arg(long, short = 'f')]
     pub filter: Option<String>,
 
-    /// League to display
-    #[arg(long, short = 'l', default_value = "epl", value_name = "LEAGUE")]
-    pub league: String,
+    /// League to display (defaults to all competitions when omitted)
+    #[arg(long, short = 'l', value_name = "LEAGUE")]
+    pub league: Option<String>,
 }
 
 impl Cli {
@@ -50,7 +50,7 @@ impl Cli {
 
 pub struct Config {
     pub api_token: String,
-    pub league: League,
+    pub league: Option<League>,
     pub show_all: bool,
     pub show_standings: bool,
     pub team_filter: Option<String>,
@@ -62,8 +62,12 @@ impl Config {
             return Err(AppError::InvalidToken);
         }
 
-        let league = League::from_arg(&cli.league)
-            .ok_or_else(|| AppError::InvalidLeague(cli.league.clone()))?;
+        let league = match &cli.league {
+            Some(arg) => {
+                Some(League::from_arg(arg).ok_or_else(|| AppError::InvalidLeague(arg.clone()))?)
+            }
+            None => None,
+        };
 
         Ok(Self {
             api_token: cli.token.clone(),
@@ -86,25 +90,39 @@ mod tests {
             standings: false,
             all: true,
             filter: Some("arsenal".to_string()),
-            league: "epl".to_string(),
+            league: Some("epl".to_string()),
         };
 
         let config = Config::from_cli(&cli).unwrap();
         assert_eq!(config.api_token, "test-token");
-        assert_eq!(config.league, League::PremierLeague);
+        assert_eq!(config.league, Some(League::PremierLeague));
         assert!(config.show_all);
         assert!(!config.show_standings);
         assert_eq!(config.team_filter, Some("arsenal".to_string()));
     }
 
     #[test]
+    fn test_config_no_league_defaults_to_all() {
+        let cli = Cli {
+            token: "test-token".to_string(),
+            standings: false,
+            all: false,
+            filter: None,
+            league: None,
+        };
+
+        let config = Config::from_cli(&cli).unwrap();
+        assert_eq!(config.league, None);
+    }
+
+    #[test]
     fn test_config_missing_token() {
         let cli = Cli {
             token: String::new(),
             standings: false,
             all: false,
             filter: None,
-            league: "epl".to_string(),
+            league: Some("epl".to_string()),
         };
 
         let result = Config::from_cli(&cli);
@@ -118,7 +136,7 @@ mod tests {
             standings: false,
             all: false,
             filter: None,
-            league: "bundesliga".to_string(),
+            league: Some("bundesliga".to_string()),
         };
 
         let result = Config::from_cli(&cli);
blob - 347f29874df4b5a0b632dff6605f571c35d709cf
blob + 5108e2b76716a655a1dddcb1c3933c17f2419f42
--- src/display.rs
+++ src/display.rs
@@ -59,7 +59,7 @@ pub fn filter_matches(
         .collect()
 }
 
-pub fn display_table(matches: &[Match]) {
+pub fn display_table(matches: &[Match], show_competition: bool) {
     if matches.is_empty() {
         println!("No matches found.");
         return;
@@ -68,14 +68,20 @@ pub fn display_table(matches: &[Match]) {
     let mut table = Table::new();
     table.set_format(*format::consts::FORMAT_BOX_CHARS);
 
-    table.add_row(Row::new(vec![
+    let mut header = vec![
         Cell::new("MD").style_spec("Fb"),
         Cell::new("Date & Time").style_spec("Fb"),
+    ];
+    if show_competition {
+        header.push(Cell::new("Competition").style_spec("Fb"));
+    }
+    header.extend([
         Cell::new("Home Team").style_spec("Fb"),
         Cell::new("Score").style_spec("Fb"),
         Cell::new("Away Team").style_spec("Fb"),
         Cell::new("Status").style_spec("Fb"),
-    ]));
+    ]);
+    table.add_row(Row::new(header));
 
     for m in matches {
         let matchday = m
@@ -101,14 +107,22 @@ pub fn display_table(matches: &[Match]) {
         let home_team = m.home_team.name.as_deref().unwrap_or("Unknown");
         let away_team = m.away_team.name.as_deref().unwrap_or("Unknown");
 
-        table.add_row(Row::new(vec![
-            Cell::new(&matchday),
-            Cell::new(&date),
+        let mut cells = vec![Cell::new(&matchday), Cell::new(&date)];
+        if show_competition {
+            let competition = m
+                .competition
+                .as_ref()
+                .and_then(|c| c.name.as_deref())
+                .unwrap_or("-");
+            cells.push(Cell::new(competition));
+        }
+        cells.extend([
             Cell::new(home_team).style_spec("r"),
             Cell::new(&score).style_spec("Fyc"),
             Cell::new(away_team).style_spec("l"),
             Cell::new(&format!("{status_icon} {status}")),
-        ]));
+        ]);
+        table.add_row(Row::new(cells));
     }
 
     table.printstd();
@@ -185,6 +199,7 @@ mod tests {
             score: Score {
                 full_time: ScoreDetail::default(),
             },
+            competition: None,
         }
     }
 
blob - 57f4ccdad5733bfc9aa180cc26d155087638c2a4
blob + 0480fbe511e4a4c5fd270d5eb5510c849f7f15ed
--- src/main.rs
+++ src/main.rs
@@ -7,6 +7,7 @@ mod models;
 
 use config::Cli;
 use error::Result;
+use league::League;
 
 #[tokio::main]
 async fn main() -> Result<()> {
@@ -15,16 +16,19 @@ async fn main() -> Result<()> {
     let api_client = api::ApiClient::new(config.api_token);
 
     if config.show_standings {
-        let standings = api_client.fetch_standings(config.league).await?;
+        let league = config.league.unwrap_or(League::PremierLeague);
+        let standings = api_client.fetch_standings(league).await?;
         display::display_standings(standings);
+    } else if let (false, Some(league)) = (config.show_all, config.league) {
+        let response = api_client.fetch_matches(league).await?;
+        let filtered =
+            display::filter_matches(response.matches, config.team_filter.as_deref(), false);
+        display::display_table(&filtered, false);
     } else {
-        let response = api_client.fetch_matches(config.league).await?;
-        let filtered = display::filter_matches(
-            response.matches,
-            config.team_filter.as_deref(),
-            config.show_all,
-        );
-        display::display_table(&filtered);
+        let response = api_client.fetch_all_matches().await?;
+        let filtered =
+            display::filter_matches(response.matches, config.team_filter.as_deref(), true);
+        display::display_table(&filtered, true);
     }
 
     Ok(())
blob - 51c9addaf1d8677e06267a74af7c42de3076a433
blob + 1097cba7f660902243a139389e3b32ad1f046833
--- src/models.rs
+++ src/models.rs
@@ -10,9 +10,15 @@ pub struct Match {
     pub home_team: Team,
     pub away_team: Team,
     pub score: Score,
+    pub competition: Option<Competition>,
 }
 
 #[derive(Debug, Deserialize, Clone)]
+pub struct Competition {
+    pub name: Option<String>,
+}
+
+#[derive(Debug, Deserialize, Clone)]
 pub struct Team {
     pub name: Option<String>,
     pub tla: Option<String>,