fix warnings, cleanup

This commit is contained in:
i do not exist 2026-08-12 18:59:19 +03:00
parent 406aabde6e
commit da2099c52e
10 changed files with 379 additions and 450 deletions

View file

@ -1,44 +1,6 @@
#![allow(clippy::unit_arg)]
#![feature(impl_trait_in_assoc_type)] // Used by EntriesIterator; TODO remove
pub extern crate atomic_float;
pub extern crate xdg;
pub extern crate tengri;
#[cfg(feature = "cli")]
pub(crate) use ::clap::{self, Parser, Subcommand};
#[allow(unused)]
pub(crate) use ::{
std::{
cmp::Ord,
collections::BTreeMap,
error::Error,
ffi::OsString,
fmt::{Write, Debug, Formatter},
fs::File,
ops::{Add, Sub, Mul, Div, Rem},
path::{Path, PathBuf},
sync::{Arc, RwLock, atomic::{AtomicBool, AtomicUsize, AtomicU64, Ordering::Relaxed}},
time::Duration,
thread::{spawn, JoinHandle},
},
xdg::{
BaseDirectories,
},
tengri::{
*,
dizzle::*,
midly::{
Smf, TrackEventKind, MidiMessage, Error as MidiError,
num::*,
live::*,
},
crossterm::event::{Event, KeyEvent},
ratatui::{
self,
prelude::{Rect, Style, Stylize, Buffer, Color::{self, *}},
widgets::{Widget, canvas::{Canvas, Line}},
},
},
};
//#![feature(impl_trait_in_assoc_type)] // Used by EntriesIterator; TODO remove
mod deps; pub use self::deps::*;
/// Banner.
pub(crate) const HEADER: &'static str = r#"
@ -88,6 +50,27 @@ fn run_new_plain (config: Config) -> Usually<()> {
})?)
}
//pub fn tui (
//app: Arc<RwLock<App>>,
//jack: Jack,
//sync_lead: &bool,
//sync_follow: &bool,
//) -> Usually<()> {
//// Run the [Tui] and [Jack] threads with the [App] state.
//Tui::run_main(&jack.run(move|jack|{
//// Between jack init and app's first cycle:
////jack.sync_lead(*sync_lead, |mut state|{
////let clock = app.write().unwrap().clock();
////clock.playhead.update_from_sample(state.position.frame() as f64);
////state.position.bbt = Some(clock.bbt());
////state.position
////})?;
////jack.sync_follow(*sync_follow)?;
//// FIXME: They don't work properly.
//Ok(app)
//})?)?
//}
#[cfg(feature = "cli")] pub mod cli {
use crate::*;
@ -174,7 +157,7 @@ fn run_new_plain (config: Config) -> Usually<()> {
#[arg(short='n', long)] name: Option<String>,
/// Whether to attempt to become transport master
#[arg(short='Y', long, default_value_t = false)] sync_lead: bool,
/// Whether to sync to external transport master
/// Whether to sync to external transport master
#[arg(short='y', long, default_value_t = true)] sync_follow: bool,
/// Initial tempo in beats per minute
#[arg(short='b', long, default_value = None)] bpm: Option<f64>,
@ -238,14 +221,8 @@ fn run_new_plain (config: Config) -> Usually<()> {
.chain(
connect_audio_outs(&jack, &"R".to_string(), &right_to, None)?.into_iter()
));
//&jack, Clock::new(&jack, *bpm)?, &lf, &lt, &rf, &rt, &mf, &mt, &mfr, &mtr)?;
proj.tracks_add_many(tracks.unwrap_or(0), None, [].into(), [].into())?;
proj.scenes_add_many(scenes.unwrap_or(0))?;
//if matches!(self, Action::Status) {
//// Show status and exit
//tek_print_status(&proj);
//return Ok(())
//}
Ok(proj)
}
}
@ -325,11 +302,14 @@ mod config {
}
impl Config {
/// Default configuration directory.
const CONFIG_DIR: &'static str = "tek";
/// Default configuration subdirectory.
const CONFIG_SUB: &'static str = "v0";
/// Default configuration file name.
const CONFIG: &'static str = "tek.edn";
/// Default configuration contents.
const DEFAULTS: &'static str = include_str!("tek.edn");
/// Create a new app configuration from a set of XDG base directories,
pub fn new (dirs: Option<BaseDirectories>) -> Self {
Self {
@ -340,20 +320,20 @@ mod config {
..Default::default()
}
}
/// Create, initialize, and watch a new configuration.
pub fn watched <T> (callback: impl FnOnce(Arc<Self>)->T) -> Usually<T> {
let config = Self::init_new(None)?;
Self::watch(config.clone(), None)?;
let result = callback(config);
Ok(result)
}
/// Create and initialize a new configuration.
pub fn init_new (_dirs: Option<BaseDirectories>) -> Usually<Arc<Self>> {
let config = Arc::new(Self::new(None));
config.init()?;
Ok(config)
}
/// Watch a config's file for changes.
pub fn watch (config: Arc<Self>, poll: Option<Duration>) -> Usually<()> {
let handler = {
let config = config.clone();
@ -383,19 +363,18 @@ mod config {
Err(format!("no config path").into())
}
}
/// Find the config file.
fn find_file (&self) -> Option<PathBuf> {
self.dirs.find_config_file(Self::CONFIG)
}
/// Place config file in default location.
fn place_file (&self) -> Result<PathBuf, std::io::Error> {
self.dirs.place_config_file(Self::CONFIG)
}
/// Get path to config file.
fn get_file (&self) -> Option<PathBuf> {
self.dirs.get_config_file(Self::CONFIG)
}
/// Write initial contents of configuration.
pub fn init (&self) -> Usually<()> {
//println!("\r\ninit {}", quanta::Clock::new().raw());
@ -405,13 +384,9 @@ mod config {
Ok(())
})
}
/// Write initial contents of a configuration file.
pub fn load (
&self,
path: &str,
defaults: &str,
mut each: impl FnMut(&Self, &str)->Usually<()>
pub fn load <F: FnMut(&Self, &str)->Usually<()>> (
&self, path: &str, defaults: &str, mut each: F
) -> Usually<()> {
self.stamp.store(quanta::Clock::new().raw(), Relaxed);
if self.find_file().is_none() {
@ -426,19 +401,18 @@ mod config {
return Err(format!("{path}: not found").into())
})
}
/// Add statements to configuration from [Dsl] source.
pub fn add (&self, dsl: impl Language) -> Usually<&Self> {
dsl.each(|item|self.add_one(item))?;
Ok(self)
}
/// Make this configuration empty.
fn clear (&self) {
*self.modes.0.write().unwrap() = Default::default();
*self.views.write().unwrap() = Default::default();
*self.binds.write().unwrap() = Default::default();
}
/// Add one entry to the configuration.
fn add_one (&self, item: impl Language) -> Usually<()> {
if let Some(expr) = item.expr()? {
let head = expr.head()?;
@ -458,74 +432,35 @@ mod config {
return Err(format!("Config::load: expected expr, got: {item:?}").into())
}
}
/// Get a mode by name.
pub fn get_mode (&self, mode: impl AsRef<str>) -> Option<Arc<Mode<Arc<str>>>> {
self.modes.get(mode)
}
/// Print the configuration.
pub fn print (&self) {
use ::ansi_term::Color::*;
println!("{:?}", self.dirs);
for (k, v) in self.views.read().unwrap().iter() {
println!("{} {} {v}", Green.paint("VIEW"), Green.bold().paint(format!("{k:<16}")));
}
for (k, v) in self.binds.read().unwrap().iter() {
println!("{} {}", Green.paint("BIND"), Green.bold().paint(format!("{k:<16}")));
for (k, v) in v.0.iter() {
print!("{} ", &Yellow.paint(match &k.0 {
Event::Key(KeyEvent { modifiers, .. }) =>
format!("{:>16}", format!("{modifiers}")),
_ => unimplemented!()
}));
print!("{}", &Yellow.bold().paint(match &k.0 {
Event::Key(KeyEvent { code, .. }) =>
format!("{:<10}", format!("{code}")),
_ => unimplemented!()
}));
for v in v.iter() {
print!(" => {:?}", v.commands);
print!(" {}", v.condition.as_ref().map(|x|format!("{x:?}")).unwrap_or_default());
println!(" {}", v.description.as_ref().map(|x|x.as_ref()).unwrap_or_default());
//println!(" {:?}", v.source);
}
}
}
self.modes.for_each(|k, v|{
println!();
for v in v.name.iter() { print!("{}", Green.bold().paint(format!("{v} "))); }
for v in v.info.iter() { print!("\n{}", Green.paint(format!("{v}"))); }
print!("\n{} {}", Blue.paint("TOOL"), Green.bold().paint(format!("{k:<16}")));
print!("\n{}", Blue.paint("KEYS"));
for v in v.keys.iter() { print!("{}", Green.paint(format!(" {v}"))); }
println!();
v.modes.for_each(|k, v|{
print!("{} {} {:?}", Blue.paint("MODE"), Green.bold().paint(format!("{k:<16}")), v.name);
print!( " INFO={:?}", v.info);
print!( " VIEW={:?}", v.view);
println!(" KEYS={:?}", v.keys);
});
print!("{}", Blue.paint("VIEW"));
for v in v.view.iter() { print!("{}", Green.paint(format!(" {v}"))); }
println!();
});
print_config(self)
}
}
impl Modes {
/// Register a mode.
pub fn add (&self, name: &impl AsRef<str>, body: &impl Language) -> Usually<()> {
let mut mode = Mode::default();
body.each(|item|mode.add(item))?;
self.0.write().unwrap().insert(name.as_ref().into(), Arc::new(mode));
Ok(())
}
/// Get a mode by name.
pub fn get (&self, name: impl AsRef<str>) -> Option<Arc<Mode<Arc<str>>>> {
self.0.read().unwrap().get(name.as_ref()).cloned()
}
/// Run something for each mode.
pub fn for_each <T> (&self, mut ator: impl FnMut(&str, &Mode<Arc<str>>)->T) {
for (k, v) in self.0.read().unwrap().iter() {
let _ = ator(k.as_ref(), v.as_ref());
}
}
/// Count modes.
pub fn len (&self) -> usize {
self.0.read().unwrap().len()
}
@ -562,34 +497,24 @@ mod config {
} else {
return Err(format!("Mode::add: unexpected: {dsl:?}").into());
})
//DslParse(dsl, ||Err(format!("Mode::add: unexpected: {dsl:?}").into()))
//.word(|word|self.add_view(word))
//.expr(|expr|expr.head(|head|{
////println!("Mode::add: {head} {:?}", expr.tail());
//let tail = expr.tail()?.map(|x|x.trim()).unwrap_or("");
//match head {
//"name" => self.add_name(tail),
//"info" => self.add_info(tail),
//"keys" => self.add_keys(tail)?,
//"mode" => self.add_mode(tail)?,
//_ => self.add_view(tail),
//};
//}))
}
/// Add a name to the mode.
fn add_name (&mut self, dsl: impl Language) -> Perhaps<()> {
Ok(dsl.src()?.map(|src|self.name.push(src.into())))
}
/// Add a description to the mode.
fn add_info (&mut self, dsl: impl Language) -> Perhaps<()> {
Ok(dsl.src()?.map(|src|self.info.push(src.into())))
}
/// Add a view definition to the mode.
fn add_view (&mut self, dsl: impl Language) -> Perhaps<()> {
Ok(dsl.src()?.map(|src|self.view.push(src.into())))
}
/// Add a keyboard input bindin to the mode.
fn add_keys (&mut self, dsl: impl Language) -> Perhaps<()> {
Ok(Some(dsl.each(|expr|{ self.keys.push(expr.trim().into()); Ok(()) })?))
}
/// Add a submode to the mode.
fn add_mode (&mut self, dsl: impl Language) -> Perhaps<()> {
Ok(Some(if let Some(id) = dsl.head()? {
self.modes.add(&id, &dsl.tail())?;
@ -639,30 +564,27 @@ mod app {
/// let _ = app.project.h_scenes();
/// ```
#[derive(Default, Debug)]
#[namespace(Arc<[Connect]> App::get_arc_array_connect)]
#[namespace(Arc<str> App::get_arc_str)]
#[namespace(Color App::get_color)]
#[namespace(ControlAxis App::get_axis)]
#[namespace(Dialog App::get_dialog)]
#[namespace(MidiClip)]
#[namespace(ItemColor)]
#[namespace(ItemTheme)]
#[namespace(Option<Arc<RwLock<MidiClip>>> App::get_clip)]
#[namespace(Option<Arc<[Connect]>> App::get_opt_arc_array_connect)]
#[namespace(Option<Arc<str>> App::get_opt_arc_str)]
#[namespace(Option<ItemTheme> App::get_opt_itemtheme)]
#[namespace(Option<Vec<Option<Arc<RwLock<MidiClip>>>>> App::get_opt_vec_opt_arc_rwlock_midiclip)]
#[namespace(Option<u16> App::get_opt_u16)]
#[namespace(Option<u7> App::get_opt_u7)]
#[namespace(Option<usize> App::get_opt_usize)]
#[namespace(Option<bool> App::get_opt_bool)]
#[namespace(Selection App::get_selection)]
#[namespace(bool App::get_bool)]
#[namespace(u16 App::get_u16)]
#[namespace(PathBuf App::get_path_buf)]
#[namespace(isize)]
#[namespace(u8)]
#[namespace(usize App::get_usize)]
#[namespace(Arc<[Connect]> get_arc_array_connect)]
#[namespace(Arc<str> get_arc_str)]
#[namespace(Color get_color)]
#[namespace(ControlAxis get_axis)]
#[namespace(Option<Arc<[Connect]>> get_opt_arc_array_connect)]
#[namespace(Option<Arc<str>> get_opt_arc_str)]
#[namespace(Option<ItemTheme> get_opt_itemtheme)]
#[namespace(Option<Vec<Option<Arc<RwLock<MidiClip>>>>> get_opt_vec_opt_arc_rwlock_midiclip)]
#[namespace(Option<u16> get_opt_u16)]
#[namespace(Option<usize> get_opt_usize)]
#[namespace(Option<bool> get_opt_bool)]
#[namespace(bool get_bool)]
#[namespace(u16 get_u16)]
#[namespace(PathBuf get_path_buf)]
#[namespace(usize get_usize)]
#[namespace(Dialog App::get_dialog)]
pub struct App {
/// Exit flag
pub exit: Exit,
@ -701,10 +623,7 @@ mod app {
/// let tek = tek::App::new(None, proj, conf, "hello");
/// ```
pub fn new (
exit: Option<Exit>,
project: Arrangement,
config: Arc<Config>,
mode: impl AsRef<str>
exit: Option<Exit>, project: Arrangement, config: Arc<Config>, mode: impl AsRef<str>
) -> Self {
App {
exit: exit.unwrap_or_default(),
@ -717,157 +636,144 @@ mod app {
..Default::default()
}
}
}
fn get_path_buf (&self, src: impl Language) -> Perhaps<PathBuf> {
todo!()
}
fn get_arc_str (&self, src: impl Language) -> Perhaps<Arc<str>> {
Ok(src.src()?.map(|x|x.into()))
}
fn get_u16 (&self, src: impl Language) -> Perhaps<u16> {
Ok(Some(match src.word()? {
Some(":w/sidebar") => self.project.w_sidebar(self.editor().is_some()),
Some(":h/sample-detail") => 6.max(self.size.h() as u16 * 3 / 9),
_ => return try_to_u16(src)
}))
}
fn get_usize (&self, src: impl Language) -> Perhaps<usize> {
Ok(Some(match src.word()? {
Some(":scene-count") => self.scenes().len(),
Some(":track-count") => self.tracks().len(),
Some(":device-kind") => self.dialog.device_kind().unwrap_or(0),
Some(":device-kind/next") => self.dialog.device_kind_next().unwrap_or(0),
Some(":device-kind/prev") => self.dialog.device_kind_prev().unwrap_or(0),
_ => return try_to_usize(src)
}))
}
fn get_bool (&self, src: impl Language) -> Perhaps<bool> {
src.word()?.map(|word|Ok(match word {
"Y" => true,
"N" => false,
":mode/editor" => self.project.editor.is_some(),
":focused/dialog" => !matches!(self.dialog, Dialog::None),
":focused/message" => matches!(self.dialog, Dialog::Message(..)),
":focused/add_device" => matches!(self.dialog, Dialog::Device(..)),
":focused/browser" => self.dialog.browser().is_some(),
":focused/pool/import" => matches!(self.pool.mode, Some(PoolMode::Import(..))),
":focused/pool/export" => matches!(self.pool.mode, Some(PoolMode::Export(..))),
":focused/pool/rename" => matches!(self.pool.mode, Some(PoolMode::Rename(..))),
":focused/pool/length" => matches!(self.pool.mode, Some(PoolMode::Length(..))),
":focused/clip" => !self.editor_focused() && matches!(self.selection(), Selection::TrackClip{..}),
":focused/track" => !self.editor_focused() && matches!(self.selection(), Selection::Track(..)),
":focused/scene" => !self.editor_focused() && matches!(self.selection(), Selection::Scene(..)),
":focused/mix" => !self.editor_focused() && matches!(self.selection(), Selection::Mix),
_ => return Err(format!("not bool: {word}").into())
})).transpose()
}
fn get_selection (&self, src: impl Language) -> Perhaps<Selection> {
src.word()?.map(|word|Ok(match word {
":select/scene" => self.selection().select_scene(self.tracks().len()),
":select/scene/next" => self.selection().select_scene_next(self.scenes().len()),
":select/scene/prev" => self.selection().select_scene_prev(),
":select/track" => self.selection().select_track(self.tracks().len()),
":select/track/next" => self.selection().select_track_next(self.tracks().len()),
":select/track/prev" => self.selection().select_track_prev(),
_ => return Err(format!("not selection: {word}").into())
})).transpose()
}
fn get_color (&self, src: impl Language) -> Perhaps<Color> {
if let Some(expr) = src.expr()? {
match (expr.head()?, expr.tail()?) {
(Some("g"), Some(tail)) => {
let n = try_to_u8(tail.head().map_err(Into::into))?
.ok_or(LanguageError::Domain("not gray"))?;
Ok(Some(Color::Rgb(n, n, n)))
},
(Some("rgb"), Some(tail)) => {
let r = try_to_u8(tail.head().map_err(Into::into))?
.ok_or(LanguageError::Domain("not red"))?;
let g = try_to_u8(tail.tail().head().map_err(Into::into))?
.ok_or(LanguageError::Domain("not green"))?;
let b = try_to_u8(tail.tail().tail().head().map_err(Into::into))?
.ok_or(LanguageError::Domain("not blue"))?;
Ok(Some(Color::Rgb(r, g, b)))
},
(Some(_), _) => return Err(format!("not a color expression: {expr}").into()),
(None, _) => return Err(format!("not a color expression: {expr}").into()),
}
} else if let Ok(Some(sym)) = src.word() {
Ok(match sym {
":color/bg" => Some(Color::Rgb(28, 32, 36)),
":color/fg" => Some(Color::Rgb(98, 92, 96)),
_ => return Err(format!("not a color: {sym}").into())
})
} else {
return Err(format!("not a color: {:?}", src.src()?).into())
fn get_arc_str (_: &App, src: impl Language) -> Perhaps<Arc<str>> {
Ok(src.src()?.map(|x|x.into()))
}
fn get_u16 (state: &App, src: impl Language) -> Perhaps<u16> {
Ok(Some(match src.word()? {
Some(":w/sidebar") => state.project.w_sidebar(state.editor().is_some()),
Some(":h/sample-detail") => 6.max(state.size.h() as u16 * 3 / 9),
_ => return try_to_u16(src)
}))
}
fn get_usize (state: &App, src: impl Language) -> Perhaps<usize> {
Ok(Some(match src.word()? {
Some(":scene-count") => state.scenes().len(),
Some(":track-count") => state.tracks().len(),
Some(":device-kind") => state.dialog.device_kind().unwrap_or(0),
Some(":device-kind/next") => state.dialog.device_kind_next().unwrap_or(0),
Some(":device-kind/prev") => state.dialog.device_kind_prev().unwrap_or(0),
_ => return try_to_usize(src)
}))
}
fn get_bool (state: &App, src: impl Language) -> Perhaps<bool> {
src.word()?.map(|word|Ok(match word {
"Y" => true,
"N" => false,
":mode/editor" => state.project.editor.is_some(),
":focused/dialog" => !matches!(state.dialog, Dialog::None),
":focused/message" => matches!(state.dialog, Dialog::Message(..)),
":focused/add_device" => matches!(state.dialog, Dialog::Device(..)),
":focused/browser" => state.dialog.browser().is_some(),
":focused/pool/import" => matches!(state.pool.mode, Some(PoolMode::Import(..))),
":focused/pool/export" => matches!(state.pool.mode, Some(PoolMode::Export(..))),
":focused/pool/rename" => matches!(state.pool.mode, Some(PoolMode::Rename(..))),
":focused/pool/length" => matches!(state.pool.mode, Some(PoolMode::Length(..))),
":focused/clip" => !state.editor_focused() && matches!(state.selection(), Selection::TrackClip{..}),
":focused/track" => !state.editor_focused() && matches!(state.selection(), Selection::Track(..)),
":focused/scene" => !state.editor_focused() && matches!(state.selection(), Selection::Scene(..)),
":focused/mix" => !state.editor_focused() && matches!(state.selection(), Selection::Mix),
_ => return Err(format!("not bool: {word}").into())
})).transpose()
}
#[allow(unused)]
fn get_selection (state: &App, src: impl Language) -> Perhaps<Selection> {
src.word()?.map(|word|Ok(match word {
":select/scene" => state.selection().select_scene(state.tracks().len()),
":select/scene/next" => state.selection().select_scene_next(state.scenes().len()),
":select/scene/prev" => state.selection().select_scene_prev(),
":select/track" => state.selection().select_track(state.tracks().len()),
":select/track/next" => state.selection().select_track_next(state.tracks().len()),
":select/track/prev" => state.selection().select_track_prev(),
_ => return Err(format!("not selection: {word}").into())
})).transpose()
}
fn get_color (_: &App, src: impl Language) -> Perhaps<Color> {
if let Some(expr) = src.expr()? {
match (expr.head()?, expr.tail()?) {
(Some("g"), Some(tail)) => {
let n = try_to_u8(tail.head().map_err(Into::into))?
.ok_or(LanguageError::Domain("not gray"))?;
Ok(Some(Color::Rgb(n, n, n)))
},
(Some("rgb"), Some(tail)) => {
let r = try_to_u8(tail.head().map_err(Into::into))?
.ok_or(LanguageError::Domain("not red"))?;
let g = try_to_u8(tail.tail().head().map_err(Into::into))?
.ok_or(LanguageError::Domain("not green"))?;
let b = try_to_u8(tail.tail().tail().head().map_err(Into::into))?
.ok_or(LanguageError::Domain("not blue"))?;
Ok(Some(Color::Rgb(r, g, b)))
},
(Some(_), _) => return Err(format!("not a color expression: {expr}").into()),
(None, _) => return Err(format!("not a color expression: {expr}").into()),
}
} else if let Ok(Some(sym)) = src.word() {
Ok(match sym {
":color/bg" => Some(Color::Rgb(28, 32, 36)),
":color/fg" => Some(Color::Rgb(98, 92, 96)),
_ => return Err(format!("not a color: {sym}").into())
})
} else {
return Err(format!("not a color: {:?}", src.src()?).into())
}
fn get_opt_u7 (&self, src: impl Language) -> Perhaps<Option<u7>> {
src.word()?.map(|word|Ok(match word {
":editor/pitch" => Some((
self.editor().as_ref().map(|e|e.get_note_pos()).unwrap() as u8
).into()),
_ => return Err(format!("unknown midi note: {word}").into())
})).transpose()
}
fn get_opt_u16 (&self, _src: impl Language) -> Perhaps<Option<u16>> {
Ok(None)
}
fn get_opt_usize (&self, src: impl Language) -> Perhaps<Option<usize>> {
src.word()?.map(|word|Ok(match word {
":selected/scene" => self.selection().scene(),
":selected/track" => self.selection().track(),
_ => return Err(format!("unknown opt<usize>: {word}").into())
})).transpose()
}
fn get_clip (&self, src: impl Language) -> Perhaps<Option<Arc<RwLock<MidiClip>>>> {
src.word()?.map(|word|Ok(match word {
":selected/clip" if let Selection::TrackClip { track, scene } = self.selection() =>
self.scenes()[*scene].clips[*track].clone(),
_ => return Err(format!("not a clip: {word}").into())
})).transpose()
}
fn get_axis (&self, src: impl Language) -> Perhaps<ControlAxis> {
Ok(src.word()?.map(|word|Ok(match word {
":x" => ControlAxis::X,
":y" => ControlAxis::Y,
_ => return Err(format!("unknown axis {word}"))
})).transpose()?)
}
fn get_opt_itemtheme (&self, src: impl Language) -> Perhaps<Option<ItemTheme>> {
todo!()
}
fn get_opt_vec_opt_arc_rwlock_midiclip (&self, src: impl Language) -> Perhaps<Option<Vec<Option<Arc<RwLock<MidiClip>>>>>> {
todo!()
}
fn get_opt_arc_array_connect (&self, src: impl Language) -> Perhaps<Option<Arc<[Connect]>>> {
todo!()
}
fn get_arc_array_connect (&self, src: impl Language) -> Perhaps<Arc<[Connect]>> {
todo!()
}
fn get_opt_arc_str (&self, src: impl Language) -> Perhaps<Option<Arc<str>>> {
todo!()
}
fn get_opt_bool (&self, src: impl Language) -> Perhaps<Option<bool>> {
todo!()
}
}
#[allow(unused)]
fn get_opt_u7 (state: &App, src: impl Language) -> Perhaps<Option<u7>> {
src.word()?.map(|word|Ok(match word {
":editor/pitch" => Some((
state.editor().as_ref().map(|e|e.get_note_pos()).unwrap() as u8
).into()),
_ => return Err(format!("unknown midi note: {word}").into())
})).transpose()
}
fn get_opt_usize (state: &App, src: impl Language) -> Perhaps<Option<usize>> {
src.word()?.map(|word|Ok(match word {
":selected/scene" => state.selection().scene(),
":selected/track" => state.selection().track(),
_ => return Err(format!("unknown opt<usize>: {word}").into())
})).transpose()
}
#[allow(unused)]
fn get_clip (state: &App, src: impl Language) -> Perhaps<Option<Arc<RwLock<MidiClip>>>> {
src.word()?.map(|word|Ok(match word {
":selected/clip" if let Selection::TrackClip { track, scene } = state.selection() =>
state.scenes()[*scene].clips[*track].clone(),
_ => return Err(format!("not a clip: {word}").into())
})).transpose()
}
fn get_axis (_: &App, src: impl Language) -> Perhaps<ControlAxis> {
Ok(src.word()?.map(|word|Ok(match word {
":x" => ControlAxis::X,
":y" => ControlAxis::Y,
_ => return Err(format!("unknown axis {word}"))
})).transpose()?)
}
fn get_opt_u16 (_: &App, _src: impl Language) -> Perhaps<Option<u16>> {
Ok(None)
}
fn get_opt_itemtheme (_: &App, _: impl Language) -> Perhaps<Option<ItemTheme>> {
todo!()
}
fn get_opt_vec_opt_arc_rwlock_midiclip (_: &App, _: impl Language) -> Perhaps<Option<Vec<Option<Arc<RwLock<MidiClip>>>>>> {
todo!()
}
fn get_opt_arc_array_connect (_: &App, _: impl Language) -> Perhaps<Option<Arc<[Connect]>>> {
todo!()
}
fn get_arc_array_connect (_: &App, _: impl Language) -> Perhaps<Arc<[Connect]>> {
todo!()
}
fn get_opt_arc_str (_: &App, _: impl Language) -> Perhaps<Option<Arc<str>>> {
todo!()
}
fn get_opt_bool (_: &App, _: impl Language) -> Perhaps<Option<bool>> {
todo!()
}
fn get_path_buf (_: &App, _: impl Language) -> Perhaps<PathBuf> {
todo!()
}
}
@ -959,19 +865,6 @@ mod bind {
}
}
//#[derive(Clone, Debug)]
//pub enum AppCommand {
//Axis(AxisCommand),
//Browse(BrowseCommand),
//Dialog(DialogCommand),
//MidiClip(MidiClipCommand),
//Pool(PoolCommand),
//Scene(SceneCommand),
//Scenes(ScenesCommand),
//Track(TrackCommand),
//Tracks(TracksCommand),
//}
impl_from!(AppCommand: |x: AxisCommand| AppCommand::Axis { command: x });
impl_from!(AppCommand: |x: BrowseCommand| AppCommand::Browse { command: x });
impl_from!(AppCommand: |x: DialogCommand| AppCommand::Dialog { command: x });
@ -1401,27 +1294,6 @@ mod device {
#[cfg(feature = "plugin")] pub use self::plugin::*;
}
//pub fn tui (
//app: Arc<RwLock<App>>,
//jack: Jack,
//sync_lead: &bool,
//sync_follow: &bool,
//) -> Usually<()> {
//// Run the [Tui] and [Jack] threads with the [App] state.
//Tui::run_main(&jack.run(move|jack|{
//// Between jack init and app's first cycle:
////jack.sync_lead(*sync_lead, |mut state|{
////let clock = app.write().unwrap().clock();
////clock.playhead.update_from_sample(state.position.frame() as f64);
////state.position.bbt = Some(clock.bbt());
////state.position
////})?;
////jack.sync_follow(*sync_follow)?;
//// FIXME: They don't work properly.
//Ok(app)
//})?)?
//}
pub use self::draw::*;
mod draw {
use crate::*;
@ -1698,6 +1570,53 @@ mod draw {
}
pub fn print_config (config: &Config) {
use ::ansi_term::Color::*;
println!("{:?}", config.dirs);
for (k, v) in config.views.read().unwrap().iter() {
println!("{} {} {v}", Green.paint("VIEW"), Green.bold().paint(format!("{k:<16}")));
}
for (k, v) in config.binds.read().unwrap().iter() {
println!("{} {}", Green.paint("BIND"), Green.bold().paint(format!("{k:<16}")));
for (k, v) in v.0.iter() {
print!("{} ", &Yellow.paint(match &k.0 {
Event::Key(KeyEvent { modifiers, .. }) =>
format!("{:>16}", format!("{modifiers}")),
_ => unimplemented!()
}));
print!("{}", &Yellow.bold().paint(match &k.0 {
Event::Key(KeyEvent { code, .. }) =>
format!("{:<10}", format!("{code}")),
_ => unimplemented!()
}));
for v in v.iter() {
print!(" => {:?}", v.commands);
print!(" {}", v.condition.as_ref().map(|x|format!("{x:?}")).unwrap_or_default());
println!(" {}", v.description.as_ref().map(|x|x.as_ref()).unwrap_or_default());
//println!(" {:?}", v.source);
}
}
}
config.modes.for_each(|k, v|{
println!();
for v in v.name.iter() { print!("{}", Green.bold().paint(format!("{v} "))); }
for v in v.info.iter() { print!("\n{}", Green.paint(format!("{v}"))); }
print!("\n{} {}", Blue.paint("TOOL"), Green.bold().paint(format!("{k:<16}")));
print!("\n{}", Blue.paint("KEYS"));
for v in v.keys.iter() { print!("{}", Green.paint(format!(" {v}"))); }
println!();
v.modes.for_each(|k, v|{
print!("{} {} {:?}", Blue.paint("MODE"), Green.bold().paint(format!("{k:<16}")), v.name);
print!( " INFO={:?}", v.info);
print!( " VIEW={:?}", v.view);
println!(" KEYS={:?}", v.keys);
});
print!("{}", Blue.paint("VIEW"));
for v in v.view.iter() { print!("{}", Green.paint(format!(" {v}"))); }
println!();
});
}
pub fn print_status (project: &Arrangement) {
println!("Name: {:?}", &project.name);
println!("JACK: {:?}", &project.jack);