vtcode_config/loader/
layers.rs

1use crate::loader::merge_toml_values;
2use serde::{Deserialize, Serialize};
3use std::path::PathBuf;
4use toml::Value as TomlValue;
5
6/// Source of a configuration layer.
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub enum ConfigLayerSource {
9    /// System-wide configuration (e.g., /etc/vtcode/vtcode.toml)
10    System { file: PathBuf },
11    /// User-specific configuration (e.g., ~/.vtcode/vtcode.toml)
12    User { file: PathBuf },
13    /// Project-specific configuration (e.g., .vtcode/projects/foo/config/vtcode.toml)
14    Project { file: PathBuf },
15    /// Workspace-specific configuration (e.g., vtcode.toml in workspace root)
16    Workspace { file: PathBuf },
17    /// Runtime overrides (e.g., CLI flags)
18    Runtime,
19}
20
21/// A single layer of configuration.
22#[derive(Debug, Clone, PartialEq)]
23pub struct ConfigLayerEntry {
24    /// Source of this layer
25    pub source: ConfigLayerSource,
26    /// Parsed TOML content
27    pub config: TomlValue,
28}
29
30impl ConfigLayerEntry {
31    /// Create a new configuration layer entry.
32    pub fn new(source: ConfigLayerSource, config: TomlValue) -> Self {
33        Self { source, config }
34    }
35}
36
37/// A stack of configuration layers, ordered from lowest to highest precedence.
38#[derive(Debug, Clone, Default)]
39pub struct ConfigLayerStack {
40    layers: Vec<ConfigLayerEntry>,
41}
42
43impl ConfigLayerStack {
44    /// Create a new configuration layer stack.
45    pub fn new(layers: Vec<ConfigLayerEntry>) -> Self {
46        Self { layers }
47    }
48
49    /// Add a layer to the stack.
50    pub fn push(&mut self, layer: ConfigLayerEntry) {
51        self.layers.push(layer);
52    }
53
54    /// Merge all layers into a single effective configuration.
55    pub fn effective_config(&self) -> TomlValue {
56        let mut merged = TomlValue::Table(toml::Table::new());
57        for layer in &self.layers {
58            merge_toml_values(&mut merged, &layer.config);
59        }
60        merged
61    }
62
63    /// Get all layers in the stack.
64    pub fn layers(&self) -> &[ConfigLayerEntry] {
65        &self.layers
66    }
67}