use super::TernBackend;
use crate::backend::*;
use parking_lot::Mutex;
use std::sync::Arc;
mod cli;
mod close;
mod focus;
mod probe;
mod spawn;
#[derive(Default)]
struct Script {
calls: Mutex<Vec<String>>,
script: Mutex<Vec<Reply>>,
}
struct Reply {
fragment: String,
status: i32,
stdout: String,
stderr: String,
}
impl Script {
fn reply(self, fragment: &str, stdout: impl Into<String>) -> Self {
self.script.lock().push(Reply {
fragment: fragment.to_string(),
status: 0,
stdout: stdout.into(),
stderr: String::new(),
});
self
}
fn refused(self, fragment: &str, stderr: impl Into<String>) -> Self {
self.script.lock().push(Reply {
fragment: fragment.to_string(),
status: 1,
stdout: String::new(),
stderr: stderr.into(),
});
self
}
fn calls(&self) -> Vec<String> {
self.calls.lock().clone()
}
fn call_count(&self) -> usize {
self.calls.lock().len()
}
}
impl Runner for Script {
fn run(
&self,
program: &str,
args: &[String],
_cwd: Option<&Path>,
env: &BTreeMap<String, String>,
) -> Result<CommandOutput> {
let call = format!("{program} {}", args.join(" "));
self.calls.lock().push(call.clone());
let mut script = self.script.lock();
let index = script
.iter()
.position(|reply| call.contains(reply.fragment.as_str()))
.unwrap_or_else(|| panic!("unscripted tern call: {call}"));
let reply = script.remove(index);
let _ = env;
Ok(CommandOutput {
status: reply.status,
stdout: reply.stdout.into_bytes(),
stderr: reply.stderr.into_bytes(),
})
}
}
fn tab(id: u64, name: Option<&str>, blocks: &[u64], focused: Option<usize>) -> Value {
serde_json::json!({
"id": id,
"number": 1,
"name": name,
"shown": true,
"zoomed": false,
"blocks": blocks.iter().enumerate().map(|(at, block)| {
serde_json::json!({
"id": block,
"title": "/w",
"cwd": "/w",
"program": "/opt/homebrew/bin/fish",
"args": ["-l"],
"command": null,
"exited": null,
"keep_open": true,
"focused": Some(at) == focused,
"live": true,
})
}).collect::<Vec<_>>(),
"splits": {"Leaf": blocks.first().copied().unwrap_or(0)},
})
}
fn session(id: u64, name: Option<&str>, tabs: Vec<Value>) -> Value {
serde_json::json!({
"id": id,
"name": name,
"shown": true,
"tabs": tabs,
})
}
fn listing(sessions: Vec<Value>) -> String {
serde_json::json!({"sessions": sessions, "detached": []}).to_string()
}
fn created(session: u64, tab_id: u64, block: u64) -> String {
serde_json::json!({"session": session, "tab": tab_id, "block": block}).to_string()
}
fn session_ref(pane: &str) -> SessionRef {
SessionRef {
task_id: "abcd1234-ffff-4000-8000-000000000001".into(),
backend: "tern".into(),
backend_ref: serde_json::json!({
"tern": {
"session_id": "2147483648",
"tab_id": "2147483649",
"pane_id": pane,
"session_label": "onlyne:lab",
"base_pane": "2147483650",
"split_direction": "right",
}
}),
generation: 1,
}
}
fn backend(script: Script) -> (TernBackend, Arc<Script>) {
let script = Arc::new(script);
(
TernBackend::with_env(script.clone(), BTreeMap::new()),
script,
)
}
fn spec() -> SpawnSpec {
SpawnSpec {
cwd: std::path::PathBuf::from("/w"),
task_id: "abcd1234-ffff-4000-8000-000000000001".into(),
command: vec!["pi".into(), "--session-id".into(), "a b".into()],
env: [
("ONLYNE_ROLE".to_string(), "planner".to_string()),
("ONLYNE_CLUSTER".to_string(), "lab".to_string()),
]
.into_iter()
.collect(),
tools_token: String::new(),
prose: String::new(),
focus: None,
placement: None,
rename: None,
}
}