mirror of
https://github.com/martinvonz/jj.git
synced 2025-02-07 21:27:06 +00:00
cli: config: leverage toml_edit::Value to serialize values
I use ValueKind::Ty(ref v) here because (*v).into() looked rather noisy. Fixes #3374
This commit is contained in:
parent
d38c366a98
commit
ef8038f60f
4 changed files with 53 additions and 20 deletions
|
@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
* `jj split` will now refuse to split an empty commit.
|
* `jj split` will now refuse to split an empty commit.
|
||||||
|
|
||||||
|
* `jj config list` now uses multi-line strings and single-quoted strings in the
|
||||||
|
output when appropriate.
|
||||||
|
|
||||||
### Deprecations
|
### Deprecations
|
||||||
|
|
||||||
- Attempting to alias a built-in command now gives a warning, rather than being silently ignored.
|
- Attempting to alias a built-in command now gives a warning, rather than being silently ignored.
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
@ -172,23 +173,29 @@ fn toml_escape_key(key: String) -> String {
|
||||||
toml_edit::Key::from(key).to_string()
|
toml_edit::Key::from(key).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use a proper TOML library to serialize instead.
|
fn to_toml_value(value: &config::Value) -> Result<toml_edit::Value, config::ConfigError> {
|
||||||
fn serialize_config_value(value: &config::Value) -> String {
|
fn type_error<T: fmt::Display>(message: T) -> config::ConfigError {
|
||||||
match &value.kind {
|
config::ConfigError::Message(message.to_string())
|
||||||
config::ValueKind::Table(table) => format!(
|
}
|
||||||
"{{{}}}",
|
// It's unlikely that the config object contained unsupported values, but
|
||||||
// TODO: Remove sorting when config crate maintains deterministic ordering.
|
// there's no guarantee. For example, values coming from environment
|
||||||
table
|
// variables might be big int.
|
||||||
.iter()
|
match value.kind {
|
||||||
.sorted_by_key(|(k, _)| *k)
|
config::ValueKind::Nil => Err(type_error(format!("Unexpected value: {value}"))),
|
||||||
.map(|(k, v)| format!("{k}={}", serialize_config_value(v)))
|
config::ValueKind::Boolean(v) => Ok(v.into()),
|
||||||
.join(", ")
|
config::ValueKind::I64(v) => Ok(v.into()),
|
||||||
),
|
config::ValueKind::I128(v) => Ok(i64::try_from(v).map_err(type_error)?.into()),
|
||||||
config::ValueKind::Array(vals) => {
|
config::ValueKind::U64(v) => Ok(i64::try_from(v).map_err(type_error)?.into()),
|
||||||
format!("[{}]", vals.iter().map(serialize_config_value).join(", "))
|
config::ValueKind::U128(v) => Ok(i64::try_from(v).map_err(type_error)?.into()),
|
||||||
}
|
config::ValueKind::Float(v) => Ok(v.into()),
|
||||||
config::ValueKind::String(val) => format!("{val:?}"),
|
config::ValueKind::String(ref v) => Ok(v.into()),
|
||||||
_ => value.to_string(),
|
// TODO: Remove sorting when config crate maintains deterministic ordering.
|
||||||
|
config::ValueKind::Table(ref table) => table
|
||||||
|
.iter()
|
||||||
|
.sorted_by_key(|(k, _)| *k)
|
||||||
|
.map(|(k, v)| Ok((k, to_toml_value(v)?)))
|
||||||
|
.collect(),
|
||||||
|
config::ValueKind::Array(ref array) => array.iter().map(to_toml_value).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +293,8 @@ fn config_template_language() -> GenericTemplateLanguage<'static, AnnotatedValue
|
||||||
});
|
});
|
||||||
language.add_keyword("value", |self_property| {
|
language.add_keyword("value", |self_property| {
|
||||||
// TODO: would be nice if we can provide raw dynamically-typed value
|
// TODO: would be nice if we can provide raw dynamically-typed value
|
||||||
let out_property = self_property.map(|annotated| serialize_config_value(&annotated.value));
|
let out_property =
|
||||||
|
self_property.and_then(|annotated| Ok(to_toml_value(&annotated.value)?.to_string()));
|
||||||
Ok(L::wrap_string(out_property))
|
Ok(L::wrap_string(out_property))
|
||||||
});
|
});
|
||||||
language.add_keyword("overridden", |self_property| {
|
language.add_keyword("overridden", |self_property| {
|
||||||
|
|
|
@ -334,6 +334,6 @@ fn test_alias_in_repo_config() {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
insta::assert_snapshot!(stdout, @r###"
|
insta::assert_snapshot!(stdout, @r###"
|
||||||
aliases.l=["log", "-r@", "--no-graph", "-T\"user alias\\n\""]
|
aliases.l=["log", "-r@", "--no-graph", '-T"user alias\n"']
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,11 +104,12 @@ fn test_config_list_inline_table() {
|
||||||
x = 1
|
x = 1
|
||||||
[[test-table]]
|
[[test-table]]
|
||||||
y = ["z"]
|
y = ["z"]
|
||||||
|
z."key=with whitespace" = []
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
let stdout = test_env.jj_cmd_success(test_env.env_root(), &["config", "list", "test-table"]);
|
let stdout = test_env.jj_cmd_success(test_env.env_root(), &["config", "list", "test-table"]);
|
||||||
insta::assert_snapshot!(stdout, @r###"
|
insta::assert_snapshot!(stdout, @r###"
|
||||||
test-table=[{x=1}, {y=["z"]}]
|
test-table=[{ x = 1 }, { y = ["z"], z = { "key=with whitespace" = [] } }]
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,6 +137,27 @@ fn test_config_list_all() {
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_config_list_multiline_string() {
|
||||||
|
let test_env = TestEnvironment::default();
|
||||||
|
test_env.add_config(
|
||||||
|
r#"
|
||||||
|
multiline = '''
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
'''
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
let stdout = test_env.jj_cmd_success(test_env.env_root(), &["config", "list", "multiline"]);
|
||||||
|
insta::assert_snapshot!(stdout, @r###"
|
||||||
|
multiline="""
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
"""
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_config_list_layer() {
|
fn test_config_list_layer() {
|
||||||
let mut test_env = TestEnvironment::default();
|
let mut test_env = TestEnvironment::default();
|
||||||
|
|
Loading…
Reference in a new issue