use super::event_handlers::{
handle_key_press, handle_mouse_event, handle_resize_event, poll_and_tick,
};
use super::input_submit::{SubmitOutcome as FlowSubmitOutcome, handle_submit_result};
use crate::app::agent::config::Config;
use crate::session::ui_types as models;
use anyhow::Result;
use crossterm::event::{self, Event as CrosstermEvent, KeyEventKind};
use super::super::session::{build_project_info, collect_modified_files, create_cli_session};
use super::super::setup::CliSetup;
use super::super::stats::{CliStats, build_session_title};
use super::super::stdio::StdIoRedirectGuard;
use super::super::transcript::{TranscriptEntry, TranscriptRole};
use super::super::tui::CliTui;
use crate::app::agent::session;
pub(crate) async fn run_interactive_loop(
config: &Config,
setup: &CliSetup,
final_output: &mut String,
) -> Result<()> {
let interactive_log_path =
config.workspace_dir.join(".vibewindow").join("logs").join("interactive-terminal.log");
let _stdio_redirect_guard = StdIoRedirectGuard::redirect_to_file(&interactive_log_path)?;
let mut tui = CliTui::new()?;
let request_root_dir = std::env::current_dir().unwrap_or_else(|_| config.workspace_dir.clone());
let mut session_history: Vec<models::ChatMessage> = Vec::new();
let mut session_id = create_cli_session(&request_root_dir, None).await;
let mut stream_id = session::session::now_ms();
let mut session_title_refreshed = false;
let mut transcript: Vec<TranscriptEntry> = vec![TranscriptEntry::new(
TranscriptRole::System,
"欢迎来到 VibeWindow 交互式模式,输入 /help 查看命令",
)];
let mut input = String::new();
let mut cursor_idx: usize = 0;
let mut busy = false;
let mut awaiting_clear_confirm = false;
let mut stats = CliStats::default();
let workspace = build_project_info(&config.workspace_dir);
let mut modified_files = collect_modified_files(&config.workspace_dir);
let mut files_collapsed = true;
let mut draft = String::new();
let mut scroll_back: u16 = 0;
let mut show_menu = false;
let mut exit_confirm_armed = false;
let session_title = build_session_title(&stats, &setup.provider_name, &setup.model_name);
tui.draw(
&transcript,
&input,
cursor_idx,
busy,
awaiting_clear_confirm,
&setup.provider_name,
&setup.model_name,
&stats,
&workspace,
&draft,
&session_title,
&modified_files,
files_collapsed,
scroll_back,
show_menu,
)?;
loop {
if !poll_and_tick(
&mut tui,
busy,
&transcript,
&input,
cursor_idx,
awaiting_clear_confirm,
&stats,
&workspace,
&draft,
&setup.provider_name,
&setup.model_name,
&modified_files,
files_collapsed,
scroll_back,
show_menu,
)? {
continue;
}
let evt = event::read()?;
if let CrosstermEvent::Resize(_, _) = evt {
handle_resize_event(
&mut tui,
&transcript,
&input,
cursor_idx,
busy,
awaiting_clear_confirm,
&stats,
&workspace,
&draft,
&setup.provider_name,
&setup.model_name,
&modified_files,
files_collapsed,
scroll_back,
show_menu,
)?;
continue;
}
if let CrosstermEvent::Mouse(mouse) = evt {
handle_mouse_event(
&mut tui,
mouse,
&mut scroll_back,
&transcript,
&input,
cursor_idx,
busy,
awaiting_clear_confirm,
&stats,
&workspace,
&draft,
&setup.provider_name,
&setup.model_name,
&modified_files,
files_collapsed,
show_menu,
)?;
continue;
}
let CrosstermEvent::Key(key) = evt else {
continue;
};
if key.kind != KeyEventKind::Press {
continue;
}
let submit = handle_key_press(
&mut tui,
key,
&mut transcript,
&mut input,
&mut cursor_idx,
&mut scroll_back,
&mut show_menu,
&mut exit_confirm_armed,
);
if let Some(user_input) = submit {
let result = handle_submit_result(
config,
setup,
user_input,
&mut tui,
&mut transcript,
&mut session_history,
&mut session_id,
&mut stream_id,
&mut session_title_refreshed,
&input,
&mut cursor_idx,
&mut busy,
&mut awaiting_clear_confirm,
&mut stats,
&workspace,
&mut modified_files,
&mut files_collapsed,
&mut draft,
&mut scroll_back,
&mut show_menu,
final_output,
)
.await?;
if result == FlowSubmitOutcome::Exit {
break;
}
}
}
Ok(())
}
#[derive(PartialEq, Eq)]
pub(crate) enum SubmitOutcome {
Continue,
Exit,
}