vtcode 0.99.1

A Rust-based terminal coding agent with modular architecture supporting multiple LLM providers
use std::fs;
use std::path::{Path, PathBuf};

use anyhow::{Context, Result};
use toml::Value as TomlValue;
use vtcode_core::config::loader::ConfigManager;
use vtcode_core::config::loader::layers::ConfigLayerSource;

pub(super) fn ensure_child_table<'a>(
    table: &'a mut toml::map::Map<String, TomlValue>,
    key: &str,
) -> &'a mut toml::map::Map<String, TomlValue> {
    let entry = table
        .entry(key.to_string())
        .or_insert_with(|| TomlValue::Table(Default::default()));
    if !entry.is_table() {
        *entry = TomlValue::Table(Default::default());
    }
    entry
        .as_table_mut()
        .expect("table entry should be a table after initialization")
}

pub(super) fn load_toml_value(path: &Path) -> Result<TomlValue> {
    if !path.exists() {
        return Ok(TomlValue::Table(Default::default()));
    }

    let content =
        fs::read_to_string(path).with_context(|| format!("Failed to read {}", path.display()))?;
    if content.trim().is_empty() {
        return Ok(TomlValue::Table(Default::default()));
    }

    toml::from_str::<TomlValue>(&content)
        .with_context(|| format!("Failed to parse {}", path.display()))
}

pub(super) fn save_toml_value(path: &Path, root: &TomlValue) -> Result<()> {
    let is_empty = root.as_table().is_some_and(|table| table.is_empty());
    if is_empty {
        if path.exists() {
            fs::remove_file(path)
                .with_context(|| format!("Failed to remove {}", path.display()))?;
        }
        return Ok(());
    }

    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent)
            .with_context(|| format!("Failed to create {}", parent.display()))?;
    }
    fs::write(path, toml::to_string_pretty(root)?)
        .with_context(|| format!("Failed to write {}", path.display()))
}

pub(super) fn preferred_workspace_config_path(
    manager: &ConfigManager,
    workspace: &Path,
) -> PathBuf {
    manager
        .layer_stack()
        .layers()
        .iter()
        .rev()
        .find_map(|layer| match &layer.source {
            ConfigLayerSource::Workspace { file } if layer.is_enabled() => Some(file.clone()),
            _ => None,
        })
        .unwrap_or_else(|| workspace.join(manager.config_file_name()))
}