tenere 0.8.0

TUI interface for LLMs written in Rust
Documentation
use std;
use std::collections::HashMap;
use std::sync::atomic::AtomicBool;

use crate::config::Config;
use crate::notification::Notification;
use crate::spinner::Spinner;
use crossterm::event::KeyCode;
use tui::widgets::scrollbar::ScrollbarState;

use std::sync::Arc;

pub type AppResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;

#[derive(Debug)]
pub enum Mode {
    Normal,
    Insert,
}

#[derive(Debug)]
pub enum FocusedBlock {
    Prompt,
    Chat,
    History,
    Preview,
}

#[derive(Debug)]
pub struct App {
    pub prompt: String,
    pub mode: Mode,
    pub running: bool,
    pub chat: Vec<String>,
    pub scroll: u16,
    pub previous_key: KeyCode,
    pub focused_block: FocusedBlock,
    pub show_help_popup: bool,
    pub llm_messages: Vec<HashMap<String, String>>,
    pub answer: String,
    pub history: Vec<Vec<String>>,
    pub show_history_popup: bool,
    pub history_thread_index: usize,
    pub config: Arc<Config>,
    pub notifications: Vec<Notification>,
    pub spinner: Spinner,
    pub terminate_response_signal: Arc<AtomicBool>,
    pub chat_scroll_state: ScrollbarState,
    pub chat_scroll: u16,
}

impl App {
    pub fn new(config: Arc<Config>) -> Self {
        Self {
            running: true,
            prompt: String::from(">_ "),
            mode: Mode::Normal,
            chat: Vec::new(),
            scroll: 0,
            previous_key: KeyCode::Null,
            focused_block: FocusedBlock::Prompt,
            show_help_popup: false,
            llm_messages: Vec::new(),
            answer: String::new(),
            history: Vec::new(),
            show_history_popup: false,
            history_thread_index: 0,
            config,
            notifications: Vec::new(),
            spinner: Spinner::default(),
            terminate_response_signal: Arc::new(AtomicBool::new(false)),
            chat_scroll_state: ScrollbarState::default(),
            chat_scroll: 0,
        }
    }

    pub fn tick(&mut self) {
        self.notifications.retain(|n| n.ttl > 0);
        self.notifications.iter_mut().for_each(|n| n.ttl -= 1);

        if self.spinner.active {
            self.chat.pop();
            self.chat
                .push(format!("🤖: Waiting {}", self.spinner.draw()));
            self.spinner.update();
        }
    }
}