use super::App;
use crate::tui::state::{PopupKind, PopupState};
impl App {
pub(super) fn navigate_history_up(&mut self) {
if self.input_history.is_empty() {
return;
}
match self.history_index {
None => {
self.saved_input = self.state.input.clone();
let idx = self.input_history.len() - 1;
self.history_index = Some(idx);
self.state.input = self.input_history[idx].clone();
self.state.cursor = self.state.input.len();
}
Some(idx) if idx > 0 => {
let new_idx = idx - 1;
self.history_index = Some(new_idx);
self.state.input = self.input_history[new_idx].clone();
self.state.cursor = self.state.input.len();
}
_ => {}
}
}
pub(super) fn navigate_history_down(&mut self) {
if let Some(idx) = self.history_index {
if idx + 1 < self.input_history.len() {
let new_idx = idx + 1;
self.history_index = Some(new_idx);
self.state.input = self.input_history[new_idx].clone();
self.state.cursor = self.state.input.len();
} else {
self.history_index = None;
self.state.input = self.saved_input.clone();
self.state.cursor = self.state.input.len();
}
}
}
pub(super) fn switch_agent(&mut self, direction: i32) {
let count = self.config.agents.len();
if count == 0 {
return;
}
let new_index =
(self.current_agent_index as i32 + direction).rem_euclid(count as i32) as usize;
self.current_agent_index = new_index;
let agent = self.config.agents[new_index].clone();
self.config.cli = None;
self.config.cli_args = Vec::new();
let effective_provider: Option<(String, crate::config::ProviderEntry, String, String)> =
agent
.providers
.iter()
.find_map(|entry_name| {
let model = entry_name
.find('/')
.map(|i| entry_name[i + 1..].to_string())
.unwrap_or_else(|| agent.model.clone());
crate::config::resolve_provider(entry_name)
.map(|(p, k)| (entry_name.clone(), p, k, model))
})
.or_else(|| {
crate::config::resolve_default_provider()
});
let effective_model = effective_provider
.as_ref()
.map(|(_, _, _, m)| m.clone())
.unwrap_or_else(|| agent.model.clone());
let resolved_provider_name = effective_provider
.as_ref()
.map(|(_, entry, _, _)| entry.name.clone())
.or_else(|| agent.provider.clone());
if let Some((_, entry, api_key, ref model)) = effective_provider {
if entry.is_cli() {
self.config.cli = entry.cli.clone();
self.config.cli_args = entry.cli_args.clone();
self.client.model = model.clone();
} else {
let profile = crate::api::model_profile::profile_for(model);
self.client.switch_provider(
entry.base_url.clone(),
api_key,
model.clone(),
agent.max_output_tokens.unwrap_or(profile.max_output_tokens),
);
self.config.base_url = entry.base_url;
self.config.api_key = String::new(); }
self.config.supports_tools = agent.supports_tools;
} else {
self.client.model = effective_model.clone();
}
self.config.model = effective_model.clone();
self.state.model_name = effective_model.clone();
if let Some(ref name) = resolved_provider_name {
self.state.provider_name = name.clone();
}
self.config.temperature = self.config.resolve_temperature(&agent.model, Some(&agent));
self.config.thinking_budget_tokens = self
.config
.resolve_thinking_budget(&agent.model, Some(&agent));
self.config.reasoning_effort = self
.config
.resolve_reasoning_effort(&agent.model, Some(&agent));
self.state.agent_mode = agent.name.clone();
let display_provider = resolved_provider_name.as_deref().unwrap_or("");
let status = if display_provider.is_empty() {
effective_model.clone()
} else {
format!("{} / {}", display_provider, effective_model)
};
tracing::info!(agent = %agent.name, model = %effective_model, provider = ?resolved_provider_name, index = new_index, total = count, "Switched agent");
self.state.status_msg = format!("Agent: {} ({})", agent.name, status);
}
pub(super) fn handle_output_click(&mut self, column: u16, row: u16) {
let area = *self.state.last_output_area.borrow();
if column < area.x
|| column >= area.x + area.width
|| row < area.y
|| row >= area.y + area.height
{
return;
}
let click_visual_row = row - area.y;
let scroll = *self.state.last_render_scroll.borrow();
let absolute_row = click_visual_row + scroll;
let cum = self.state.last_line_cum_heights.borrow();
let line_index = match cum
.windows(2)
.enumerate()
.find(|(_, w)| absolute_row >= w[0] && absolute_row < w[1])
{
Some((idx, _)) => idx,
None => return,
};
let regions = self.state.diff_click_regions.borrow();
if let Some(region) = regions.iter().find(|r| r.line_index == line_index) {
let title = region.title.clone();
let content = region.content.clone();
drop(regions);
self.state.popup = Some(PopupState {
title,
content,
scroll: 0,
kind: PopupKind::Info,
saved_theme: None,
select_prefix: None,
search: String::new(),
});
}
}
}