use crate::AppModel;
use crate::world::marks::{self, BlConf, MarksState, Mode};
use crate::xdg::Env;
use std::path::{Path, PathBuf};
pub struct MarksPane {
runner: BlConf,
project: Option<PathBuf>,
state: Option<MarksState>,
branch: String,
status: String,
}
impl MarksPane {
pub fn resolve(world: &Env) -> Self {
Self {
runner: BlConf::resolve(world),
project: None,
state: None,
branch: String::new(),
status: String::new(),
}
}
}
pub fn render(ui: &mut egui::Ui, model: &mut AppModel, pane: &mut MarksPane) {
ui.heading(
egui::RichText::new("project marks (bl store branch)")
.color(crate::theme::integration_hue("bl")),
);
let Some(project) = model.focused_join().map(|r| r.project.clone()) else {
ui.weak("focus a workspace bound to a project to set its marks");
return;
};
let state_root = model.state_root().to_path_buf();
ui.monospace(project.display().to_string());
if pane.project.as_deref() == Some(project.as_path())
&& let Some(state) = &pane.state
{
ui.label(format!("mode: {}", describe_mode(&state.mode)));
ui.weak(format!("provenance: {}", state.provenance));
}
ui.weak(
"stealth = claims invisible to ambient `bl list`; custom branch = a parallel task universe",
);
ui.horizontal(|ui| {
if ui.button("Read current").clicked() {
pane.status = read_marks(pane, &project);
}
if ui.button("Shared").clicked() {
pane.status = apply_marks(pane, &state_root, &project, &Mode::Shared);
}
if ui.button("Stealth").clicked() {
pane.status = apply_marks(pane, &state_root, &project, &Mode::Stealth);
}
});
ui.horizontal(|ui| {
ui.label("custom branch:");
ui.text_edit_singleline(&mut pane.branch);
if ui.button("Set custom branch").clicked() {
pane.status = match Mode::custom_branch(&pane.branch) {
Some(mode) => apply_marks(pane, &state_root, &project, &mode),
None => "branch name required (and not the default)".to_string(),
};
}
});
if !pane.status.is_empty() {
ui.weak(&pane.status);
}
}
fn describe_mode(mode: &Mode) -> String {
match mode {
Mode::Shared => "shared (origin / balls/tasks) — coordinates with ambient bl".to_string(),
Mode::Stealth => "stealth (local-only) — invisible to ambient bl list".to_string(),
Mode::CustomBranch(name) => format!("custom branch: {name} — a parallel task universe"),
}
}
fn read_marks(pane: &mut MarksPane, project: &Path) -> String {
match marks::read(&pane.runner, project) {
Ok(state) => {
pane.project = Some(project.to_path_buf());
let msg = summary(state.as_ref());
pane.state = state;
msg
}
Err(e) => e.to_string(),
}
}
fn apply_marks(pane: &mut MarksPane, state_root: &Path, project: &Path, mode: &Mode) -> String {
match marks::apply(&pane.runner, state_root, &super::now_ts(), project, mode) {
Ok(state) => {
pane.project = Some(project.to_path_buf());
let msg = summary(state.as_ref());
pane.state = state;
format!("applied — now {msg}")
}
Err(e) => e.to_string(),
}
}
fn summary(state: Option<&MarksState>) -> String {
match state {
Some(s) => describe_mode(&s.mode),
None => "not a balls project (run bl prime)".to_string(),
}
}