feat: implement idx-cli MVP foundation, provider abstraction, and core quote/history commands

This commit is contained in:
Ciphercat 2026-03-05 17:54:52 +00:00
commit 2174b42cff
18 changed files with 2678 additions and 0 deletions

13
src/cli/cache.rs Normal file
View file

@ -0,0 +1,13 @@
use clap::{Args, Subcommand};
#[derive(Debug, Args)]
pub struct CacheCmd {
#[command(subcommand)]
pub command: CacheSubcommand,
}
#[derive(Debug, Subcommand)]
pub enum CacheSubcommand {
Info,
Clear,
}

15
src/cli/config.rs Normal file
View file

@ -0,0 +1,15 @@
use clap::{Args, Subcommand};
#[derive(Debug, Args)]
pub struct ConfigCmd {
#[command(subcommand)]
pub command: ConfigSubcommand,
}
#[derive(Debug, Subcommand)]
pub enum ConfigSubcommand {
Init,
Get { key: String },
Set { key: String, value: String },
Path,
}

38
src/cli/mod.rs Normal file
View file

@ -0,0 +1,38 @@
pub mod cache;
pub mod config;
pub mod stocks;
use clap::{Parser, Subcommand, ValueEnum};
use crate::output::OutputFormat;
#[derive(Debug, Clone, ValueEnum)]
pub enum Shell {
Bash,
Zsh,
Fish,
}
#[derive(Debug, Parser)]
#[command(name = "idx", about = "Indonesian stock analysis CLI")]
pub struct Cli {
#[arg(short, long, value_enum, global = true, default_value_t = OutputFormat::Table)]
pub output: OutputFormat,
#[arg(long, global = true)]
pub no_color: bool,
#[arg(short, long, global = true)]
pub quiet: bool,
#[arg(short, long, global = true, action = clap::ArgAction::Count)]
pub verbose: u8,
#[command(subcommand)]
pub command: Commands,
}
#[derive(Debug, Subcommand)]
pub enum Commands {
Stocks(stocks::StocksCmd),
Config(config::ConfigCmd),
Cache(cache::CacheCmd),
Completions { shell: Shell },
Version,
}

51
src/cli/stocks.rs Normal file
View file

@ -0,0 +1,51 @@
use clap::{Args, Subcommand};
use crate::api::types::{Interval, Period};
use crate::api::MarketDataProvider;
use crate::config::IdxConfig;
use crate::error::IdxError;
use crate::output::{render_history, render_quotes};
#[derive(Debug, Args)]
pub struct StocksCmd {
#[command(subcommand)]
pub command: StocksSubcommand,
}
#[derive(Debug, Subcommand)]
pub enum StocksSubcommand {
Quote { symbols: Vec<String> },
History {
symbol: String,
#[arg(long, value_enum, default_value_t = Period::ThreeMonths)]
period: Period,
#[arg(long, value_enum, default_value_t = Interval::Day)]
interval: Interval,
},
}
pub fn handle(
cmd: &StocksCmd,
config: &IdxConfig,
provider: &dyn MarketDataProvider,
) -> Result<(), IdxError> {
match &cmd.command {
StocksSubcommand::Quote { symbols } => {
let mut quotes = Vec::new();
for sym in symbols.iter().flat_map(|s| s.split(',')) {
let resolved = crate::api::resolve_symbol(sym, &config.exchange);
quotes.push(provider.quote(&resolved)?);
}
render_quotes(&quotes, &config.output, config.no_color)
}
StocksSubcommand::History {
symbol,
period,
interval,
} => {
let resolved = crate::api::resolve_symbol(symbol, &config.exchange);
let history = provider.history(&resolved, period, interval)?;
render_history(&resolved, &history, &config.output)
}
}
}