feat: cli

This commit is contained in:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 2026-01-17 01:03:24 +02:00
parent b1074bd831
commit 204e26a324
2 changed files with 99 additions and 54 deletions

View file

@ -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<str>
) -> 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<LaunchMode>,
#[command(subcommand)] action: Action,
/// Name of JACK client
#[arg(short='n', long)] name: Option<String>,
/// Whether to attempt to become transport master
@ -895,10 +911,22 @@ pub mod glue {
#[arg(short='R', long)] right_to: Vec<String>,
}
/// 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<Connect> {
@ -908,7 +936,16 @@ pub mod glue {
Connect::collect(&self.midi_to, &[] as &[&str], &self.midi_to_re)
}
pub fn run (&self) -> Usually<()> {
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];
@ -918,44 +955,24 @@ pub mod glue {
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 = {
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()
};
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);
@ -964,7 +981,16 @@ pub mod glue {
})?;
jack.sync_follow(self.sync_follow)?;
Ok(app)
})?)
})?;
if matches!(self.action, Action::Headless) {
println!("todo headless");
} else {
return Tui::new()?.run(&client)
}
}
}
}
Ok(())
}
}
}

View file

@ -74,6 +74,25 @@ impl Arrangement {
}
impl Arrangement {
/// Create a new arrangement.
pub fn new (
jack: &Jack<'static>,
name: Option<Arc<str>>,
clock: Clock,
tracks: Vec<Track>,
scenes: Vec<Scene>,
midi_ins: Vec<MidiInput>,
midi_outs: Vec<MidiOutput>,
) -> 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