Skip to content

Commit 17ff13e

Browse files
committed
Update config API and add dependencies
1 parent a261981 commit 17ff13e

File tree

7 files changed

+152
-20
lines changed

7 files changed

+152
-20
lines changed

Cargo.lock

Lines changed: 13 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ tera = { version = "1.17.1", default-features = false }
3838
tiktoken-rs = "0.1.2"
3939
tokio = { version = "1.25.0", features = ["full"] }
4040
toml = "0.7.2"
41+
toml_edit = "0.19.4"
4142
which = "4.4.0"
4243

4344
[dev-dependencies]

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ Configs are applied in the following order:
5151
- The settings as read from the repo clone at `$GIT_ROOT/.git/gptcommit.toml`.
5252
- Environment variables starting with `GPTCOMMIT__*`.
5353

54+
See all the config options available with `gptcommit config keys`.
55+
5456
### Set your OpenAI API key
5557

5658
Persist your OpenAI key
@@ -139,7 +141,6 @@ All of these awesome projects are built using `gptcommit`.
139141

140142
If you encounter any bugs or have any suggestions for improvements, please open an issue on the repository.
141143

142-
143144
## License
144145

145146
This project is licensed under the [MIT License](./LICENSE).

e2e/test_config_list_get_set.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ set -eu
33

44
gptcommit config list
55
# assert is valid TOML
6+
gptcommit config keys
67

78
gptcommit config get openai.model
89
# assert default = text-davinci-003

src/actions/config.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
use std::{collections::VecDeque, fs, path::PathBuf};
22

3-
use async_std::path::Path;
43
use clap::{Args, Subcommand};
54
use toml::Value;
65

7-
use crate::settings::{get_local_config_path, get_user_config_path, Settings};
6+
use crate::{
7+
settings::{get_local_config_path, get_user_config_path, Settings},
8+
toml::DeepKeysCollector,
9+
};
810
use anyhow::{bail, Result};
911

1012
#[derive(Subcommand, Debug)]
1113
pub(crate) enum ConfigAction {
14+
/// List all config keys
15+
Keys,
1216
/// List all config values
1317
List {
1418
/// if set, will save the config to the user's config file
@@ -44,6 +48,7 @@ pub(crate) async fn main(settings: Settings, args: ConfigArgs) -> Result<()> {
4448
debug!("Config subcommand - Settings = {:?}", settings);
4549

4650
match args.action {
51+
ConfigAction::Keys => keys(settings).await,
4752
ConfigAction::List { save } => list(settings, save).await,
4853
ConfigAction::Get { key } => get(settings, key).await,
4954
ConfigAction::Set { key, value, local } => set(settings, key, value, local).await,
@@ -58,13 +63,20 @@ fn get_config_path(local: bool) -> Result<PathBuf> {
5863
} else {
5964
bail!("No repo-local config found. Please run `git init` to create a repo first");
6065
}
66+
} else if let Some(config_path) = get_user_config_path() {
67+
Ok(config_path)
6168
} else {
62-
if let Some(config_path) = get_user_config_path() {
63-
Ok(config_path)
64-
} else {
65-
bail!("No user config found.");
66-
}
69+
bail!("No user config found.");
70+
}
71+
}
72+
73+
async fn keys(settings: Settings) -> Result<()> {
74+
let toml_string = toml::to_string_pretty(&settings).unwrap();
75+
let keys = DeepKeysCollector::get_keys(toml_string);
76+
for key in keys {
77+
println!("{key}");
6778
}
79+
Ok(())
6880
}
6981

7082
async fn delete(_settings: Settings, full_key: String, local: bool) -> Result<()> {

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod cmd;
88
mod git;
99
mod prompt;
1010
mod summarize;
11+
mod toml;
1112
mod util;
1213

1314
use anyhow::Result;

src/toml.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use toml_edit::{visit::*, Document, Item, Value};
2+
3+
#[derive(Default)]
4+
pub(crate) struct DeepKeysCollector<'doc> {
5+
current_path: Vec<&'doc str>,
6+
pub keys: Vec<String>,
7+
}
8+
9+
impl DeepKeysCollector<'_> {
10+
pub fn get_keys(toml_string: String) -> Vec<String> {
11+
let document: Document = toml_string.parse().unwrap();
12+
let mut visitor = DeepKeysCollector::default();
13+
visitor.visit_document(&document);
14+
15+
visitor.keys.sort();
16+
visitor.keys
17+
}
18+
}
19+
20+
impl<'doc> Visit<'doc> for DeepKeysCollector<'doc> {
21+
fn visit_table_like_kv(&mut self, key: &'doc str, node: &'doc Item) {
22+
self.current_path.push(key);
23+
self.visit_item(node);
24+
self.current_path.pop();
25+
}
26+
27+
fn visit_value(&mut self, node: &'doc Value) {
28+
match node {
29+
Value::InlineTable(_table) => {}
30+
_ => {
31+
self.keys.push(self.current_path.join("."));
32+
}
33+
};
34+
35+
match node {
36+
Value::String(s) => self.visit_string(s),
37+
Value::Integer(i) => self.visit_integer(i),
38+
Value::Float(f) => self.visit_float(f),
39+
Value::Boolean(b) => self.visit_boolean(b),
40+
Value::Datetime(dt) => self.visit_datetime(dt),
41+
Value::Array(array) => self.visit_array(array),
42+
Value::InlineTable(table) => self.visit_inline_table(table),
43+
}
44+
}
45+
}
46+
47+
#[cfg(test)]
48+
mod tests {
49+
use toml_edit::Document;
50+
51+
use crate::settings::Settings;
52+
53+
use super::*;
54+
55+
#[test]
56+
fn test_basic() {
57+
let input = r#"
58+
laputa = "sky-castle"
59+
the-force = { value = "surrounds-you" }
60+
"#;
61+
62+
let document: Document = input.parse().unwrap();
63+
let mut visitor = DeepKeysCollector::default();
64+
visitor.visit_document(&document);
65+
66+
assert_eq!(visitor.current_path, Vec::<&str>::new());
67+
assert_eq!(visitor.keys, vec!["laputa", "the-force.value"]);
68+
}
69+
70+
#[test]
71+
fn test_default_config() {
72+
let input = toml::to_string_pretty(&Settings::new().unwrap()).unwrap();
73+
74+
let document: Document = input.parse().unwrap();
75+
let mut visitor = DeepKeysCollector::default();
76+
visitor.visit_document(&document);
77+
78+
assert_eq!(visitor.current_path, Vec::<&str>::new());
79+
visitor.keys.sort();
80+
assert_eq!(
81+
visitor.keys,
82+
vec![
83+
"allow_amend",
84+
"model_provider",
85+
"openai.api_key",
86+
"openai.model",
87+
"output.lang",
88+
"prompt.commit_summary",
89+
"prompt.commit_title",
90+
"prompt.file_diff",
91+
"prompt.translation",
92+
]
93+
);
94+
}
95+
96+
#[test]
97+
fn test_get_keys() {
98+
let input = toml::to_string_pretty(&Settings::new().unwrap()).unwrap();
99+
100+
assert_eq!(
101+
DeepKeysCollector::get_keys(input),
102+
vec![
103+
"allow_amend",
104+
"model_provider",
105+
"openai.api_key",
106+
"openai.model",
107+
"output.lang",
108+
"prompt.commit_summary",
109+
"prompt.commit_title",
110+
"prompt.file_diff",
111+
"prompt.translation",
112+
]
113+
);
114+
}
115+
}

0 commit comments

Comments
 (0)