use crate::tui::app::{ActivePanel, App, ConfirmationKind};
pub struct TextEditor<'a> {
pub buffer: &'a mut String,
pub cursor: &'a mut usize,
}
impl TextEditor<'_> {
pub fn insert_char(&mut self, c: char) {
let byte_pos = self.buffer
.char_indices()
.nth(*self.cursor)
.map(|(i, _)| i)
.unwrap_or(self.buffer.len());
self.buffer.insert(byte_pos, c);
*self.cursor += 1;
}
pub fn insert_newline(&mut self) {
let byte_pos = self.buffer
.char_indices()
.nth(*self.cursor)
.map(|(i, _)| i)
.unwrap_or(self.buffer.len());
self.buffer.insert(byte_pos, '\n');
*self.cursor += 1;
}
pub fn backspace(&mut self) {
if *self.cursor == 0 {
return;
}
let char_pos = *self.cursor - 1;
let byte_pos = self.buffer
.char_indices()
.nth(char_pos)
.map(|(i, _)| i)
.unwrap_or(self.buffer.len());
let char_len = self.buffer[byte_pos..]
.chars()
.next()
.map(|c| c.len_utf8())
.unwrap_or(1);
self.buffer.drain(byte_pos..byte_pos + char_len);
*self.cursor -= 1;
}
#[allow(dead_code)]
pub fn delete(&mut self) {
if *self.cursor >= self.buffer.chars().count() {
return;
}
let byte_pos = self.buffer
.char_indices()
.nth(*self.cursor)
.map(|(i, _)| i)
.unwrap_or(self.buffer.len());
self.buffer.remove(byte_pos);
}
pub fn move_left(&mut self) {
if *self.cursor > 0 {
*self.cursor -= 1;
}
}
pub fn move_right(&mut self) {
let max = self.buffer.chars().count();
if *self.cursor < max {
*self.cursor += 1;
}
}
pub fn home(&mut self) {
*self.cursor = 0;
}
pub fn end(&mut self) {
*self.cursor = self.buffer.chars().count();
}
}
pub async fn execute_confirmation(app: &mut App, kind: ConfirmationKind) {
match kind {
ConfirmationKind::Exit => {
app.running = false;
}
ConfirmationKind::Reset => {
app.reset_to_defaults();
}
ConfirmationKind::Delete => {
if let Some(model) = app.selected_model() {
let display_name = model.display_name.clone();
app.add_log(
format!(
"Deleting model {} (config moved to unused)...",
display_name
),
crate::config::LogLevel::Info,
);
}
}
ConfirmationKind::Unload => {
if let Some((name, _)) = &app.pending.pending_api_unload {
app.add_log(
format!("Unloading {} via API...", name),
crate::config::LogLevel::Info,
);
}
}
ConfirmationKind::DeleteBackend => {
}
}
}
pub fn mark_settings_dirty(app: &mut App, recalc_vram: bool) {
app.settings_state.settings_render_cache = None;
if recalc_vram {
app.update_vram_estimate();
}
}
pub fn sync_global_settings(app: &mut App) {
let changed = app.config.default.host != app.settings.host
|| app.config.default.port != app.settings.port
|| app.config.default.backend != app.settings.backend
|| app.config.default.parallel != app.settings.parallel
|| app.config.default.max_concurrent_predictions != app.settings.max_concurrent_predictions
|| app.config.default.threads != app.settings.threads
|| app.config.default.threads_batch != app.settings.threads_batch
|| app.config.default.api_endpoint_enabled != app.settings.api_endpoint_enabled
|| app.config.default.api_endpoint_port != app.settings.api_endpoint_port
|| app.config.default.server_mode != app.server_mode
|| app.config.default.router_max_models != app.router_max_models
|| app.config.default.llama_cpp_version_cpu != app.settings.llama_cpp_version_cpu
|| app.config.default.llama_cpp_version_vulkan != app.settings.llama_cpp_version_vulkan
|| app.config.default.llama_cpp_version_rocm != app.settings.llama_cpp_version_rocm
|| app.config.default.llama_cpp_version_rocm_lemonade
!= app.settings.llama_cpp_version_rocm_lemonade
|| app.config.default.llama_cpp_version_cuda != app.settings.llama_cpp_version_cuda;
if !changed {
return;
}
app.config.default.host = app.settings.host.clone();
app.config.default.port = app.settings.port;
app.config.default.backend = app.settings.backend;
app.config.default.parallel = app.settings.parallel;
app.config.default.max_concurrent_predictions = app.settings.max_concurrent_predictions;
app.config.default.threads = app.settings.threads;
app.config.default.threads_batch = app.settings.threads_batch;
app.config.default.api_endpoint_enabled = app.settings.api_endpoint_enabled;
app.config.default.api_endpoint_port = app.settings.api_endpoint_port;
app.config.default.server_mode = app.server_mode;
app.config.default.router_max_models = app.router_max_models;
app.config.default.llama_cpp_version_cpu = app.settings.llama_cpp_version_cpu.clone();
app.config.default.llama_cpp_version_vulkan = app.settings.llama_cpp_version_vulkan.clone();
app.config.default.llama_cpp_version_rocm = app.settings.llama_cpp_version_rocm.clone();
app.config.default.llama_cpp_version_rocm_lemonade =
app.settings.llama_cpp_version_rocm_lemonade.clone();
app.config.default.llama_cpp_version_cuda = app.settings.llama_cpp_version_cuda.clone();
if let Err(e) = app.config.save() {
app.add_log(
format!("Failed to save global settings: {}", e),
crate::config::LogLevel::Error,
);
}
}
pub fn handle_fkey_toggle(
app: &mut App,
panel_idx: u8,
target_panel: Option<ActivePanel>,
require_no_server: bool,
) {
if require_no_server && app.server.server_handle.is_some() {
return;
}
app.toggle_panel_visibility(panel_idx);
if app.is_panel_visible(panel_idx) {
if let Some(panel) = target_panel {
app.ui.active_panel = panel;
}
}
}
pub fn handle_fkey_show(
app: &mut App,
panel_idx: u8,
target_panel: ActivePanel,
require_no_server: bool,
) {
if require_no_server && app.server.server_handle.is_some() {
return;
}
app.ui.panel_visibility |= 1 << panel_idx;
app.ui.active_panel = target_panel;
}
pub fn handle_fkey_show_all(app: &mut App) {
app.ui.panel_visibility = 0b111111;
app.log.log_expanded = false;
}