Feat: add hidden mode and new documentation

This commit is contained in:
2026-02-26 12:31:56 +01:00
parent e1cf57918e
commit 70032acc75
95 changed files with 1055 additions and 286 deletions

View File

@@ -1,3 +1,5 @@
//! Forth script compilation, evaluation, and editor ↔ step synchronization.
use crossbeam_channel::Sender;
use crate::engine::LinkState;
@@ -8,6 +10,7 @@ use crate::state::{EditorTarget, FlashKind, Modal, SampleTree};
use super::{App, COMPLETION_CANDIDATES};
impl App {
/// Build a `StepContext` for evaluating a script outside the sequencer.
pub(super) fn create_step_context(&self, step_idx: usize, link: &LinkState) -> StepContext<'static> {
let (bank, pattern) = self.current_bank_pattern();
let speed = self
@@ -37,6 +40,7 @@ impl App {
}
}
/// Load the current step's script into the editor widget.
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(
@@ -63,6 +67,7 @@ impl App {
}
}
/// Write the editor widget's content back to the current step.
pub fn save_editor_to_step(&mut self) {
let text = self.editor_ctx.editor.content();
let (bank, pattern) = self.current_bank_pattern();
@@ -76,6 +81,7 @@ impl App {
self.project_state.mark_dirty(change.bank, change.pattern);
}
/// Switch the editor to the project prelude script.
pub fn open_prelude_editor(&mut self) {
let prelude = &self.project_state.project.prelude;
let lines: Vec<String> = if prelude.is_empty() {
@@ -104,6 +110,7 @@ impl App {
self.load_step_to_editor();
}
/// Evaluate the project prelude to seed variables and definitions.
pub fn evaluate_prelude(&mut self, link: &LinkState) {
let prelude = &self.project_state.project.prelude;
if prelude.trim().is_empty() {
@@ -121,6 +128,7 @@ impl App {
}
}
/// Evaluate a script and immediately send its audio commands.
pub fn execute_script_oneshot(
&self,
script: &str,
@@ -137,6 +145,7 @@ impl App {
Ok(())
}
/// Compile (evaluate) the current step's script to check for errors.
pub fn compile_current_step(&mut self, link: &LinkState) {
let step_idx = self.editor_ctx.step;
let (bank, pattern) = self.current_bank_pattern();
@@ -162,6 +171,49 @@ impl App {
}
}
/// Load the project's periodic script into the script editor.
pub fn load_script_to_editor(&mut self) {
let script = &self.project_state.project.script;
let lines: Vec<String> = if script.is_empty() {
vec![String::new()]
} else {
script.lines().map(String::from).collect()
};
self.script_editor.editor.set_content(lines);
self.script_editor.editor.set_candidates(COMPLETION_CANDIDATES.clone());
self.script_editor
.editor
.set_completion_enabled(self.ui.show_completion);
let tree = SampleTree::from_paths(&self.audio.config.sample_paths);
self.script_editor.editor.set_sample_folders(tree.all_folder_names());
}
/// Write the script editor content back to the project.
pub fn save_script_from_editor(&mut self) {
let text = self.script_editor.editor.content();
self.project_state.project.script = text;
self.script_editor.dirty = true;
}
/// Evaluate the script page content to check for errors.
pub fn evaluate_script_page(&mut self, link: &LinkState) {
let script = self.script_editor.editor.content();
if script.trim().is_empty() {
return;
}
let ctx = self.create_step_context(0, 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);
}
}
}
/// Compile all steps in the current pattern to warm up definitions.
pub fn compile_all_steps(&mut self, link: &LinkState) {
let pattern_len = self.current_edit_pattern().length;
let (bank, pattern) = self.current_bank_pattern();