devalang_wasm/tools/cli/
mod.rs

1// Parent `tools` module controls `cli` gating; avoid duplicating crate-level cfg here.
2mod commands;
3pub mod config;
4pub mod io;
5pub mod state;
6
7use anyhow::Result;
8use clap::{Parser, Subcommand};
9use commands::devices::DevicesListCommand;
10use commands::play::PlayCommand;
11use state::CliContext;
12
13#[derive(Parser, Debug)]
14#[command(name = "devalang")]
15#[command(
16    version,
17    about = "🦊 Devalang – A programming language for music and sound."
18)]
19pub struct Cli {
20    #[command(subcommand)]
21    command: Commands,
22}
23
24#[derive(Subcommand, Debug)]
25pub enum Commands {
26    /// Build and play deva file(s)
27    Play(PlayCommand),
28    /// Initialize a new project
29    Init(commands::init::InitCommand),
30    /// Builds deva file(s)
31    Build(commands::build::BuildCommand),
32    /// Check syntax without building
33    Check(commands::check::CheckCommand),
34    /// Manages addons (install, update, remove, list, discover)
35    Addon(commands::addon::AddonCommand),
36    /// Login to Devalang (authenticate with token)
37    Login {
38        /// Authentication token (optional, will prompt if not provided)
39        token: Option<String>,
40    },
41    /// Logout from Devalang
42    Logout,
43    /// Check authentication status
44    Me,
45    /// Manage telemetry settings
46    Telemetry {
47        #[command(subcommand)]
48        action: TelemetryAction,
49    },
50    /// Manage MIDI devices
51    Devices {
52        #[command(subcommand)]
53        action: DevicesCommands,
54    },
55}
56
57#[derive(Subcommand, Debug)]
58pub enum DevicesCommands {
59    /// List MIDI devices
60    List(DevicesListCommand),
61    /// Preview incoming/outgoing notes (non-writing)
62    Preview(commands::devices::DevicesLiveCommand),
63    /// Record incoming notes and write to a file
64    Write(commands::devices::DevicesWriteCommand),
65}
66
67#[derive(Subcommand, Debug)]
68pub enum TelemetryAction {
69    /// Enable telemetry
70    Enable,
71    /// Disable telemetry
72    Disable,
73    /// Show telemetry status
74    Status,
75}
76
77pub fn run() -> Result<()> {
78    let cli = Cli::parse();
79    let ctx = CliContext::new();
80    let runtime = tokio::runtime::Runtime::new()?;
81
82    runtime.block_on(async move {
83        match cli.command {
84            Commands::Play(command) => commands::play::execute(command, &ctx).await?,
85            Commands::Init(command) => command.execute(&ctx).await?,
86            Commands::Build(command) => command.execute(&ctx).await?,
87            Commands::Check(command) => command.execute(&ctx).await?,
88            Commands::Addon(command) => command.execute(&ctx).await?,
89            Commands::Login { token } => commands::auth::login(token).await?,
90            Commands::Logout => commands::auth::logout().await?,
91            Commands::Me => commands::auth::check_auth_status().await?,
92            Commands::Telemetry { action } => {
93                let logger = ctx.logger();
94                match action {
95                    TelemetryAction::Enable => {
96                        config::telemetry::enable_telemetry()?;
97                        logger.success("Telemetry enabled");
98                        logger.info("Thank you for helping us improve Devalang!");
99                    }
100                    TelemetryAction::Disable => {
101                        config::telemetry::disable_telemetry()?;
102                        logger.success("Telemetry disabled");
103                    }
104                    TelemetryAction::Status => {
105                        let status = config::telemetry::get_telemetry_status();
106                        logger.info(format!("Telemetry is currently: {}", status));
107                    }
108                }
109            }
110            Commands::Devices { action } => match action {
111                DevicesCommands::List(cmd) => {
112                    commands::devices::execute_list(cmd, &ctx)?;
113                }
114                DevicesCommands::Preview(cmd) => {
115                    commands::devices::execute_preview(cmd, &ctx).await?;
116                }
117                DevicesCommands::Write(cmd) => {
118                    commands::devices::execute_write(cmd, &ctx).await?;
119                }
120            },
121        }
122        Ok(())
123    })
124}