130 lines
3.8 KiB
Rust
130 lines
3.8 KiB
Rust
mod app;
|
|
mod block;
|
|
mod cache;
|
|
mod command;
|
|
mod input;
|
|
pub mod keys;
|
|
mod markdown;
|
|
mod multi_pod;
|
|
mod picker;
|
|
mod pod_list;
|
|
mod role_session_registry;
|
|
mod scroll;
|
|
mod single_pod;
|
|
mod spawn;
|
|
mod task;
|
|
mod tool;
|
|
mod ui;
|
|
mod view_mode;
|
|
mod workspace_panel;
|
|
|
|
use std::io;
|
|
use std::path::PathBuf;
|
|
use std::process::ExitCode;
|
|
|
|
use crossterm::event::{DisableBracketedPaste, DisableMouseCapture, EnableBracketedPaste};
|
|
use crossterm::execute;
|
|
use crossterm::terminal::{LeaveAlternateScreen, disable_raw_mode, enable_raw_mode};
|
|
use session_store::SegmentId;
|
|
|
|
use client::PodRuntimeCommand;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct LaunchOptions {
|
|
pub mode: LaunchMode,
|
|
pub runtime_command: PodRuntimeCommand,
|
|
pub workspace_root: PathBuf,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum LaunchMode {
|
|
Spawn {
|
|
pod_name: Option<String>,
|
|
profile: Option<String>,
|
|
},
|
|
/// `yoi <name>` / `yoi --pod <name>`: attach to a live Pod by name if
|
|
/// possible; otherwise launch the Pod runtime command with `--pod <name>` so it
|
|
/// resumes from name-keyed state or creates a fresh same-name Pod.
|
|
PodName {
|
|
pod_name: String,
|
|
socket_override: Option<PathBuf>,
|
|
},
|
|
/// `yoi -r` / `yoi --resume`: open the Pod picker, then attach to the
|
|
/// selected live Pod or restore the selected stopped Pod by name.
|
|
Resume,
|
|
/// `yoi --session <UUID>`: skip the picker, go straight to the
|
|
/// resume name dialog with `id` baked in.
|
|
ResumeWithSession(SegmentId),
|
|
/// `yoi panel`: open the workspace panel from the current workspace.
|
|
Panel,
|
|
}
|
|
|
|
pub async fn launch(options: LaunchOptions) -> ExitCode {
|
|
let LaunchOptions {
|
|
mode,
|
|
runtime_command,
|
|
workspace_root,
|
|
} = options;
|
|
|
|
if let Err(e) = std::env::set_current_dir(&workspace_root) {
|
|
eprintln!(
|
|
"yoi: failed to enter workspace {}: {e}",
|
|
workspace_root.display()
|
|
);
|
|
return ExitCode::FAILURE;
|
|
}
|
|
|
|
if let Err(e) = enable_raw_mode() {
|
|
eprintln!("yoi: failed to enter raw mode: {e}");
|
|
return ExitCode::FAILURE;
|
|
}
|
|
if let Err(e) = execute!(io::stdout(), EnableBracketedPaste) {
|
|
let _ = disable_raw_mode();
|
|
eprintln!("yoi: {e}");
|
|
return ExitCode::FAILURE;
|
|
}
|
|
|
|
let result = match mode {
|
|
LaunchMode::Spawn { pod_name, profile } => {
|
|
single_pod::run_spawn(None, pod_name, profile, runtime_command).await
|
|
}
|
|
LaunchMode::PodName {
|
|
pod_name,
|
|
socket_override,
|
|
} => single_pod::run_pod_name(pod_name, socket_override, runtime_command).await,
|
|
LaunchMode::Resume => single_pod::run_resume(runtime_command).await,
|
|
LaunchMode::ResumeWithSession(id) => {
|
|
single_pod::run_spawn(Some(id), None, None, runtime_command).await
|
|
}
|
|
LaunchMode::Panel => single_pod::run_panel(runtime_command).await,
|
|
};
|
|
|
|
// Always restore the terminal first so any pending eprintln below
|
|
// shows up cleanly in scrollback rather than inside an active
|
|
// alternate-screen buffer.
|
|
let mut stdout = io::stdout();
|
|
let _ = execute!(
|
|
stdout,
|
|
DisableMouseCapture,
|
|
LeaveAlternateScreen,
|
|
DisableBracketedPaste
|
|
);
|
|
let _ = disable_raw_mode();
|
|
let _ = execute!(stdout, crossterm::cursor::Show);
|
|
|
|
match result {
|
|
Ok(()) => ExitCode::SUCCESS,
|
|
Err(e) => {
|
|
// SpawnError has already been painted into the inline
|
|
// viewport's final frame, so it's already visible in the
|
|
// user's scrollback — printing it again would be a noisy
|
|
// duplicate. Other errors (pod-name failures, terminal setup
|
|
// hiccups, etc.) need surfacing here.
|
|
if e.downcast_ref::<spawn::SpawnError>().is_none() {
|
|
eprintln!("yoi: {e}");
|
|
}
|
|
ExitCode::FAILURE
|
|
}
|
|
}
|
|
}
|