darwincode 1.9.65

The open source terminal AI coding agent
use crate::config::{PermissionLevel, StoredConfig, Theme};
use anyhow::Result;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SetupField {
    ApiKey,
    Model,
    BaseUrl,
    EnableCodebase,
    EnableBash,
    PermissionLevel,
    ShowThoughts,
    Theme,
    RespectGitignore,
    Save,
}

impl SetupField {
    pub fn index(self) -> usize {
        match self {
            Self::ApiKey => 0,
            Self::Model => 1,
            Self::BaseUrl => 2,
            Self::EnableCodebase => 3,
            Self::EnableBash => 4,
            Self::PermissionLevel => 5,
            Self::ShowThoughts => 6,
            Self::Theme => 7,
            Self::RespectGitignore => 8,
            Self::Save => 9,
        }
    }

    pub fn from_index(idx: usize) -> Self {
        match idx {
            0 => Self::ApiKey,
            1 => Self::Model,
            2 => Self::BaseUrl,
            3 => Self::EnableCodebase,
            4 => Self::EnableBash,
            5 => Self::PermissionLevel,
            6 => Self::ShowThoughts,
            7 => Self::Theme,
            8 => Self::RespectGitignore,
            _ => Self::Save,
        }
    }
}

#[derive(Debug)]
pub struct SetupState {
    pub api_key: String,
    pub model: String,
    pub base_url: String,
    pub enable_codebase_tools: bool,
    pub enable_bash_tools: bool,
    pub permission_level: PermissionLevel,
    pub show_thoughts: bool,
    pub theme: Theme,
    pub respect_gitignore: bool,
    pub active_field: SetupField,
    pub models: Vec<String>,
    pub selected_model: usize,
    pub is_editing: bool,
}

impl SetupState {
    pub fn from_config(config: &StoredConfig) -> Self {
        Self {
            api_key: config.api_key.clone(),
            model: config.model.clone(),
            base_url: config.base_url.clone(),
            enable_codebase_tools: config.enable_codebase_tools,
            enable_bash_tools: config.enable_bash_tools,
            permission_level: config.permission_level,
            show_thoughts: config.show_thoughts,
            theme: config.theme,
            respect_gitignore: config.respect_gitignore,
            active_field: SetupField::ApiKey,
            models: Vec::new(),
            selected_model: 0,
            is_editing: false,
        }
    }

    pub fn to_config(&self) -> Result<StoredConfig> {
        let config = StoredConfig {
            api_key: self.api_key.trim().to_owned(),
            model: self.model.trim().trim_start_matches("models/").to_owned(),
            base_url: self.base_url.trim().trim_end_matches('/').to_owned(),
            enable_codebase_tools: self.enable_codebase_tools,
            enable_bash_tools: self.enable_bash_tools,
            show_thoughts: self.show_thoughts,
            permission_level: self.permission_level,
            theme: self.theme,
            respect_gitignore: self.respect_gitignore,
        };

        config.validate()?;
        Ok(config)
    }

    pub fn push_char(&mut self, value: char) {
        match self.active_field {
            SetupField::ApiKey => {
                self.api_key.push(value);
            }
            SetupField::Model => self.model.push(value),
            SetupField::BaseUrl => self.base_url.push(value),
            _ => {}
        }
    }

    pub fn pop_char(&mut self) {
        match self.active_field {
            SetupField::ApiKey => {
                self.api_key.pop();
            }
            SetupField::Model => {
                self.model.pop();
            }
            SetupField::BaseUrl => {
                self.base_url.pop();
            }
            _ => {}
        }
    }

    pub fn select_next_model(&mut self) {
        if self.models.is_empty() {
            return;
        }

        self.selected_model = (self.selected_model + 1) % self.models.len();
        self.model = self.models[self.selected_model]
            .trim_start_matches("models/")
            .to_owned();
    }

    pub fn select_previous_model(&mut self) {
        if self.models.is_empty() {
            return;
        }

        self.selected_model = self
            .selected_model
            .checked_sub(1)
            .unwrap_or_else(|| self.models.len() - 1);
        self.model = self.models[self.selected_model]
            .trim_start_matches("models/")
            .to_owned();
    }
}

impl Default for SetupState {
    fn default() -> Self {
        let config = StoredConfig::default();

        Self {
            api_key: config.api_key,
            model: config.model,
            base_url: config.base_url,
            enable_codebase_tools: config.enable_codebase_tools,
            enable_bash_tools: config.enable_bash_tools,
            permission_level: config.permission_level,
            show_thoughts: config.show_thoughts,
            theme: config.theme,
            respect_gitignore: config.respect_gitignore,
            active_field: SetupField::ApiKey,
            models: Vec::new(),
            selected_model: 0,
            is_editing: false,
        }
    }
}