use crate::args::Args;
use crate::event::VivacKind;
use crate::failure::{Failure, R};
use crate::output::outln;
struct HookInput {
source: String,
session: Option<String>,
}
impl HookInput {
fn read() -> HookInput {
use std::io::IsTerminal;
let mut raw = String::new();
if !std::io::stdin().is_terminal() {
use std::io::Read;
std::io::stdin().read_to_string(&mut raw).ok();
}
let v: serde_json::Value = serde_json::from_str(&raw).unwrap_or(serde_json::Value::Null);
HookInput {
source: v
.get("source")
.and_then(|s| s.as_str())
.unwrap_or("unknown")
.to_string(),
session: v
.get("session_id")
.and_then(|s| s.as_str())
.map(str::to_string),
}
}
}
pub fn start(ctx: &mut crate::ops::Ctx, a: &Args, project: &str) -> R {
if !a.has("hook") {
return crate::brief::brief(&ctx.tree, ctx.anchor.as_ref(), a, project);
}
let text = crate::brief::to_text(&ctx.tree, ctx.anchor.as_ref(), a, project)?;
print!("{text}");
let hook = HookInput::read();
crate::ops::session_started(ctx, &hook.source, hook.session).ok();
Ok(())
}
pub fn end(ctx: &mut crate::ops::Ctx, a: &Args) -> R {
if ctx.tree.stack.is_empty() {
if !a.has("hook") {
outln!(" Empty stack: no stop worth saving.");
}
return Ok(());
}
if ctx.tree.seq_change <= ctx.tree.seq_vivac {
if !a.has("hook") {
outln!(" Nothing changed since the last stop.");
}
return Ok(());
}
let next = a.opt_or("next");
let label = segment_label(&ctx.tree);
let num = ctx.tree.next_vivac_num.max(1);
crate::ops::auto_vivac(ctx, VivacKind::Auto, &next, &label)?;
if !a.has("hook") {
outln!(" v{num} automatic stop at session close");
}
Ok(())
}
fn segment_label(t: &crate::model::Tree) -> String {
let mut parts = Vec::new();
if t.seg_new > 0 {
parts.push(format!("{} new", t.seg_new));
}
if t.seg_closed > 0 {
parts.push(format!("{} closed", t.seg_closed));
}
if t.seg_notes == 1 {
parts.push("1 note".to_string());
} else if t.seg_notes > 1 {
parts.push(format!("{} notes", t.seg_notes));
}
if parts.is_empty() && t.seg_events > 0 {
parts.push(if t.seg_events == 1 {
"1 change".to_string()
} else {
format!("{} changes", t.seg_events)
});
}
parts.join(", ")
}
pub fn dispatch(ctx: &mut crate::ops::Ctx, a: &Args, project: &str) -> R {
match a.positional(0) {
Some("start") => start(ctx, a, project),
Some("end") => end(ctx, a),
_ => Err(Failure::usage("usage: vivac session start|end [--hook]")),
}
}