use crate::config::{mask_api_key, NikaConfig};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SettingsField {
#[default]
AnthropicKey,
OpenAiKey,
Provider,
Model,
}
impl SettingsField {
pub fn all() -> &'static [SettingsField] {
&[
SettingsField::AnthropicKey,
SettingsField::OpenAiKey,
SettingsField::Provider,
SettingsField::Model,
]
}
pub fn next(&self) -> SettingsField {
match self {
SettingsField::AnthropicKey => SettingsField::OpenAiKey,
SettingsField::OpenAiKey => SettingsField::Provider,
SettingsField::Provider => SettingsField::Model,
SettingsField::Model => SettingsField::AnthropicKey,
}
}
pub fn prev(&self) -> SettingsField {
match self {
SettingsField::AnthropicKey => SettingsField::Model,
SettingsField::OpenAiKey => SettingsField::AnthropicKey,
SettingsField::Provider => SettingsField::OpenAiKey,
SettingsField::Model => SettingsField::Provider,
}
}
pub fn label(&self) -> &'static str {
match self {
SettingsField::AnthropicKey => "Anthropic API Key",
SettingsField::OpenAiKey => "OpenAI API Key",
SettingsField::Provider => "Default Provider",
SettingsField::Model => "Default Model",
}
}
}
#[derive(Debug, Clone, Default)]
pub struct SettingsState {
pub focus: SettingsField,
pub editing: bool,
pub input_buffer: String,
pub cursor: usize,
pub config: NikaConfig,
pub dirty: bool,
pub status_message: Option<String>,
}
impl SettingsState {
pub fn new(config: NikaConfig) -> Self {
Self {
config,
..Default::default()
}
}
pub fn focus_next(&mut self) {
self.focus = self.focus.next();
self.editing = false;
self.input_buffer.clear();
self.cursor = 0;
}
pub fn focus_prev(&mut self) {
self.focus = self.focus.prev();
self.editing = false;
self.input_buffer.clear();
self.cursor = 0;
}
pub fn start_edit(&mut self) {
self.editing = true;
self.input_buffer = match self.focus {
SettingsField::AnthropicKey => {
self.config.api_keys.anthropic.clone().unwrap_or_default()
}
SettingsField::OpenAiKey => self.config.api_keys.openai.clone().unwrap_or_default(),
SettingsField::Provider => self.config.defaults.provider.clone().unwrap_or_default(),
SettingsField::Model => self.config.defaults.model.clone().unwrap_or_default(),
};
self.cursor = self.input_buffer.len();
}
pub fn cancel_edit(&mut self) {
self.editing = false;
self.input_buffer.clear();
self.cursor = 0;
}
pub fn confirm_edit(&mut self) {
if !self.editing {
return;
}
let value = if self.input_buffer.is_empty() {
None
} else {
Some(self.input_buffer.clone())
};
match self.focus {
SettingsField::AnthropicKey => {
self.config.api_keys.anthropic = value;
}
SettingsField::OpenAiKey => {
self.config.api_keys.openai = value;
}
SettingsField::Provider => {
self.config.defaults.provider = value;
}
SettingsField::Model => {
self.config.defaults.model = value;
}
}
self.dirty = true;
self.editing = false;
self.input_buffer.clear();
self.cursor = 0;
}
pub fn insert_char(&mut self, c: char) {
if !self.editing {
return;
}
self.input_buffer.insert(self.cursor, c);
self.cursor += 1;
}
pub fn backspace(&mut self) {
if !self.editing || self.cursor == 0 {
return;
}
self.cursor -= 1;
self.input_buffer.remove(self.cursor);
}
pub fn delete(&mut self) {
if !self.editing || self.cursor >= self.input_buffer.len() {
return;
}
self.input_buffer.remove(self.cursor);
}
pub fn cursor_left(&mut self) {
if self.cursor > 0 {
self.cursor -= 1;
}
}
pub fn cursor_right(&mut self) {
if self.cursor < self.input_buffer.len() {
self.cursor += 1;
}
}
pub fn cursor_home(&mut self) {
self.cursor = 0;
}
pub fn cursor_end(&mut self) {
self.cursor = self.input_buffer.len();
}
pub fn save(&mut self) -> Result<(), String> {
self.config.save().map_err(|e| e.to_string())?;
self.dirty = false;
self.status_message = Some("Settings saved".to_string());
Ok(())
}
pub fn key_status(&self, field: SettingsField) -> (bool, String) {
match field {
SettingsField::AnthropicKey => {
if let Some(ref key) = self.config.api_keys.anthropic {
(true, mask_api_key(key, 12))
} else {
(false, "Not set".to_string())
}
}
SettingsField::OpenAiKey => {
if let Some(ref key) = self.config.api_keys.openai {
(true, mask_api_key(key, 10))
} else {
(false, "Not set".to_string())
}
}
SettingsField::Provider => {
if let Some(ref provider) = self.config.defaults.provider {
(true, provider.clone())
} else {
let auto = self.config.default_provider().unwrap_or("none");
(false, format!("{} (auto)", auto))
}
}
SettingsField::Model => {
if let Some(ref model) = self.config.defaults.model {
(true, model.clone())
} else {
(false, "Default".to_string())
}
}
}
}
}