From 204e26a3242ede43f32af79d69c5b966ab9bfe19 Mon Sep 17 00:00:00 2001 From: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Date: Sat, 17 Jan 2026 01:03:24 +0200 Subject: [PATCH] feat: cli --- app/tek.rs | 134 +++++++++++++++++++++++++++------------------ device/arranger.rs | 19 +++++++ 2 files changed, 99 insertions(+), 54 deletions(-) diff --git a/app/tek.rs b/app/tek.rs index 82ee7dda..2964aba6 100644 --- a/app/tek.rs +++ b/app/tek.rs @@ -145,6 +145,22 @@ pub mod model { pub mod core { use super::{*, model::*, gui::*}; impl App { + pub fn new ( + jack: &Jack<'static>, + project: Arrangement, + config: Config, + mode: impl AsRef + ) -> Self { + Self { + color: ItemTheme::random(), + dialog: Dialog::welcome(), + jack: jack.clone(), + mode: config.modes.clone().read().unwrap().get(mode.as_ref()).cloned().unwrap(), + config, + project, + ..Default::default() + } + } pub fn update_clock (&self) { ViewCache::update_clock(&self.project.clock.view_cache, self.clock(), self.size.w() > 80) } @@ -847,7 +863,7 @@ pub mod glue { } /// Command-line configuration. #[cfg(feature = "cli")] pub mod cli { - use super::{*, model::*, gui::*}; + use super::{*, model::*}; use clap::{self, Parser, Subcommand}; /// CLI banner. const HEADER: &'static str = r#" @@ -866,7 +882,7 @@ pub mod glue { /// Pre-defined configuration modes. /// /// TODO: Replace these with scripted configurations. - #[command(subcommand)] mode: Option, + #[command(subcommand)] action: Action, /// Name of JACK client #[arg(short='n', long)] name: Option, /// Whether to attempt to become transport master @@ -895,10 +911,22 @@ pub mod glue { #[arg(short='R', long)] right_to: Vec, } /// Application modes - #[derive(Debug, Clone, Subcommand)] - enum LaunchMode { + #[derive(Debug, Clone, Subcommand, Default)] + enum Action { + /// Continue where you left off + #[default] Resume, + /// Show version. + Version, + /// Show configuration. + Config, + /// Show status of current session. + Status, + /// Run headlessly in current session. + Headless, /// Create a new session instead of loading the previous one. New, + /// Create new session from importable file. + Import, } impl Cli { fn midi_froms (&self) -> Vec { @@ -908,63 +936,61 @@ pub mod glue { Connect::collect(&self.midi_to, &[] as &[&str], &self.midi_to_re) } pub fn run (&self) -> Usually<()> { - let name = self.name.as_ref().map_or("tek", |x|x.as_str()); - let tracks = vec![]; - let scenes = vec![]; - let empty = &[] as &[&str]; - let left_froms = Connect::collect(&self.left_from, empty, empty); - let left_tos = Connect::collect(&self.left_to, empty, empty); - let right_froms = Connect::collect(&self.right_from, empty, empty); - let right_tos = Connect::collect(&self.right_to, empty, empty); - let _audio_froms = &[left_froms.as_slice(), right_froms.as_slice()]; - let _audio_tos = &[left_tos.as_slice(), right_tos.as_slice()]; - let mut config = Config::new(None); - config.init()?; - Tui::new()?.run(&Jack::new_run(&name, move|jack|{ - let midi_ins = { + if matches!(self.action, Action::Version) { + println!("todo version"); + } else { + let mut config = Config::new(None); + config.init()?; + if matches!(self.action, Action::Config) { + println!("{config:#?}"); + } else { + let name = self.name.as_ref().map_or("tek", |x|x.as_str()); + let jack = Jack::new(&name)?; + let tracks = vec![]; + let scenes = vec![]; + let empty = &[] as &[&str]; + let left_froms = Connect::collect(&self.left_from, empty, empty); + let left_tos = Connect::collect(&self.left_to, empty, empty); + let right_froms = Connect::collect(&self.right_from, empty, empty); + let right_tos = Connect::collect(&self.right_to, empty, empty); + let _audio_froms = &[left_froms.as_slice(), right_froms.as_slice()]; + let _audio_tos = &[left_tos.as_slice(), right_tos.as_slice()]; let mut midi_ins = vec![]; + let mut midi_outs = vec![]; for (index, connect) in self.midi_froms().iter().enumerate() { midi_ins.push(jack.midi_in(&format!("M/{index}"), &[connect.clone()])?); } - midi_ins - }; - let midi_outs = { - let mut midi_outs = vec![]; for (index, connect) in self.midi_tos().iter().enumerate() { midi_outs.push(jack.midi_out(&format!("{index}/M"), &[connect.clone()])?); }; - midi_outs - }; - let project = Arrangement { - name: Default::default(), - color: ItemTheme::random(), - jack: jack.clone(), - clock: Clock::new(&jack, self.bpm)?, - tracks, - scenes, - selection: Selection::TrackClip { track: 0, scene: 0 }, - midi_ins, - midi_outs, - ..Default::default() - }; - let app = App { - jack: jack.clone(), - color: ItemTheme::random(), - dialog: Dialog::welcome(), - mode: config.modes.clone().read().unwrap().get(":menu").cloned().unwrap(), - config, - project, - ..Default::default() - }; - jack.sync_lead(self.sync_lead, |mut state|{ - let clock = app.clock(); - clock.playhead.update_from_sample(state.position.frame() as f64); - state.position.bbt = Some(clock.bbt()); - state.position - })?; - jack.sync_follow(self.sync_follow)?; - Ok(app) - })?) + let clock = Clock::new(&jack, self.bpm)?; + let project = Arrangement::new( + &jack, None, clock, tracks, scenes, midi_ins, midi_outs + ); + if matches!(self.action, Action::Status) { + println!("{project:?}"); + // TODO git integration + } else { + let app = App::new(&jack, project, config, ":menu"); + let client = jack.run(move|jack|{ + jack.sync_lead(self.sync_lead, |mut state|{ + let clock = app.clock(); + clock.playhead.update_from_sample(state.position.frame() as f64); + state.position.bbt = Some(clock.bbt()); + state.position + })?; + jack.sync_follow(self.sync_follow)?; + Ok(app) + })?; + if matches!(self.action, Action::Headless) { + println!("todo headless"); + } else { + return Tui::new()?.run(&client) + } + } + } + } + Ok(()) } } } diff --git a/device/arranger.rs b/device/arranger.rs index 10a624b1..80bc19cc 100644 --- a/device/arranger.rs +++ b/device/arranger.rs @@ -74,6 +74,25 @@ impl Arrangement { } impl Arrangement { + /// Create a new arrangement. + pub fn new ( + jack: &Jack<'static>, + name: Option>, + clock: Clock, + tracks: Vec, + scenes: Vec, + midi_ins: Vec, + midi_outs: Vec, + ) -> Self { + Self { + clock, tracks, scenes, midi_ins, midi_outs, + jack: jack.clone(), + name: name.unwrap_or_default(), + color: ItemTheme::random(), + selection: Selection::TrackClip { track: 0, scene: 0 }, + ..Default::default() + } + } /// Width of display pub fn w (&self) -> u16 { self.size.w() as u16