diff --git a/CHANGELOG.md b/CHANGELOG.md index 6971ae28c4e..ec5b618593a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). * The `CryptographicSignature.key()` template method now also works for SSH signatures and returns the corresponding public key fingerprint. +* Templates now support an `is_terminal_output()` function that returns true if + stdout is connected to a terminal. + ### Fixed bugs * `jj metaedit --author-timestamp` twice with the same value no longer diff --git a/cli/src/template_builder.rs b/cli/src/template_builder.rs index 72c37f3db59..1c184bc4524 100644 --- a/cli/src/template_builder.rs +++ b/cli/src/template_builder.rs @@ -15,6 +15,7 @@ use std::cmp::Ordering; use std::collections::HashMap; use std::io; +use std::io::IsTerminal as _; use std::iter; use itertools::Itertools as _; @@ -1939,6 +1940,14 @@ fn builtin_functions<'a, L: TemplateLanguage<'a> + ?Sized>() -> TemplateBuildFun // .decorated("", "") to trim leading/trailing whitespace Ok(Literal(value.decorated("", "")).into_dyn_wrapped()) }); + map.insert( + "is_terminal_output", + |_language, _diagnostics, _build_ctx, function| { + function.expect_no_arguments()?; + let is_terminal = io::stdout().is_terminal(); + Ok(Literal(is_terminal).into_dyn_wrapped()) + }, + ); map } @@ -3874,4 +3883,12 @@ mod tests { env.render_ok(r#"surround(lt, gt, if(empty_content, "not empty", ""))"#), @""); } + + #[test] + fn test_is_terminal_output_function() { + let env = TestTemplateEnv::new(); + + // When running tests, stdout is typically not a terminal, so we expect false + insta::assert_snapshot!(env.render_ok(r#"is_terminal_output()"#), @"false"); + } } diff --git a/docs/templates.md b/docs/templates.md index dfe3e2cd22c..5d71b376aad 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -93,6 +93,10 @@ The following functions are defined. * `surround(prefix: Template, suffix: Template, content: Template) -> Template`: Surround **non-empty** content with texts such as parentheses. * `config(name: String) -> ConfigValue`: Look up configuration value by `name`. +* `is_terminal_output() -> Boolean`: Returns true if stdout is connected to a + terminal, or false otherwise. This is mostly useful to conditionally output + escape codes or other terminal-specific formatting only when writing to + a terminal. ## Built-in Aliases