bizzle
Some checks are pending
/ build (push) Waiting to run

This commit is contained in:
i do not exist 2026-08-19 18:21:42 +03:00
parent e50c4a5eef
commit e6984915e4
22 changed files with 1002 additions and 294 deletions

2
.gitignore vendored
View file

@ -14,3 +14,5 @@ build/*
!build/Dockerfile.* !build/Dockerfile.*
.misc .misc
.direnv .direnv
callgrind.*
tracing.*

918
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,6 @@
#export RUSTFLAGS := "--cfg procmacro2_semver_exempt -Zmacro-backtrace -Clink-arg=-fuse-ld=mold" #export RUSTFLAGS := "--cfg procmacro2_semver_exempt -Zmacro-backtrace -Clink-arg=-fuse-ld=mold"
export RUST_BACKTRACE := "1" export RUST_BACKTRACE := "1"
export RUSTFLAGS := "-Zmacro-backtrace -Clink-arg=-fuse-ld=mold"
[default] [default]
list: list:

View file

@ -233,7 +233,7 @@ attribute!(commands {
append(disp, quote! { #command::#variant { #params } => state.#ident(#params), }); append(disp, quote! { #command::#variant { #params } => state.#ident(#params), });
append(exps, quote! { append(exps, quote! {
let tail_base = tail; let tail_base = tail;
if head.src()? == Some(#keyword) { if head == Some(#keyword) {
let tail = tail_base; let tail = tail_base;
#obtain #obtain
return Ok(Some(#command::#variant { #params })) return Ok(Some(#command::#variant { #params }))
@ -261,19 +261,13 @@ attribute!(commands {
let tys = Punctuated::<_, Comma>::from_iter(generics.type_params()); let tys = Punctuated::<_, Comma>::from_iter(generics.type_params());
quote! { quote! {
impl<#tys> dizzle::Namespace<#command> for #state { impl<#tys> dizzle::Namespace<#command> for #state {
//def_namespace_symbols!('n |state: Self| -> #command { fn namespace_symbol <L: Language> (&self, word: &L) -> Perhaps<#command> {
//#syms
//});
//def_namespace_exps!('n |state: Self| -> #command {
//#exps
//});
fn namespace_symbol (&self, word: impl Symbol) -> Perhaps<#command> {
if let Some(word) = word.word()? { if let Some(word) = word.word()? {
#syms #syms
} }
Ok(None) Ok(None)
} }
fn namespace_expression (&self, expr: impl Expression) -> Perhaps<#command> { fn namespace_expression <L: Language> (&self, expr: &L) -> Perhaps<#command> {
let state = self; let state = self;
if let Some(expr) = expr.expr()? { if let Some(expr) = expr.expr()? {
let head = expr.head()?; let head = expr.head()?;
@ -303,13 +297,13 @@ attribute!(commands {
) -> TokenStream2 { ) -> TokenStream2 {
quote! { quote! {
impl<T: #state> dizzle::Namespaced<T> for #command { impl<T: #state> dizzle::Namespaced<T> for #command {
fn namespaced_symbol <L: Symbol> (state: &T, word: L) -> Perhaps<#command> { fn namespaced_symbol <L: Language> (state: &T, word: &L) -> Perhaps<Self> {
if let Some(word) = word.word()? { if let Some(word) = word.word()? {
#syms #syms
} }
Ok(None) Ok(None)
} }
fn namespaced_expression <L: Expression> (state: &T, expr: L) -> Perhaps<#command> { fn namespaced_expression <L: Language> (state: &T, expr: &L) -> Perhaps<Self> {
if let Some(expr) = expr.expr()? { if let Some(expr) = expr.expr()? {
let head = expr.head()?; let head = expr.head()?;
let tail = expr.tail()?; let tail = expr.tail()?;

View file

@ -163,17 +163,17 @@ pub(self) fn toggle_bool <U> (
} }
} }
//pub fn per_track <'a, T: Draw<Tui> + 'a, U: TracksSizes<'a>> ( //pub fn per_track <'a, T: Draw<'_, Tui> + 'a, U: TracksSizes<'a>> (
//tracks: impl Fn() -> U + Send + Sync + 'a, //tracks: impl Fn() -> U + Send + Sync + 'a,
//callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a //callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a
//) -> impl Draw<Tui> + 'a { //) -> impl Draw<'_, Tui> + 'a {
//per_track_top(tracks, move|index, track|callback(index, track).full_h().align_y()) //per_track_top(tracks, move|index, track|callback(index, track).full_h().align_y())
//} //}
//pub fn per_track_top <'a, T: Draw<Tui> + 'a, U: TracksSizes<'a>> ( //pub fn per_track_top <'a, T: Draw<'_, Tui> + 'a, U: TracksSizes<'a>> (
//tracks: impl Fn() -> U + Send + Sync + 'a, //tracks: impl Fn() -> U + Send + Sync + 'a,
//callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a //callback: impl Fn(usize, &'a Track)->T + Send + Sync + 'a
//) -> impl Draw<Tui> + 'a { //) -> impl Draw<'_, Tui> + 'a {
//bg(Reset, iter_east(||tracks() //bg(Reset, iter_east(||tracks()
//.map(move|(index, track, x1, x2): (usize, &'a Track, usize, usize)|{ //.map(move|(index, track, x1, x2): (usize, &'a Track, usize, usize)|{
//fg_bg( //fg_bg(

View file

@ -70,7 +70,7 @@ impl<T: TracksView + ScenesView + Send + Sync> ClipsView for T {}
pub trait ClipsView: TracksView + ScenesView { pub trait ClipsView: TracksView + ScenesView {
/// Draw clips per scene /// Draw clips per scene
fn view_scenes_clips (&self) -> impl Draw<Tui> { fn view_scenes_clips (&self) -> impl Draw<'_, Tui> {
let select = self.selection(); let select = self.selection();
let editor = self.editor(); let editor = self.editor();
let size = self.clips_size(); let size = self.clips_size();

View file

@ -5,24 +5,24 @@ impl_has!(Vec<MidiOutput>: |self: Arrangement| self.midi_outs);
impl_has!(Vec<MidiInput>: |self: App|self.project.midi_ins); impl_has!(Vec<MidiInput>: |self: App|self.project.midi_ins);
impl_has!(Vec<MidiOutput>: |self: App|self.project.midi_outs); impl_has!(Vec<MidiOutput>: |self: App|self.project.midi_outs);
pub fn view_midi_ins_status (theme: ItemTheme, track: Option<&Track>) -> impl Draw<Tui> { pub fn view_midi_ins_status (theme: ItemTheme, track: Option<&Track>) -> impl Draw<'_, Tui> {
track.map(move|track|view_ports_status(theme, "MIDI ins: ", &track.sequencer.midi_ins)) track.map(move|track|view_ports_status(theme, "MIDI ins: ", &track.sequencer.midi_ins))
} }
pub fn view_midi_outs_status (theme: ItemTheme, track: Option<&Track>) -> impl Draw<Tui> { pub fn view_midi_outs_status (theme: ItemTheme, track: Option<&Track>) -> impl Draw<'_, Tui> {
track.map(move|track|view_ports_status(theme, "MIDI outs: ", &track.sequencer.midi_outs)) track.map(move|track|view_ports_status(theme, "MIDI outs: ", &track.sequencer.midi_outs))
} }
pub fn view_audio_ins_status (theme: ItemTheme, track: Option<&Track>) -> impl Draw<Tui> { pub fn view_audio_ins_status (theme: ItemTheme, track: Option<&Track>) -> impl Draw<'_, Tui> {
track.map(move|track|view_ports_status(theme, "Audio ins: ", &track.audio_ins())) track.map(move|track|view_ports_status(theme, "Audio ins: ", &track.audio_ins()))
} }
pub fn view_audio_outs_status (theme: ItemTheme, track: Option<&Track>) -> impl Draw<Tui> { pub fn view_audio_outs_status (theme: ItemTheme, track: Option<&Track>) -> impl Draw<'_, Tui> {
track.map(move|track|view_ports_status(theme, "Audio outs:", &track.audio_outs())) track.map(move|track|view_ports_status(theme, "Audio outs:", &track.audio_outs()))
} }
pub fn view_ports_status <'a, T: JackPort> (theme: ItemTheme, title: &'a str, ports: &'a [T]) pub fn view_ports_status <'a, T: JackPort> (theme: ItemTheme, title: &'a str, ports: &'a [T])
-> impl Draw<Tui> + use<'a, T> -> impl Draw<'a, Tui> + use<'a, T>
{ {
let ins = ports.len() as u16; let ins = ports.len() as u16;
let frame = Outer(true, Style::default().fg(g(96))); let frame = Outer(true, Style::default().fg(g(96)));
@ -35,7 +35,7 @@ pub fn view_ports_status <'a, T: JackPort> (theme: ItemTheme, title: &'a str, po
pub fn view_io_ports <'a, T: PortsSizes<'a>> ( pub fn view_io_ports <'a, T: PortsSizes<'a>> (
fg: Color, bg: Color, items: impl Fn()->T + Send + Sync + 'a fg: Color, bg: Color, items: impl Fn()->T + Send + Sync + 'a
) -> impl Draw<Tui> + 'a { ) -> impl Draw<'a, Tui> + 'a {
type Item<'a> = (usize, &'a Arc<str>, &'a [Connect], usize, usize); type Item<'a> = (usize, &'a Arc<str>, &'a [Connect], usize, usize);
iter(items, iter(items,
move|(_index, name, connections, y, y2): Item<'a>, _| south( move|(_index, name, connections, y, y2): Item<'a>, _| south(
@ -49,7 +49,7 @@ pub fn view_io_ports <'a, T: PortsSizes<'a>> (
pub struct Junction<T: JackPort>(T); pub struct Junction<T: JackPort>(T);
impl<T: JackPort> View<Tui> for Junction<T> { impl<T: JackPort> View<Tui> for Junction<T> {
fn view (&self) -> impl Draw<Tui> { fn view (&self) -> impl Draw<'_, Tui> {
T::KIND T::KIND
} }
} }

View file

@ -203,7 +203,7 @@ pub trait ScenesView: HasEditor + HasSelection + HasSceneScroll + HasClipsSize +
fn w_side (&self) -> u16; fn w_side (&self) -> u16;
fn w_mid (&self) -> u16; fn w_mid (&self) -> u16;
fn view_scenes_names (&self) -> impl Draw<Tui> { fn view_scenes_names (&self) -> impl Draw<'_, Tui> {
let select = self.selection(); let select = self.selection();
let editor = self.editor(); let editor = self.editor();
let editing = self.is_editing(); let editing = self.is_editing();
@ -275,13 +275,13 @@ impl HasSceneScroll for App {
} }
} }
pub fn view_scene_name ( pub fn view_scene_name <'a> (
select: &Selection, select: &Selection,
editor: Option<&MidiEditor>, editor: Option<&'a MidiEditor>,
index: usize, index: usize,
scene: &Scene, scene: &Scene,
editing: bool editing: bool
) -> impl Draw<Tui> { ) -> impl Draw<'a, Tui> {
let h = if select.scene() == Some(index) && let Some(_editor) = editor { let h = if select.scene() == Some(index) && let Some(_editor) = editor {
7 7
} else { } else {

View file

@ -46,10 +46,10 @@ impl Track {
pub fn audio_outs (&self) -> &[AudioOutput] { pub fn audio_outs (&self) -> &[AudioOutput] {
self.devices.last().map(|x|x.audio_outs()).unwrap_or_default() self.devices.last().map(|x|x.audio_outs()).unwrap_or_default()
} }
pub fn per <'a, T: Draw<Tui> + 'a, U: TracksSizes<'a>> ( pub fn per <'a, T: Draw<'a, Tui> + 'a, U: TracksSizes<'a>> (
tracks: impl Fn() -> U + Send + Sync + 'a, tracks: impl Fn() -> U + Send + Sync + 'a,
callback: &'a (impl Fn(usize, &'a Track)->T + Send + Sync + 'a) callback: &'a (impl Fn(usize, &'a Track)->T + Send + Sync + 'a)
) -> impl Draw<Tui> + 'a { ) -> impl Draw<'a, Tui> {
iter_east(move||tracks().map(|(index, track, x1, x2): (usize, &Track, usize, usize)|{ iter_east(move||tracks().map(|(index, track, x1, x2): (usize, &Track, usize, usize)|{
fg_bg( fg_bg(
track.color.lightest.term, track.color.lightest.term,
@ -343,7 +343,7 @@ pub trait TracksView: HasTracks + ScenesView + HasMidiIns + HasMidiOuts + HasTra
} }
/// Draw name of each track /// Draw name of each track
fn view_track_names (&self, theme: ItemTheme) -> impl Draw<Tui> { fn view_track_names (&self, theme: ItemTheme) -> impl Draw<'_, Tui> {
let selected = self.selection(); let selected = self.selection();
east( east(
south( south(
@ -396,7 +396,7 @@ pub trait TracksView: HasTracks + ScenesView + HasMidiIns + HasMidiOuts + HasTra
} }
/// Draw outputs per track /// Draw outputs per track
fn view_track_outputs <'a> (&'a self, theme: ItemTheme, _h: u16) -> impl Draw<Tui> { fn view_track_outputs <'a> (&'a self, theme: ItemTheme, _h: u16) -> impl Draw<'_, Tui> {
view_track_row_section(theme, view_track_row_section(theme,
south(button_2("o", "utput", false).align_w().full_w(), south(button_2("o", "utput", false).align_w().full_w(),
draw(|to: &mut Tui|{ draw(|to: &mut Tui|{
@ -431,7 +431,7 @@ pub trait TracksView: HasTracks + ScenesView + HasMidiIns + HasMidiOuts + HasTra
} }
/// Draw inputs per track /// Draw inputs per track
fn view_track_inputs <'a> (&'a self, theme: ItemTheme) -> impl Draw<Tui> { fn view_track_inputs <'a> (&'a self, theme: ItemTheme) -> impl Draw<'_, Tui> {
let mut height = 0u16; let mut height = 0u16;
for track in self.tracks().iter() { for track in self.tracks().iter() {
height = height.max(track.sequencer.midi_ins.len() as u16); height = height.max(track.sequencer.midi_ins.len() as u16);
@ -459,7 +459,7 @@ pub trait TracksView: HasTracks + ScenesView + HasMidiIns + HasMidiOuts + HasTra
}).align_w())) }).align_w()))
} }
fn view_track_devices (&self, theme: ItemTheme) -> impl Draw<Tui> { fn view_track_devices (&self, theme: ItemTheme) -> impl Draw<'_, Tui> {
let height = self.tracks_devices_height(); let height = self.tracks_devices_height();
let btn1 = button_3("d", "evice", self.track().map(|t|t.devices.len()).unwrap_or(0), false); let btn1 = button_3("d", "evice", self.track().map(|t|t.devices.len()).unwrap_or(0), false);
let btn2 = button_2("D", "+", false); let btn2 = button_2("D", "+", false);
@ -488,7 +488,7 @@ pub trait TracksView: HasTracks + ScenesView + HasMidiIns + HasMidiOuts + HasTra
h as u16 h as u16
} }
fn view_inputs (&self, _theme: ItemTheme) -> impl Draw<Tui> + '_ { fn view_inputs (&self, _theme: ItemTheme) -> impl Draw<'_, Tui> + '_ {
let title_1 = button_3("i", "nput ", self.midi_ins().len(), false).align_w().exact_wh(20, 1); let title_1 = button_3("i", "nput ", self.midi_ins().len(), false).align_w().exact_wh(20, 1);
let title_2 = button_2("I", "+", false).exact_wh(4, 1); let title_2 = button_2("I", "+", false).exact_wh(4, 1);
east(title_1, west(title_2, draw(move|to: &mut Tui|{ east(title_1, west(title_2, draw(move|to: &mut Tui|{
@ -532,7 +532,7 @@ pub trait TracksView: HasTracks + ScenesView + HasMidiIns + HasMidiOuts + HasTra
h as u16 h as u16
} }
fn view_outputs (&self, theme: ItemTheme) -> impl Draw<Tui> { fn view_outputs (&self, theme: ItemTheme) -> impl Draw<'_, Tui> {
let height = self.outputs_height(); let height = self.outputs_height();
let list = south( let list = south(
button_3( button_3(
@ -630,12 +630,12 @@ impl HasTrackScroll for App {
} }
} }
fn view_track_row_section ( fn view_track_row_section <'a> (
_theme: ItemTheme, _theme: ItemTheme,
button: impl Draw<Tui>, button: impl Draw<'a, Tui>,
button_add: impl Draw<Tui>, button_add: impl Draw<'a, Tui>,
content: impl Draw<Tui>, content: impl Draw<'a, Tui>,
) -> impl Draw<Tui> { ) -> impl Draw<'a, Tui> {
west( west(
button_add.align_nw().exact_w(4).full_h(), button_add.align_nw().exact_w(4).full_h(),
east( east(

View file

@ -118,7 +118,7 @@ impl Browse {
unreachable!() unreachable!()
}) })
} }
//fn tui (&self) -> impl Draw<Tui> { //fn tui (&self) -> impl Draw<'_, Tui> {
//iter_south_fixed(1, ||self.tui_entries(), |entry, _index|entry.origin_w().full_w()) //iter_south_fixed(1, ||self.tui_entries(), |entry, _index|entry.origin_w().full_w())
//} //}
//fn tui_entries (&self) -> EntriesIterator<'_, Tui> { //fn tui_entries (&self) -> EntriesIterator<'_, Tui> {
@ -133,7 +133,7 @@ impl Browse {
} }
//impl<'a> Iterator for EntriesIterator<'a, Tui> { //impl<'a> Iterator for EntriesIterator<'a, Tui> {
//type Item = impl Draw<Tui>; //type Item = impl Draw<'_, Tui>;
//fn next (&mut self) -> Option<Self::Item> { //fn next (&mut self) -> Option<Self::Item> {
//let dirs = self.browser.dirs.len(); //let dirs = self.browser.dirs.len();
//let files = self.browser.files.len(); //let files = self.browser.files.len();
@ -179,7 +179,7 @@ pub fn scan (dir: &PathBuf) -> Usually<(Vec<OsString>, Vec<OsString>)> {
Ok((subdirs, files)) Ok((subdirs, files))
} }
pub fn view_browse_title (state: &App) -> impl Draw<Tui> { pub fn view_browse_title (state: &App) -> impl Draw<'_, Tui> {
field_v(ItemTheme::default(), match state.dialog.browser_target().unwrap() { field_v(ItemTheme::default(), match state.dialog.browser_target().unwrap() {
BrowseTarget::SaveProject => "Save project:", BrowseTarget::SaveProject => "Save project:",
BrowseTarget::LoadProject => "Load project:", BrowseTarget::LoadProject => "Load project:",

View file

@ -462,7 +462,7 @@ impl_time_unit!(LaunchSync);
/// let _ = tek::view_transport(true, x.as_ref(), x.as_ref(), x.as_ref()); /// let _ = tek::view_transport(true, x.as_ref(), x.as_ref(), x.as_ref());
/// let _ = tek::view_transport(false, x.as_ref(), x.as_ref(), x.as_ref()); /// let _ = tek::view_transport(false, x.as_ref(), x.as_ref(), x.as_ref());
/// ``` /// ```
pub fn view_transport (play: bool, bpm: &str, beat: &str, time: &str) -> impl Draw<Tui> { pub fn view_transport <'a> (play: bool, bpm: &str, beat: &str, time: &str) -> impl Draw<'a, Tui> {
let theme = ItemTheme::G[96]; let theme = ItemTheme::G[96];
bg(Black, east!(above( bg(Black, east!(above(
button_play_pause(play, false).align_w(), button_play_pause(play, false).align_w(),
@ -479,7 +479,7 @@ pub fn view_transport (play: bool, bpm: &str, beat: &str, time: &str) -> impl Dr
/// let _ = tek::view_status(None, x.as_ref(), x.as_ref(), x.as_ref()); /// let _ = tek::view_status(None, x.as_ref(), x.as_ref(), x.as_ref());
/// let _ = tek::view_status(Some("".into()), x.as_ref(), x.as_ref(), x.as_ref()); /// let _ = tek::view_status(Some("".into()), x.as_ref(), x.as_ref(), x.as_ref());
/// ``` /// ```
pub fn view_status (sel: Option<&str>, sr: &str, buf: &str, lat: &str) -> impl Draw<Tui> { pub fn view_status <'a> (sel: Option<&str>, sr: &str, buf: &str, lat: &str) -> impl Draw<'a, Tui> {
let theme = ItemTheme::G[96]; let theme = ItemTheme::G[96];
let sr = field_h(theme, "SR", sr); let sr = field_h(theme, "SR", sr);
let buf = field_h(theme, "Buf", buf); let buf = field_h(theme, "Buf", buf);
@ -496,7 +496,7 @@ pub fn view_status (sel: Option<&str>, sr: &str, buf: &str, lat: &str) -> impl D
/// let _ = tek::button_play_pause(false, true); /// let _ = tek::button_play_pause(false, true);
/// let _ = tek::button_play_pause(false, false); /// let _ = tek::button_play_pause(false, false);
/// ``` /// ```
pub fn button_play_pause (playing: bool, compact: bool) -> impl Draw<Tui> { pub fn button_play_pause <'a> (playing: bool, compact: bool) -> impl Draw<'a, Tui> {
bg(if playing { Rgb(0, 128, 0) } else { Rgb(128, 64, 0) }, bg(if playing { Rgb(0, 128, 0) } else { Rgb(128, 64, 0) },
either(compact, either(compact,
draw(move|to: &mut Tui|either(playing, draw(move|to: &mut Tui|either(playing,

View file

@ -1,8 +1,8 @@
use crate::{*, device::*}; use crate::{*, device::*};
pub fn draw_dialog ( pub fn draw_dialog <'a, L: Language + ?Sized> (
to: &mut Tui, mut frags: std::str::Split<&str>, state: &App, dsl: &impl Expression to: &mut Tui, mut frags: std::str::Split<&str>, state: &App, dsl: &'a L
) -> Drawn<u16> { ) -> Drawn<'a, u16> {
match frags.next() { match frags.next() {
Some("menu") => if let Dialog::Menu(selected, items) = &state.dialog { Some("menu") => if let Dialog::Menu(selected, items) = &state.dialog {
//Some(iter_south(move||items.0.iter().enumerate().map(move|(index, MenuItem(item, _))|{ //Some(iter_south(move||items.0.iter().enumerate().map(move|(index, MenuItem(item, _))|{
@ -34,7 +34,7 @@ pub fn draw_dialog (
impl App { impl App {
pub fn get_dialog (&self, src: impl Language) -> Perhaps<Dialog> { pub fn get_dialog <'a> (&self, src: impl Language) -> Perhaps<Dialog> {
src.word()?.map(|word|Ok(match word { src.word()?.map(|word|Ok(match word {
":dialog/none" => Dialog::None, ":dialog/none" => Dialog::None,
":dialog/options" => Dialog::Options, ":dialog/options" => Dialog::Options,

View file

@ -268,7 +268,7 @@ impl MidiEditor {
self.get_time_pos().overflowing_sub(1) self.get_time_pos().overflowing_sub(1)
.0.min(self.clip_length().saturating_sub(1)) .0.min(self.clip_length().saturating_sub(1))
} }
pub fn clip_status (&self) -> impl Draw<Tui> + '_ { pub fn clip_status (&self) -> impl Draw<'_, Tui> + '_ {
let (_color, name, length, looped) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) { let (_color, name, length, looped) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) {
(clip.color, clip.name.clone(), clip.length, clip.looped) (clip.color, clip.name.clone(), clip.length, clip.looped)
} else { (ItemTheme::G[64], String::new().into(), 0, false) }; } else { (ItemTheme::G[64], String::new().into(), 0, false) };
@ -281,7 +281,7 @@ impl MidiEditor {
.origin_w().full_w(), .origin_w().full_w(),
).exact_w(20) ).exact_w(20)
} }
pub fn edit_status (&self) -> impl Draw<Tui> + '_ { pub fn edit_status (&self) -> impl Draw<'_, Tui> + '_ {
let (_color, length) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) { let (_color, length) = if let Some(clip) = self.clip().as_ref().map(|p|p.read().unwrap()) {
(clip.color, clip.length) (clip.color, clip.length)
} else { (ItemTheme::G[64], 0) }; } else { (ItemTheme::G[64], 0) };
@ -426,7 +426,7 @@ impl MidiViewer for MidiEditor {
} }
impl View<Tui> for MidiEditor { impl View<Tui> for MidiEditor {
fn view (&self) -> impl Draw<Tui> { fn view (&self) -> impl Draw<'_, Tui> {
self.autoscroll(); self.autoscroll();
/*self.autozoom();*/ /*self.autozoom();*/
self.size.of(self.mode.view()) self.size.of(self.mode.view())

