mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 09:45:36 +00:00
fix(cli): idx config prints JSON only when JSON is asked for
Auto output stays plain text when piped, as in 0.3.2, so scripts that read $(idx config path) or $(idx config get KEY) keep working; -o json, IDX_OUTPUT=json, or general.output = "json" print JSON. The config goldens return to their 0.3.2 content. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
This commit is contained in:
parent
c8e79b8f7b
commit
57eccc5843
10 changed files with 62 additions and 18 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
use clap::{Args, Subcommand};
|
use clap::{Args, Subcommand};
|
||||||
|
|
||||||
use crate::config::{config_path, ensure_default_config, get_config_value, set_config_value};
|
use crate::config::{config_path, ensure_default_config, get_config_value, set_config_value};
|
||||||
use crate::output::{OutputFormat, json};
|
use crate::output::{OutputSetting, json};
|
||||||
use idx_core::error::IdxError;
|
use idx_core::error::IdxError;
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
|
|
@ -23,10 +23,11 @@ pub enum ConfigSubcommand {
|
||||||
Path,
|
Path,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle(cmd: &ConfigCmd, format: &OutputFormat) -> Result<(), IdxError> {
|
pub fn handle(cmd: &ConfigCmd, setting: OutputSetting) -> Result<(), IdxError> {
|
||||||
// Each result as plain text, or one JSON document with -o json.
|
// Plain text, as scripts read `$(idx config path)`, unless JSON is asked
|
||||||
|
// for (-o json, IDX_OUTPUT, or general.output); auto stays text when piped.
|
||||||
let print = |text: String, document: serde_json::Value| {
|
let print = |text: String, document: serde_json::Value| {
|
||||||
if format.is_json() {
|
if matches!(setting, OutputSetting::Json | OutputSetting::Jsonl) {
|
||||||
json::print_json(&document)
|
json::print_json(&document)
|
||||||
} else {
|
} else {
|
||||||
println!("{}", crate::output::text::terminal_safe(&text));
|
println!("{}", crate::output::text::terminal_safe(&text));
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ use idx_core::error::IdxError;
|
||||||
pub struct IdxConfig {
|
pub struct IdxConfig {
|
||||||
pub core: CoreConfig,
|
pub core: CoreConfig,
|
||||||
pub output: OutputFormat,
|
pub output: OutputFormat,
|
||||||
|
/// The setting `output` came from, before auto was resolved.
|
||||||
|
pub output_setting: OutputSetting,
|
||||||
pub no_color: bool,
|
pub no_color: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,7 +34,7 @@ impl IdxConfig {
|
||||||
pub fn load_with_cli(cli: &Cli) -> Result<Self, IdxError> {
|
pub fn load_with_cli(cli: &Cli) -> Result<Self, IdxError> {
|
||||||
let mut core = CoreConfig::load()?;
|
let mut core = CoreConfig::load()?;
|
||||||
core.verbose = cli.verbose > 0;
|
core.verbose = cli.verbose > 0;
|
||||||
let mut output = OutputSetting::Auto.resolve(stdout_is_terminal());
|
let mut setting = OutputSetting::Auto;
|
||||||
let mut no_color = false;
|
let mut no_color = false;
|
||||||
|
|
||||||
let path = config_path()?;
|
let path = config_path()?;
|
||||||
|
|
@ -41,8 +43,8 @@ impl IdxConfig {
|
||||||
let parsed: FileConfig =
|
let parsed: FileConfig =
|
||||||
toml::from_str(&raw).map_err(|e| IdxError::ConfigError(e.to_string()))?;
|
toml::from_str(&raw).map_err(|e| IdxError::ConfigError(e.to_string()))?;
|
||||||
if let Some(general) = parsed.general {
|
if let Some(general) = parsed.general {
|
||||||
if let Some(setting) = general.output {
|
if let Some(file_setting) = general.output {
|
||||||
output = setting.resolve(stdout_is_terminal());
|
setting = file_setting;
|
||||||
}
|
}
|
||||||
if let Some(color) = general.color {
|
if let Some(color) = general.color {
|
||||||
no_color = !color;
|
no_color = !color;
|
||||||
|
|
@ -51,25 +53,25 @@ impl IdxConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(value) = std::env::var("IDX_OUTPUT") {
|
if let Ok(value) = std::env::var("IDX_OUTPUT") {
|
||||||
let setting = OutputSetting::parse(&value).ok_or_else(|| {
|
setting = OutputSetting::parse(&value).ok_or_else(|| {
|
||||||
IdxError::ConfigError(format!(
|
IdxError::ConfigError(format!(
|
||||||
"invalid IDX_OUTPUT value: '{value}', expected 'auto', 'table', 'json', or 'jsonl'"
|
"invalid IDX_OUTPUT value: '{value}', expected 'auto', 'table', 'json', or 'jsonl'"
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
output = setting.resolve(stdout_is_terminal());
|
|
||||||
}
|
}
|
||||||
if let Ok(value) = std::env::var("IDX_NO_COLOR") {
|
if let Ok(value) = std::env::var("IDX_NO_COLOR") {
|
||||||
no_color = value == "1" || value.eq_ignore_ascii_case("true");
|
no_color = value == "1" || value.eq_ignore_ascii_case("true");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(setting) = cli.output {
|
if let Some(cli_setting) = cli.output {
|
||||||
output = setting.resolve(stdout_is_terminal());
|
setting = cli_setting;
|
||||||
}
|
}
|
||||||
no_color = no_color || cli.no_color || !stdout_is_terminal();
|
no_color = no_color || cli.no_color || !stdout_is_terminal();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
core,
|
core,
|
||||||
output,
|
output: setting.resolve(stdout_is_terminal()),
|
||||||
|
output_setting: setting,
|
||||||
no_color,
|
no_color,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ fn run() -> Result<(), IdxError> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Commands::Config(cfg) => {
|
Commands::Config(cfg) => {
|
||||||
if let Err(err) = cli::config::handle(cfg, &config.output) {
|
if let Err(err) = cli::config::handle(cfg, config.output_setting) {
|
||||||
emit_error(&err, &config.output);
|
emit_error(&err, &config.output);
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -980,6 +980,43 @@ fn config_set_and_get_provider_round_trip() {
|
||||||
.stdout(predicate::str::contains("msn"));
|
.stdout(predicate::str::contains("msn"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn config_prints_json_only_when_json_is_asked_for() {
|
||||||
|
// Piped with auto output, scripts read plain text: `$(idx config path)`.
|
||||||
|
let root = test_env_dir("config-output-format");
|
||||||
|
bin_with_root(&root)
|
||||||
|
.args(["config", "set", "general.provider", "msn"])
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stdout("ok\n");
|
||||||
|
bin_with_root(&root)
|
||||||
|
.args(["config", "get", "general.provider"])
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stdout("msn\n");
|
||||||
|
|
||||||
|
let flag = run_success_json(bin_with_root(&root).args([
|
||||||
|
"-o",
|
||||||
|
"json",
|
||||||
|
"config",
|
||||||
|
"get",
|
||||||
|
"general.provider",
|
||||||
|
]));
|
||||||
|
assert_eq!(
|
||||||
|
flag,
|
||||||
|
serde_json::json!({"key": "general.provider", "value": "msn"})
|
||||||
|
);
|
||||||
|
let env = run_success_json(
|
||||||
|
bin_with_root(&root)
|
||||||
|
.env("IDX_OUTPUT", "json")
|
||||||
|
.args(["config", "path"]),
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
env["path"].as_str().unwrap().ends_with("config.toml"),
|
||||||
|
"{env}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn config_set_and_get_ownership_db_path_round_trip() {
|
fn config_set_and_get_ownership_db_path_round_trip() {
|
||||||
let root = test_env_dir("config-ownership-db-path");
|
let root = test_env_dir("config-ownership-db-path");
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
exit: 0
|
exit: 0
|
||||||
--- stdout
|
--- stdout
|
||||||
{"key":"general.provider","value":"msn"}
|
msn
|
||||||
--- stderr
|
--- stderr
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
exit: 0
|
exit: 0
|
||||||
--- stdout
|
--- stdout
|
||||||
{"path":"<ROOT>/config/idx/config.toml"}
|
<ROOT>/config/idx/config.toml
|
||||||
--- stderr
|
--- stderr
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
exit: 0
|
exit: 0
|
||||||
--- stdout
|
--- stdout
|
||||||
{"path":"<ROOT>/config/idx/config.toml"}
|
<ROOT>/config/idx/config.toml
|
||||||
--- stderr
|
--- stderr
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
exit: 0
|
exit: 0
|
||||||
--- stdout
|
--- stdout
|
||||||
{"key":"general.output","ok":true,"value":"jsonl"}
|
ok
|
||||||
--- stderr
|
--- stderr
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
exit: 0
|
exit: 0
|
||||||
--- stdout
|
--- stdout
|
||||||
{"key":"general.provider","ok":true,"value":"yahoo"}
|
ok
|
||||||
--- stderr
|
--- stderr
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ idx config get cache.quote_ttl
|
||||||
idx config path
|
idx config path
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`idx config` prints plain text, even when piped, so `$(idx config path)` works
|
||||||
|
in scripts. Ask for JSON with `-o json`, `IDX_OUTPUT=json`, or
|
||||||
|
`output = "json"`.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[general]
|
[general]
|
||||||
provider = "msn" # msn | yahoo
|
provider = "msn" # msn | yahoo
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue