Feat: refactoring codebase

This commit is contained in:
2026-02-16 16:00:57 +01:00
parent c749ed6f85
commit b60703aa16
49 changed files with 1852 additions and 1853 deletions

190
src/app/scripting.rs Normal file
View File

@@ -0,0 +1,190 @@
use crossbeam_channel::Sender;
use crate::engine::LinkState;
use crate::model::StepContext;
use crate::services::pattern_editor;
use crate::state::{EditorTarget, FlashKind, Modal, SampleTree};
use super::{App, COMPLETION_CANDIDATES};
impl App {
pub(super) fn create_step_context(&self, step_idx: usize, link: &LinkState) -> StepContext<'static> {
let (bank, pattern) = self.current_bank_pattern();
let speed = self
.project_state
.project
.pattern_at(bank, pattern)
.speed
.multiplier();
StepContext {
step: step_idx,
beat: link.beat(),
bank,
pattern,
tempo: link.tempo(),
phase: link.phase(),
slot: 0,
runs: 0,
iter: 0,
speed,
fill: false,
nudge_secs: 0.0,
cc_access: None,
speed_key: "",
chain_key: "",
#[cfg(feature = "desktop")]
mouse_x: 0.5,
#[cfg(feature = "desktop")]
mouse_y: 0.5,
#[cfg(feature = "desktop")]
mouse_down: 0.0,
}
}
pub(super) fn load_step_to_editor(&mut self) {
let (bank, pattern) = self.current_bank_pattern();
if let Some(script) = pattern_editor::get_step_script(
&self.project_state.project,
bank,
pattern,
self.editor_ctx.step,
) {
let lines: Vec<String> = if script.is_empty() {
vec![String::new()]
} else {
script.lines().map(String::from).collect()
};
self.editor_ctx.editor.set_content(lines);
self.editor_ctx.editor.set_candidates(COMPLETION_CANDIDATES.clone());
self.editor_ctx
.editor
.set_completion_enabled(self.ui.show_completion);
let tree = SampleTree::from_paths(&self.audio.config.sample_paths);
self.editor_ctx.editor.set_sample_folders(tree.all_folder_names());
if self.editor_ctx.show_stack {
crate::services::stack_preview::update_cache(&self.editor_ctx);
}
}
}
pub fn save_editor_to_step(&mut self) {
let text = self.editor_ctx.editor.content();
let (bank, pattern) = self.current_bank_pattern();
let change = pattern_editor::set_step_script(
&mut self.project_state.project,
bank,
pattern,
self.editor_ctx.step,
text,
);
self.project_state.mark_dirty(change.bank, change.pattern);
}
pub fn open_prelude_editor(&mut self) {
let prelude = &self.project_state.project.prelude;
let lines: Vec<String> = if prelude.is_empty() {
vec![String::new()]
} else {
prelude.lines().map(String::from).collect()
};
self.editor_ctx.editor.set_content(lines);
self.editor_ctx.editor.set_candidates(COMPLETION_CANDIDATES.clone());
self.editor_ctx
.editor
.set_completion_enabled(self.ui.show_completion);
let tree = SampleTree::from_paths(&self.audio.config.sample_paths);
self.editor_ctx.editor.set_sample_folders(tree.all_folder_names());
self.editor_ctx.target = EditorTarget::Prelude;
self.ui.modal = Modal::Editor;
}
pub fn save_prelude(&mut self) {
let text = self.editor_ctx.editor.content();
self.project_state.project.prelude = text;
}
pub fn close_prelude_editor(&mut self) {
self.editor_ctx.target = EditorTarget::Step;
self.load_step_to_editor();
}
pub fn evaluate_prelude(&mut self, link: &LinkState) {
let prelude = &self.project_state.project.prelude;
if prelude.trim().is_empty() {
return;
}
let ctx = self.create_step_context(0, link);
match self.script_engine.evaluate(prelude, &ctx) {
Ok(_) => {
self.ui.flash("Prelude evaluated", 150, FlashKind::Info);
}
Err(e) => {
self.ui
.flash(&format!("Prelude error: {e}"), 300, FlashKind::Error);
}
}
}
pub fn execute_script_oneshot(
&self,
script: &str,
link: &LinkState,
audio_tx: &arc_swap::ArcSwap<Sender<crate::engine::AudioCommand>>,
) -> Result<(), String> {
let ctx = self.create_step_context(self.editor_ctx.step, link);
let cmds = self.script_engine.evaluate(script, &ctx)?;
for cmd in cmds {
let _ = audio_tx
.load()
.send(crate::engine::AudioCommand::Evaluate { cmd, time: None });
}
Ok(())
}
pub fn compile_current_step(&mut self, link: &LinkState) {
let step_idx = self.editor_ctx.step;
let (bank, pattern) = self.current_bank_pattern();
let script =
pattern_editor::get_step_script(&self.project_state.project, bank, pattern, step_idx)
.unwrap_or_default();
if script.trim().is_empty() {
return;
}
let ctx = self.create_step_context(step_idx, link);
match self.script_engine.evaluate(&script, &ctx) {
Ok(_) => {
self.ui.flash("Script compiled", 150, FlashKind::Info);
}
Err(e) => {
self.ui
.flash(&format!("Script error: {e}"), 300, FlashKind::Error);
}
}
}
pub fn compile_all_steps(&mut self, link: &LinkState) {
let pattern_len = self.current_edit_pattern().length;
let (bank, pattern) = self.current_bank_pattern();
for step_idx in 0..pattern_len {
let script = pattern_editor::get_step_script(
&self.project_state.project,
bank,
pattern,
step_idx,
)
.unwrap_or_default();
if script.trim().is_empty() {
continue;
}
let ctx = self.create_step_context(step_idx, link);
let _ = self.script_engine.evaluate(&script, &ctx);
}
}
}