View file

@ -19,7 +19,7 @@ impl OctaveVertical {
} }
impl OctaveVertical { impl OctaveVertical {
pub fn tui (&self) -> impl Draw<Tui> { pub fn tui (&self) -> impl Draw<'_, Tui> {
east!( east!(
fg_bg(self.color(0), self.color(1), ""), fg_bg(self.color(0), self.color(1), ""),
fg_bg(self.color(2), self.color(3), ""), fg_bg(self.color(2), self.color(3), ""),

View file

@ -25,7 +25,7 @@ pub struct PianoHorizontal {
impl_has!(Sizer: |self: PianoHorizontal| self.size); impl_has!(Sizer: |self: PianoHorizontal| self.size);
impl View<Tui> for PianoHorizontal { impl View<Tui> for PianoHorizontal {
fn view (&self) -> impl Draw<Tui> { fn view (&self) -> impl Draw<'_, Tui> {
south( south(
east( east(
format!("{}x{}", self.size.w(), self.size.h()).exact_w(5), format!("{}x{}", self.size.w(), self.size.h()).exact_w(5),
@ -132,7 +132,7 @@ impl PianoHorizontal {
} }
} }
fn notes (&self) -> impl Draw<Tui> { fn notes (&self) -> impl Draw<'_, Tui> {
let time_start = self.get_time_start(); let time_start = self.get_time_start();
let note_lo = self.get_note_lo(); let note_lo = self.get_note_lo();
let note_hi = self.get_note_hi(); let note_hi = self.get_note_hi();
@ -168,7 +168,7 @@ impl PianoHorizontal {
}) })
} }
fn cursor (&self) -> impl Draw<Tui> { fn cursor (&self) -> impl Draw<'_, Tui> {
let note_hi = self.get_note_hi(); let note_hi = self.get_note_hi();
let note_lo = self.get_note_lo(); let note_lo = self.get_note_lo();
let note_pos = self.get_note_pos(); let note_pos = self.get_note_pos();
@ -202,7 +202,7 @@ impl PianoHorizontal {
}) })
} }
fn keys (&self) -> impl Draw<Tui> { fn keys (&self) -> impl Draw<'_, Tui> {
let state = self; let state = self;
let color = state.color; let color = state.color;
let note_lo = state.get_note_lo(); let note_lo = state.get_note_lo();
@ -229,7 +229,7 @@ impl PianoHorizontal {
}).exact_w(self.keys_width).full_h() }).exact_w(self.keys_width).full_h()
} }
fn timeline (&self) -> impl Draw<Tui> + '_ { fn timeline (&self) -> impl Draw<'_, Tui> + '_ {
draw(move|to: &mut Tui|{ draw(move|to: &mut Tui|{
let xywh = to.area().into(); let xywh = to.area().into();
let XYWH(x, y, w, _h) = xywh; let XYWH(x, y, w, _h) = xywh;

View file

@ -40,7 +40,7 @@ impl_draw!(|self: Log10Meter, to: Tui| {
Ok(Some(to.area().into())) Ok(Some(to.area().into()))
}); });
fn draw_meters (meters: &[f32]) -> impl Draw<Tui> + use<'_> { fn draw_meters (meters: &[f32]) -> impl Draw<'_, Tui> + use<'_> {
bg(Black, iter_east_fixed(1, ||meters.iter(), |value, _index|{ bg(Black, iter_east_fixed(1, ||meters.iter(), |value, _index|{
RmsMeter(*value).full_h() RmsMeter(*value).full_h()
}).exact_w(2)) }).exact_w(2))

View file

@ -140,7 +140,7 @@ impl ApplicationHandler for LV2PluginUI {
} }
} }
impl Draw<Tui> for Lv2 { impl Draw<'_, Tui> for Lv2 {
fn draw (&self, to: &mut Tui) { fn draw (&self, to: &mut Tui) {
let area = to.area(); let area = to.area();
let XYWH(x, y, _, height) = area; let XYWH(x, y, _, height) = area;

View file

@ -439,7 +439,7 @@ impl Pool {
} }
impl<'a> PoolView<'a> { impl<'a> PoolView<'a> {
//fn tui (&self) -> impl Draw<Tui> { //fn tui (&self) -> impl Draw<'_, Tui> {
//let Self(pool) = self; //let Self(pool) = self;
////let color = self.1.clip().map(|c|c.read().unwrap().color).unwrap_or_else(||g(32).into()); ////let color = self.1.clip().map(|c|c.read().unwrap().color).unwrap_or_else(||g(32).into());
////let on_bg = |x|x;//below(Repeat(" "), bg(color.darkest.term, x)); ////let on_bg = |x|x;//below(Repeat(" "), bg(color.darkest.term, x));
@ -467,7 +467,7 @@ impl<'a> PoolView<'a> {
} }
impl ClipLength { impl ClipLength {
//fn tui (&self) -> impl Draw<Tui> { //fn tui (&self) -> impl Draw<'_, Tui> {
//use ClipLengthFocus::*; //use ClipLengthFocus::*;
//let bars = format!("{}", self.bars()); //let bars = format!("{}", self.bars());
//let beats = format!("{}", self.beats()); //let beats = format!("{}", self.beats());

View file

@ -330,7 +330,7 @@ fn draw_list_item (sample: &Option<Arc<RwLock<Sample>>>) -> String {
} }
} }
fn draw_viewer (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> + use<'_> { fn draw_viewer (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<'_, Tui> + use<'_> {
let min_db = -64.0; let min_db = -64.0;
draw(move|to: &mut Tui|{ draw(move|to: &mut Tui|{
let xywh = to.area().into(); let xywh = to.area().into();
@ -750,7 +750,7 @@ fn read_sample_data (_: &str) -> Usually<(usize, Vec<Vec<f32>>)> {
todo!(); todo!();
} }
pub fn view_sample_info (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> + use<'_> { pub fn view_sample_info (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<'_, Tui> + use<'_> {
when(sample.is_some(), draw(move|to: &mut Tui|{ when(sample.is_some(), draw(move|to: &mut Tui|{
let sample = sample.unwrap().read().unwrap(); let sample = sample.unwrap().read().unwrap();
let theme = sample.color; let theme = sample.color;
@ -765,7 +765,7 @@ pub fn view_sample_info (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui>
})) }))
} }
pub fn view_sample_info_v (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> + use<'_> { pub fn view_sample_info_v (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<'_, Tui> + use<'_> {
let a = draw(move|to: &mut Tui|{ let a = draw(move|to: &mut Tui|{
let sample = sample.unwrap().read().unwrap(); let sample = sample.unwrap().read().unwrap();
let theme = sample.color; let theme = sample.color;
@ -788,7 +788,7 @@ pub fn view_sample_info_v (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tu
either(sample.is_some(), a, b) either(sample.is_some(), a, b)
} }
pub fn view_sample_status (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<Tui> { pub fn view_sample_status (sample: Option<&Arc<RwLock<Sample>>>) -> impl Draw<'_, Tui> {
bold(true, fg(g(224), sample bold(true, fg(g(224), sample
.map(|sample|{ .map(|sample|{
let sample = sample.read().unwrap(); let sample = sample.read().unwrap();

View file

@ -113,7 +113,7 @@ pub trait HasPlayClip: HasClock {
*self.reset_mut() = true; *self.reset_mut() = true;
} }
fn play_status (&self) -> impl Draw<Tui> { fn play_status (&self) -> impl Draw<'_, Tui> {
let (name, color): (Arc<str>, ItemTheme) = if let Some((_, Some(clip))) = self.play_clip() { let (name, color): (Arc<str>, ItemTheme) = if let Some((_, Some(clip))) = self.play_clip() {
let MidiClip { ref name, color, .. } = *clip.read().unwrap(); let MidiClip { ref name, color, .. } = *clip.read().unwrap();
(name.clone(), color) (name.clone(), color)
@ -130,7 +130,7 @@ pub trait HasPlayClip: HasClock {
.into() .into()
} }
fn next_status (&self) -> impl Draw<Tui> { fn next_status (&self) -> impl Draw<'_, Tui> {
let mut time: Arc<str> = String::from("--.-.--").into(); let mut time: Arc<str> = String::from("--.-.--").into();
let mut name: Arc<str> = String::from("").into(); let mut name: Arc<str> = String::from("").into();
let mut color = ItemTheme::G[64]; let mut color = ItemTheme::G[64];

View file

@ -257,11 +257,11 @@ mod config {
/// tek::Config::default().add(&source).unwrap().get_mode(":menu").unwrap(); /// tek::Config::default().add(&source).unwrap().get_mode(":menu").unwrap();
/// ``` /// ```
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct Config { pub struct Config<'a> {
/// XDG base directories of running user. /// XDG base directories of running user.
pub dirs: BaseDirectories, pub dirs: BaseDirectories,
/// Active collection of interaction modes. /// Active collection of interaction modes.
pub modes: Modes, pub modes: Modes<'a>,
/// Active collection of event bindings. /// Active collection of event bindings.
pub binds: Binds, pub binds: Binds,
/// Active collection of view definitions. /// Active collection of view definitions.
@ -286,7 +286,7 @@ mod config {
/// assert_eq!(modes.len(), 1); /// assert_eq!(modes.len(), 1);
/// ``` /// ```
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct Modes(Arc<RwLock<BTreeMap<Arc<str>, Arc<Mode<Arc<str>>>>>>); pub struct Modes<'a>(Arc<RwLock<BTreeMap<Arc<str>, Arc<Mode<'a, Arc<str>>>>>>);
/// Group of view and keys definitions. /// Group of view and keys definitions.
/// ///
@ -294,16 +294,16 @@ mod config {
/// let mode = tek::Mode::<std::sync::Arc<str>>::default(); /// let mode = tek::Mode::<std::sync::Arc<str>>::default();
/// ``` /// ```
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct Mode<D: Language + Ord> { pub struct Mode<'a, D: Language + Ord> {
pub path: PathBuf, pub path: PathBuf,
pub name: Vec<D>, pub name: Vec<D>,
pub info: Vec<D>, pub info: Vec<D>,
pub view: Vec<D>, pub view: Vec<D>,
pub keys: Vec<D>, pub keys: Vec<D>,
pub modes: Modes, pub modes: Modes<'a>,
} }
impl Config { impl<'a> Config<'a> {
/// Default configuration directory. /// Default configuration directory.
const CONFIG_DIR: &'static str = "tek"; const CONFIG_DIR: &'static str = "tek";
/// Default configuration subdirectory. /// Default configuration subdirectory.
@ -389,7 +389,7 @@ mod config {
/// Write initial contents of a configuration file. /// Write initial contents of a configuration file.
pub fn load <F: FnMut(&Self, &str)->Usually<()>> ( pub fn load <F: FnMut(&Self, &str)->Usually<()>> (
&self, path: &str, defaults: &str, mut each: F &self, path: &str, defaults: &str, mut each: F
) -> Usually<()> { ) -> UsuallyRef<()> {
self.stamp.store(quanta::Clock::new().raw(), Relaxed); self.stamp.store(quanta::Clock::new().raw(), Relaxed);
if self.find_file().is_none() { if self.find_file().is_none() {
//println!("Creating {path:?}"); //println!("Creating {path:?}");
@ -415,27 +415,27 @@ mod config {
*self.binds.write().unwrap() = Default::default(); *self.binds.write().unwrap() = Default::default();
} }
/// Add one entry to the configuration. /// Add one entry to the configuration.
fn add_one (&self, item: impl Language) -> Usually<()> { fn add_one (&'a self, item: &'a (impl Language + ?Sized)) -> UsuallyRef<'a, ()> {
if let Some(expr) = item.expr()? { item.expr()?
let head = expr.head()?; .map(|expr|{
let tail = expr.tail()?; let head = expr.head()?;
let name = tail.head()?; let tail = expr.tail()?;
let body = tail.tail()?; let name = tail.head()?;
match head { let body = tail.tail()?;
Some("mode") if let Some(name) = name => self.modes.add(&name, &body)?, match head {
Some("keys") if let Some(name) = name => load_bind(&self.binds, &name, &body)?, Some("mode") if let Some(name) = name => self.modes.add(name, &body)?,
Some("view") if let Some(name) = name => load_view(&self.views, &name, &body)?, Some("keys") if let Some(name) = name => load_bind(&self.binds, &name, &body)?,
_ => return Err( Some("view") if let Some(name) = name => load_view(&self.views, &name, &body)?,
format!("Config::load: expected view/keys/mode, got: {item:?}").into() _ => return Ok::<Option<()>, Box<dyn Error>>(None)
) }
} Ok(Some(()))
Ok(()) })
} else { .transpose()?
return Err(format!("Config::load: expected expr, got: {item:?}").into()) .flatten()
} .ok_or_else(||format!("Config::load: expected view/keys/mode expr, got: {item:?}").into())
} }
/// Get a mode by name. /// Get a mode by name.
pub fn get_mode (&self, mode: impl AsRef<str>) -> Option<Arc<Mode<Arc<str>>>> { pub fn get_mode (&'a self, mode: impl AsRef<str>) -> Option<Arc<Mode<'a, Arc<str>>>> {
self.modes.get(mode) self.modes.get(mode)
} }
/// Print the configuration. /// Print the configuration.
@ -444,16 +444,22 @@ mod config {
} }
} }
impl Modes { impl<'a> Modes<'a> {
/// Register a mode. /// Register a mode.
pub fn add (&self, name: &impl AsRef<str>, body: &impl Language) -> Usually<()> { pub fn add (
&self,
name: &'a (impl AsRef<str> + ?Sized),
body: &(impl Language + ?Sized)
)
-> UsuallyRef<'a, ()>
{
let mut mode = Mode::default(); let mut mode = Mode::default();
body.each(|item|mode.add(item))?; body.each(|item|mode.add(item))?;
self.0.write().unwrap().insert(name.as_ref().into(), Arc::new(mode)); self.0.write().unwrap().insert(name.as_ref().into(), Arc::new(mode));
Ok(()) Ok(())
} }
/// Get a mode by name. /// Get a mode by name.
pub fn get (&self, name: impl AsRef<str>) -> Option<Arc<Mode<Arc<str>>>> { pub fn get (&self, name: impl AsRef<str>) -> Option<Arc<Mode<'a, Arc<str>>>> {
self.0.read().unwrap().get(name.as_ref()).cloned() self.0.read().unwrap().get(name.as_ref()).cloned()
} }
/// Run something for each mode. /// Run something for each mode.
@ -468,7 +474,7 @@ mod config {
} }
} }
impl Mode<Arc<str>> { impl<'a> Mode<'a, Arc<str>> {
/// Add a definition to the mode. /// Add a definition to the mode.
/// ///
/// Supported definitions: /// Supported definitions:
@ -483,7 +489,7 @@ mod config {
/// let mut mode: tek::Mode<std::sync::Arc<str>> = Default::default(); /// let mut mode: tek::Mode<std::sync::Arc<str>> = Default::default();
/// mode.add("(name hello)").unwrap(); /// mode.add("(name hello)").unwrap();
/// ``` /// ```
pub fn add (&mut self, dsl: impl Language) -> Usually<()> { pub fn add (&mut self, dsl: &'a (impl Language + ?Sized)) -> UsuallyRef<'a, ()> {
Ok(if let Ok(Some(expr)) = dsl.expr() && let Ok(Some(head)) = expr.head() { Ok(if let Ok(Some(expr)) = dsl.expr() && let Ok(Some(head)) = expr.head() {
//println!("Mode::add: {head} {:?}", expr.tail()); //println!("Mode::add: {head} {:?}", expr.tail());
let tail = expr.tail()?.map(|x|x.trim()).unwrap_or(""); let tail = expr.tail()?.map(|x|x.trim()).unwrap_or("");
@ -501,23 +507,26 @@ mod config {
}) })
} }
/// Add a name to the mode. /// Add a name to the mode.
fn add_name (&mut self, dsl: impl Language) -> Perhaps<()> { fn add_name (&mut self, dsl: &'a (impl Language + ?Sized)) -> PerhapsRef<'a, ()> {
Ok(dsl.src()?.map(|src|self.name.push(src.into()))) Ok(dsl.text()?.map(|text|self.name.push(text.into())))
} }
/// Add a description to the mode. /// Add a description to the mode.
fn add_info (&mut self, dsl: impl Language) -> Perhaps<()> { fn add_info (&mut self, dsl: &'a (impl Language + ?Sized)) -> PerhapsRef<'a, ()> {
Ok(dsl.src()?.map(|src|self.info.push(src.into()))) Ok(dsl.text()?.map(|text|self.info.push(text.into())))
} }
/// Add a view definition to the mode. /// Add a view definition to the mode.
fn add_view (&mut self, dsl: impl Language) -> Perhaps<()> { fn add_view (&mut self, dsl: &'a (impl Language + ?Sized)) -> PerhapsRef<'a, ()> {
Ok(dsl.src()?.map(|src|self.view.push(src.into()))) Ok(dsl.text()?.map(|text|self.view.push(text.into())))
} }
/// Add a keyboard input bindin to the mode. /// Add a keyboard input bindin to the mode.
fn add_keys (&mut self, dsl: impl Language) -> Perhaps<()> { fn add_keys (&mut self, dsl: &'a (impl Language + ?Sized)) -> PerhapsRef<'a, ()> {
Ok(Some(dsl.each(|expr|{ self.keys.push(expr.trim().into()); Ok(()) })?)) Ok(Some(dsl.src()?.each(|expr|{
self.keys.push(expr.trim().into());
Ok::<(), Box<dyn Error>>(())
})?))
} }
/// Add a submode to the mode. /// Add a submode to the mode.
fn add_mode (&mut self, dsl: impl Language) -> Perhaps<()> { fn add_mode (&mut self, dsl: &'a (impl Language + ?Sized)) -> PerhapsRef<'a, ()> {
Ok(Some(if let Some(id) = dsl.head()? { Ok(Some(if let Some(id) = dsl.head()? {
self.modes.add(&id, &dsl.tail())?; self.modes.add(&id, &dsl.tail())?;
} else { } else {
@ -599,7 +608,7 @@ mod app {
/// Performance counter /// Performance counter
pub perf: PerfModel, pub perf: PerfModel,
/// Available view modes and input bindings /// Available view modes and input bindings
pub config: Arc<Config>, pub config: Arc<Config<'static>>,
/// Currently selected mode /// Currently selected mode
pub mode: Option<Arc<str>>, pub mode: Option<Arc<str>>,
/// Undo history /// Undo history
@ -640,17 +649,17 @@ mod app {
} }
} }
fn get_arc_str (_: &App, src: impl Language) -> Perhaps<Arc<str>> { fn get_arc_str <'a> (_: &App, src: impl Language) -> Perhaps<Arc<str>> {
Ok(src.src()?.map(|x|x.into())) Ok(src.src()?.map(|x|x.into()))
} }
fn get_u16 (state: &App, src: impl Language) -> Perhaps<u16> { fn get_u16 <'a> (state: &App, src: impl Language) -> Perhaps<u16> {
Ok(Some(match src.word()? { Ok(Some(match src.word()? {
Some(":w/sidebar") => state.project.w_sidebar(state.editor().is_some()), Some(":w/sidebar") => state.project.w_sidebar(state.editor().is_some()),
Some(":h/sample-detail") => 6.max(state.size.h() as u16 * 3 / 9), Some(":h/sample-detail") => 6.max(state.size.h() as u16 * 3 / 9),
_ => return try_to_u16(src) _ => return try_to_u16(src)
})) }))
} }
fn get_usize (state: &App, src: impl Language) -> Perhaps<usize> { fn get_usize <'a> (state: &App, src: impl Language) -> Perhaps<usize> {
Ok(Some(match src.word()? { Ok(Some(match src.word()? {
Some(":scene-count") => state.scenes().len(), Some(":scene-count") => state.scenes().len(),
Some(":track-count") => state.tracks().len(), Some(":track-count") => state.tracks().len(),
@ -660,7 +669,7 @@ mod app {
_ => return try_to_usize(src) _ => return try_to_usize(src)
})) }))
} }
fn get_bool (state: &App, src: impl Language) -> Perhaps<bool> { fn get_bool <'a> (state: &App, src: impl Language) -> Perhaps<bool> {
src.word()?.map(|word|Ok(match word { src.word()?.map(|word|Ok(match word {
"Y" => true, "Y" => true,
"N" => false, "N" => false,
@ -681,7 +690,7 @@ mod app {
})).transpose() })).transpose()
} }
#[allow(unused)] #[allow(unused)]
fn get_selection (state: &App, src: impl Language) -> Perhaps<Selection> { fn get_selection <'a> (state: &App, src: impl Language) -> Perhaps<Selection> {
src.word()?.map(|word|Ok(match word { src.word()?.map(|word|Ok(match word {
":select/scene" => state.selection().select_scene(state.tracks().len()), ":select/scene" => state.selection().select_scene(state.tracks().len()),
":select/scene/next" => state.selection().select_scene_next(state.scenes().len()), ":select/scene/next" => state.selection().select_scene_next(state.scenes().len()),
@ -692,21 +701,21 @@ mod app {
_ => return Err(format!("not selection: {word}").into()) _ => return Err(format!("not selection: {word}").into())
})).transpose() })).transpose()
} }
fn get_color (_: &App, src: impl Language) -> Perhaps<Color> { fn get_color <'a> (_: &App, src: impl Language) -> Perhaps<Color> {
if let Some(expr) = src.expr()? { if let Some(expr) = src.expr()? {
match (expr.head()?, expr.tail()?) { match (expr.head()?, expr.tail()?) {
(Some("g"), Some(tail)) => { (Some("g"), Some(tail)) => {
let n = try_to_u8(tail.head().map_err(Into::into))? let n = try_to_u8(tail.head().map_err(Into::into))?
.ok_or(LanguageError::Domain("not gray"))?; .ok_or(LanguageError::domain("not gray"))?;
Ok(Some(Color::Rgb(n, n, n))) Ok(Some(Color::Rgb(n, n, n)))
}, },
(Some("rgb"), Some(tail)) => { (Some("rgb"), Some(tail)) => {
let r = try_to_u8(tail.head().map_err(Into::into))? let r = try_to_u8(tail.head().map_err(Into::into))?
.ok_or(LanguageError::Domain("not red"))?; .ok_or(LanguageError::domain("not red"))?;
let g = try_to_u8(tail.tail().head().map_err(Into::into))? let g = try_to_u8(tail.tail().head().map_err(Into::into))?
.ok_or(LanguageError::Domain("not green"))?; .ok_or(LanguageError::domain("not green"))?;
let b = try_to_u8(tail.tail().tail().head().map_err(Into::into))? let b = try_to_u8(tail.tail().tail().head().map_err(Into::into))?
.ok_or(LanguageError::Domain("not blue"))?; .ok_or(LanguageError::domain("not blue"))?;
Ok(Some(Color::Rgb(r, g, b))) Ok(Some(Color::Rgb(r, g, b)))
}, },
(Some(_), _) => return Err(format!("not a color expression: {expr}").into()), (Some(_), _) => return Err(format!("not a color expression: {expr}").into()),
@ -723,7 +732,7 @@ mod app {
} }
} }
#[allow(unused)] #[allow(unused)]
fn get_opt_u7 (state: &App, src: impl Language) -> Perhaps<Option<u7>> { fn get_opt_u7 <'a> (state: &App, src: impl Language) -> Perhaps<Option<u7>> {
src.word()?.map(|word|Ok(match word { src.word()?.map(|word|Ok(match word {
":editor/pitch" => Some(( ":editor/pitch" => Some((
state.editor().as_ref().map(|e|e.get_note_pos()).unwrap() as u8 state.editor().as_ref().map(|e|e.get_note_pos()).unwrap() as u8
@ -731,7 +740,7 @@ mod app {
_ => return Err(format!("unknown midi note: {word}").into()) _ => return Err(format!("unknown midi note: {word}").into())
})).transpose() })).transpose()
} }
fn get_opt_usize (state: &App, src: impl Language) -> Perhaps<Option<usize>> { fn get_opt_usize <'a> (state: &App, src: impl Language) -> Perhaps<Option<usize>> {
src.word()?.map(|word|Ok(match word { src.word()?.map(|word|Ok(match word {
":selected/scene" => state.selection().scene(), ":selected/scene" => state.selection().scene(),
":selected/track" => state.selection().track(), ":selected/track" => state.selection().track(),
@ -739,42 +748,42 @@ mod app {
})).transpose() })).transpose()
} }
#[allow(unused)] #[allow(unused)]
fn get_clip (state: &App, src: impl Language) -> Perhaps<Option<Arc<RwLock<MidiClip>>>> { fn get_clip <'a> (state: &App, src: impl Language) -> Perhaps<Option<Arc<RwLock<MidiClip>>>> {
src.word()?.map(|word|Ok(match word { src.word()?.map(|word|Ok(match word {
":selected/clip" if let Selection::TrackClip { track, scene } = state.selection() => ":selected/clip" if let Selection::TrackClip { track, scene } = state.selection() =>
state.scenes()[*scene].clips[*track].clone(), state.scenes()[*scene].clips[*track].clone(),
_ => return Err(format!("not a clip: {word}").into()) _ => return Err(format!("not a clip: {word}").into())
})).transpose() })).transpose()
} }
fn get_axis (_: &App, src: impl Language) -> Perhaps<ControlAxis> { fn get_axis <'a> (_: &App, src: impl Language) -> Perhaps<ControlAxis> {
Ok(src.word()?.map(|word|Ok(match word { Ok(src.word()?.map(|word|Ok(match word {
":x" => ControlAxis::X, ":x" => ControlAxis::X,
":y" => ControlAxis::Y, ":y" => ControlAxis::Y,
_ => return Err(format!("unknown axis {word}")) _ => return Err(format!("unknown axis {word}"))
})).transpose()?) })).transpose()?)
} }
fn get_opt_u16 (_: &App, _src: impl Language) -> Perhaps<Option<u16>> { fn get_opt_u16 <'a> (_: &App, _src: impl Language) -> Perhaps<Option<u16>> {
Ok(None) Ok(None)
} }
fn get_opt_itemtheme (_: &App, _: impl Language) -> Perhaps<Option<ItemTheme>> { fn get_opt_itemtheme <'a> (_: &App, _: impl Language) -> Perhaps<Option<ItemTheme>> {
todo!() todo!()
} }
fn get_opt_vec_opt_arc_rwlock_midiclip (_: &App, _: impl Language) -> Perhaps<Option<Vec<Option<Arc<RwLock<MidiClip>>>>>> { fn get_opt_vec_opt_arc_rwlock_midiclip <'a> (_: &App, _: impl Language) -> Perhaps<Option<Vec<Option<Arc<RwLock<MidiClip>>>>>> {
todo!() todo!()
} }
fn get_opt_arc_array_connect (_: &App, _: impl Language) -> Perhaps<Option<Arc<[Connect]>>> { fn get_opt_arc_array_connect <'a> (_: &App, _: impl Language) -> Perhaps<Option<Arc<[Connect]>>> {
todo!() todo!()
} }
fn get_arc_array_connect (_: &App, _: impl Language) -> Perhaps<Arc<[Connect]>> { fn get_arc_array_connect <'a> (_: &App, _: impl Language) -> Perhaps<Arc<[Connect]>> {
todo!() todo!()
} }
fn get_opt_arc_str (_: &App, _: impl Language) -> Perhaps<Option<Arc<str>>> { fn get_opt_arc_str <'a> (_: &App, _: impl Language) -> Perhaps<Option<Arc<str>>> {
todo!() todo!()
} }
fn get_opt_bool (_: &App, _: impl Language) -> Perhaps<Option<bool>> { fn get_opt_bool <'a> (_: &App, _: impl Language) -> Perhaps<Option<bool>> {
todo!() todo!()
} }
fn get_path_buf (_: &App, _: impl Language) -> Perhaps<PathBuf> { fn get_path_buf <'a> (_: &App, _: impl Language) -> Perhaps<PathBuf> {
todo!() todo!()
} }
} }
@ -976,13 +985,15 @@ mod bind {
} }
} }
pub(crate) fn load_bind (binds: &Binds, name: &impl AsRef<str>, body: &impl Language) -> Usually<()> { pub(crate) fn load_bind <'a> (
binds: &Binds, name: &impl AsRef<str>, body: &impl Language
) -> Usually<()> {
binds.write().unwrap().insert(name.as_ref().into(), Bind::load(body)?); binds.write().unwrap().insert(name.as_ref().into(), Bind::load(body)?);
Ok(()) Ok(())
} }
impl Bind<TuiEvent, Arc<str>> { impl Bind<TuiEvent, Arc<str>> {
pub fn load (lang: &impl Language) -> Usually<Self> { pub fn load <'a> (lang: &impl Language) -> Usually<Self> {
let mut map = Self::new(); let mut map = Self::new();
lang.each(|item|if item.expr().head() == Ok(Some("see")) { lang.each(|item|if item.expr().head() == Ok(Some("see")) {
// TODO // TODO
@ -1269,7 +1280,7 @@ mod device {
} }
} }
pub fn view_device (state: &App) -> impl Draw<Tui> { pub fn view_device (state: &App) -> impl Draw<'_, Tui> {
let selected = state.dialog.device_kind().unwrap(); let selected = state.dialog.device_kind().unwrap();
south( south(
bold(true, "Add device"), bold(true, "Add device"),
@ -1301,9 +1312,9 @@ mod draw {
use crate::*; use crate::*;
/// Load custom view definition. /// Load custom view definition.
pub(crate) fn load_view ( pub(crate) fn load_view <'a> (
views: &Views, name: &impl AsRef<str>, body: &impl Language, views: &Views, name: &impl AsRef<str>, body: &'a impl Language,
) -> Usually<()> { ) -> UsuallyRef<'a, ()> {
views.write().unwrap().insert( views.write().unwrap().insert(
name.as_ref().into(), name.as_ref().into(),
body.src()?.unwrap_or_default().into() body.src()?.unwrap_or_default().into()
@ -1311,23 +1322,13 @@ mod draw {
Ok(()) Ok(())
} }
impl Keywords<Tui, XYWH<u16>> for App {
fn keywords () -> impl Iterator<Item = fn(&Self, &mut Tui, &str) -> Perhaps<XYWH<u16>>> {
[
kw_when, kw_either, kw_split, kw_align, kw_exact, kw_min, kw_max, kw_push, kw_full,
kw_tui_text, kw_tui_fg, kw_tui_bg
]
.into_iter()
}
}
/// The [Draw] implementation for [App] handles the loaded view, /// The [Draw] implementation for [App] handles the loaded view,
/// which is defined in terms of [dizzle] DSL. /// which is defined in terms of [dizzle] DSL.
/// ///
/// If there is an error, the error is displayed. FIXME: overlay it /// If there is an error, the error is displayed. FIXME: overlay it
/// Then, every top-level form of the DSL description is rendered. /// Then, every top-level form of the DSL description is rendered.
impl View<Tui> for App { impl View<Tui> for App {
fn view (&self) -> impl Draw<Tui> { fn view (&self) -> impl Draw<'_, Tui> {
//self.perf.cycle(&mut |_|{ //self.perf.cycle(&mut |_|{
draw(|to: &mut Tui|{ draw(|to: &mut Tui|{
self.draw_error(to)?; self.draw_error(to)?;
@ -1347,15 +1348,8 @@ mod draw {
Ok(()) Ok(())
} }
fn draw_mode (&self, to: &mut Tui) -> Usually<()> { fn draw_mode <'a> (&'a self, to: &mut Tui) -> UsuallyRef<'a, ()> {
self.mode.as_ref().and_then(|m|self.config.get_mode(m)).map(|mode|{ if let Some(mode) = self.mode.as_ref().and_then(|m|self.config.get_mode(m)) {
//south!(
//format!("Mode: {:?}", self.mode.as_ref()),
//format!("Time: {}", self.config.stamp.load(Relaxed)),
//iter_south(||mode.view.iter().enumerate().map(|(index, line)|{
//format!("View #{index} {line}")
//}))
//).align_nw().draw(to)?;
for (index, dsl) in mode.view.iter().enumerate() { for (index, dsl) in mode.view.iter().enumerate() {
match self.interpret(to, dsl) { match self.interpret(to, dsl) {
Ok(Some(XYWH(.., w, h))) => { Ok(Some(XYWH(.., w, h))) => {
@ -1364,7 +1358,10 @@ mod draw {
}, },
Err(e) => { Err(e) => {
let src = &dsl.src().unwrap_or(Some("<source error>")).unwrap_or("<no source>"); let src = &dsl.src().unwrap_or(Some("<source error>")).unwrap_or("<no source>");
let message = format!("Mode: {:?}\n\nLayer: #{index}\n\nError: {e}\n\nSource:\n{}", &mode.name, &src); let message = format!(
"Mode: {:?}\n\nLayer: #{index}\n\nError: {e}\n\nSource:\n{src}",
&mode.name
);
*self.error.write().unwrap() = Some(message.into()); *self.error.write().unwrap() = Some(message.into());
return Err(e); return Err(e);
}, },
@ -1372,8 +1369,7 @@ mod draw {
} }
} }
*self.error.write().unwrap() = None; *self.error.write().unwrap() = None;
Ok(()) }
});
Ok(()) Ok(())
} }
@ -1385,11 +1381,21 @@ mod draw {
} }
} }
impl Interpret<Tui, Option<XYWH<u16>>> for App { impl<'a> Interpret<'a, Tui, Option<XYWH<u16>>> for App {
fn interpret_expr <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) -> Drawn<u16> {
self.keyword(to, lang) fn interpret_expr <L: Language + ?Sized> (&'a self, to: &mut Tui, src: &'a L) -> Drawn<u16> {
if let Some(src) = src.src()? {
interpret_keyword!(self, to, src, [
kw_when, kw_either, kw_split, kw_align, kw_exact, kw_min, kw_max, kw_push, kw_full,
kw_tui_text, kw_tui_fg, kw_tui_bg
]);
Err(format!("interpret_expr: unexpected: {src:?}").into())
} else {
Err(format!("interpret_expr: no keyword: {src:?}").into())
}
} }
fn interpret_word <'a> (&'a self, to: &mut Tui, lang: &'a impl Expression) -> Drawn<u16> {
fn interpret_word <L: Language + ?Sized> (&'a self, to: &mut Tui, lang: &'a L) -> Drawn<u16> {
let mut frags = lang.src()?.unwrap().split("/"); let mut frags = lang.src()?.unwrap().split("/");
match frags.next() { match frags.next() {
//Some(":logo") => view_logo().draw(to), //Some(":logo") => view_logo().draw(to),
@ -1433,6 +1439,7 @@ mod draw {
_ => unreachable!() _ => unreachable!()
} }
} }
} }
impl_has!(Sizer: |self: App|self.size); impl_has!(Sizer: |self: App|self.size);
@ -1445,7 +1452,7 @@ mod draw {
fn width_dec (&mut self); fn width_dec (&mut self);
} }
pub fn view_templates (_frags: std::str::Split<&str>, state: &App) -> impl Draw<Tui> { pub fn view_templates <'a> (_frags: std::str::Split<&str>, state: &App) -> impl Draw<'a, Tui> {
let height = (state.config.modes.len() * 2) as u16; let height = (state.config.modes.len() * 2) as u16;
draw(move |to: &mut Tui|{ draw(move |to: &mut Tui|{
let mut index = 0; let mut index = 0;
@ -1466,17 +1473,17 @@ mod draw {
}).min_w(30).exact_h(height) }).min_w(30).exact_h(height)
} }
pub fn field_h <T: Screen> ( pub fn field_h <'a, T: Screen> (
_theme: ItemTheme, _head: impl Draw<T>, _body: impl Draw<T> _theme: ItemTheme, _head: impl Draw<'a, T>, _body: impl Draw<'a, T>
) -> impl Draw<T> { ) -> impl Draw<'a, T> {
} }
pub fn field_v <T: Screen> ( pub fn field_v <'a, T: Screen> (
_theme: ItemTheme, _head: impl Draw<T>, _body: impl Draw<T> _theme: ItemTheme, _head: impl Draw<'a, T>, _body: impl Draw<'a, T>
) -> impl Draw<T> { ) -> impl Draw<'a, T> {
} }
pub fn view_sessions () -> impl Draw<Tui> { pub fn view_sessions <'a> () -> impl Draw<'a, Tui> {
let h = 6; let h = 6;
let w = Some(30); let w = Some(30);
let f = Rgb(224, 192, 128); let f = Rgb(224, 192, 128);
@ -1490,12 +1497,15 @@ mod draw {
Ok(Some(to.area().into())) Ok(Some(to.area().into()))
}).min_w(w).exact_h(h) }).min_w(w).exact_h(h)
} }
/// ``` /// ```
/// let bg = tengri::ratatui::style::Color::Red; /// let bg = tengri::ratatui::style::Color::Red;
/// let fg = tengri::ratatui::style::Color::Green; /// let fg = tengri::ratatui::style::Color::Green;
/// let _ = tek::view_wrap(bg, fg, "and then blue, too!"); /// let _ = tek::view_wrap(bg, fg, "and then blue, too!");
/// ``` /// ```
pub fn view_wrap (bg: Color, fg: Color, content: impl Draw<Tui>) -> impl Draw<Tui> { pub fn view_wrap <'a> (bg: Color, fg: Color, content: impl Draw<'a, Tui>)
-> impl Draw<'a, Tui>
{
let left = fg_bg(bg, Reset, y_repeat("").exact_w(1)); let left = fg_bg(bg, Reset, y_repeat("").exact_w(1));
let right = fg_bg(bg, Reset, y_repeat("").exact_w(1)); let right = fg_bg(bg, Reset, y_repeat("").exact_w(1));
east(left, west(right, fg_bg(fg, bg, content))) east(left, west(right, fg_bg(fg, bg, content)))
@ -1505,7 +1515,9 @@ mod draw {
/// let _ = tek::view_meter("", 0.0); /// let _ = tek::view_meter("", 0.0);
/// let _ = tek::view_meters(&[0.0, 0.0]); /// let _ = tek::view_meters(&[0.0, 0.0]);
/// ``` /// ```
pub fn view_meter <'a> (label: &'a str, value: f32) -> impl Draw<Tui> + 'a { pub fn view_meter <'a> (label: &'a str, value: f32)
-> impl Draw<'a, Tui>
{
let f = field_h(ItemTheme::G[128], label, format!("{:>+9.3}", value)); let f = field_h(ItemTheme::G[128], label, format!("{:>+9.3}", value));
let w = if value >= 0.0 { 13 } let w = if value >= 0.0 { 13 }
else if value >= -1.0 { 12 } else if value >= -1.0 { 12 }
@ -1527,13 +1539,15 @@ mod draw {
south!(f, bg(c, ()).exact_wh(w, 1)) south!(f, bg(c, ()).exact_wh(w, 1))
} }
pub fn view_meters (values: &[f32;2]) -> impl Draw<Tui> + use<'_> { pub fn view_meters (values: &[f32;2]) -> impl Draw<'_, Tui> + use<'_> {
let left = format!("L/{:>+9.3}", values[0]); let left = format!("L/{:>+9.3}", values[0]);
let right = format!("R/{:>+9.3}", values[1]); let right = format!("R/{:>+9.3}", values[1]);
south(left, right) south(left, right)
} }
pub fn view_track_header (theme: ItemTheme, content: impl Draw<Tui>) -> impl Draw<Tui> { pub fn view_track_header <'a> (theme: ItemTheme, content: impl Draw<'a, Tui>)
-> impl Draw<'a, Tui>
{
bg(theme.darker.term, content.align_e().full_w()).exact_w(12) bg(theme.darker.term, content.align_e().full_w()).exact_w(12)
} }
@ -1541,7 +1555,9 @@ mod draw {
/// let _ = tek::button_2("", "", true); /// let _ = tek::button_2("", "", true);
/// let _ = tek::button_2("", "", false); /// let _ = tek::button_2("", "", false);
/// ``` /// ```
pub fn button_2 <'a> (key: impl Draw<Tui>, label: impl Draw<Tui>, hide: bool) -> impl Draw<Tui> { pub fn button_2 <'a> (key: impl Draw<'a, Tui>, label: impl Draw<'a, Tui>, hide: bool)
-> impl Draw<'a, Tui>
{
let c1 = tui_orange(); let c1 = tui_orange();
let c2 = tui_g(0); let c2 = tui_g(0);
let c3 = tui_g(96); let c3 = tui_g(96);
@ -1555,8 +1571,11 @@ mod draw {
/// let _ = tek::button_3("", "", "", false); /// let _ = tek::button_3("", "", "", false);
/// ``` /// ```
pub fn button_3 <'a> ( pub fn button_3 <'a> (
key: impl Draw<Tui>, label: impl Draw<Tui>, value: impl Draw<Tui>, editing: bool, key: impl Draw<'a, Tui>,
) -> impl Draw<Tui> { label: impl Draw<'a, Tui>,
value: impl Draw<'a, Tui>,
editing: bool,
) -> impl Draw<'a, Tui> {
let c1 = tui_orange(); let c1 = tui_orange();
let c2 = tui_g(0); let c2 = tui_g(0);
let c3 = tui_g(96); let c3 = tui_g(96);

2
tengri

@ -1 +1 @@
Subproject commit 95ace837565c65292d86694cb395d9ba7fa834eb Subproject commit 291ab632245c8beb83973da4f5157eb7b40cc7eb