diff --git a/CHANGELOG.md b/CHANGELOG.md index 20d5ab4f22..988c7f55b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Templates now support logical operators: `||`, `&&`, `!` +* Templates now support the `self` keyword, which is the current commit in `jj + log`/`obslog` templates. + * `jj show` now accepts `-T`/`--template` option to render its output using template diff --git a/cli/src/template_builder.rs b/cli/src/template_builder.rs index 8bf8d46339..136c273ba1 100644 --- a/cli/src/template_builder.rs +++ b/cli/src/template_builder.rs @@ -866,6 +866,9 @@ pub fn build_expression<'a, L: TemplateLanguage<'a>>( if let Some(make) = build_ctx.local_variables.get(name) { // Don't label a local variable with its name Ok(Expression::unlabeled(make())) + } else if *name == "self" { + // "self" is a special variable, so don't label it + Ok(Expression::unlabeled(language.build_self())) } else { build_keyword(language, build_ctx, name, node.span) } @@ -1315,6 +1318,24 @@ mod tests { "###); } + #[test] + fn test_self_keyword() { + let mut env = TestTemplateEnv::default(); + env.add_keyword("say_hello", |language| { + language.wrap_string(Literal("Hello".to_owned())) + }); + + insta::assert_snapshot!(env.render_ok(r#"self.say_hello()"#), @"Hello"); + insta::assert_snapshot!(env.parse_err(r#"self"#), @r###" + --> 1:1 + | + 1 | self + | ^--^ + | + = Expected expression of type "Template" + "###); + } + #[test] fn test_boolean_cast() { let mut env = TestTemplateEnv::default(); diff --git a/docs/templates.md b/docs/templates.md index dc37115f9d..0825fc03a0 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -9,48 +9,20 @@ A couple of `jj` commands accept a template via `-T`/`--template` option. ## Keywords Keywords represent objects of different types; the types are described in -a follow-up section. +a follow-up section. In addition to context-specific keywords, the top-level +object can be referenced as `self`. ### Commit keywords -The following keywords can be used in `jj log`/`jj obslog` templates. - -* `description: String` -* `change_id: ChangeId` -* `commit_id: CommitId` -* `parents: List` -* `author: Signature` -* `committer: Signature` -* `working_copies: String`: For multi-workspace repository, indicate - working-copy commit as `@`. -* `current_working_copy: Boolean`: True for the working-copy commit of the - current workspace. -* `branches: List`: Local and remote branches pointing to the commit. - A tracking remote branch will be included only if its target is different - from the local one. -* `local_branches: List`: All local branches pointing to the commit. -* `remote_branches: List`: All remote branches pointing to the commit. -* `tags: List` -* `git_refs: List` -* `git_head: List` -* `divergent: Boolean`: True if the commit's change id corresponds to multiple - visible commits. -* `hidden: Boolean`: True if the commit is not visible (a.k.a. abandoned). -* `conflict: Boolean`: True if the commit contains merge conflicts. -* `empty: Boolean`: True if the commit modifies no files. -* `root: Boolean`: True if the commit is the root commit. +In `jj log`/`jj obslog` templates, all 0-argument methods of [the `Commit` +type](#commit-type) are available as keywords. For example, `commit_id` is +equivalent to `self.commit_id()`. ### Operation keywords -The following keywords can be used in `jj op log` templates. - -* `current_operation: Boolean` -* `description: String` -* `id: OperationId` -* `tags: String` -* `time: TimestampRange` -* `user: String` -* `root: Boolean`: True if the commit is the root commit. +In `jj op log` templates, all 0-argument methods of [the `Operation` +type](#operation-type) are available as keywords. For example, +`current_operation` is equivalent to `self.current_operation()`. ## Operators @@ -90,8 +62,32 @@ No methods are defined. Can be constructed with `false` or `true` literal. ### Commit type -This type cannot be printed. All commit keywords are accessible as 0-argument -methods. +This type cannot be printed. The following methods are defined. + +* `description() -> String` +* `change_id() -> ChangeId` +* `commit_id() -> CommitId` +* `parents() -> List` +* `author() -> Signature` +* `committer() -> Signature` +* `working_copies() -> String`: For multi-workspace repository, indicate + working-copy commit as `@`. +* `current_working_copy() -> Boolean`: True for the working-copy commit of the + current workspace. +* `branches() -> List`: Local and remote branches pointing to the commit. + A tracking remote branch will be included only if its target is different + from the local one. +* `local_branches() -> List`: All local branches pointing to the commit. +* `remote_branches() -> List`: All remote branches pointing to the commit. +* `tags() -> List` +* `git_refs() -> List` +* `git_head() -> List` +* `divergent() -> Boolean`: True if the commit's change id corresponds to multiple + visible commits. +* `hidden() -> Boolean`: True if the commit is not visible (a.k.a. abandoned). +* `conflict() -> Boolean`: True if the commit contains merge conflicts. +* `empty() -> Boolean`: True if the commit modifies no files. +* `root() -> Boolean`: True if the commit is the root commit. ### CommitId / ChangeId type @@ -122,8 +118,15 @@ The following methods are defined. See also the `List` type. ### Operation type -This type cannot be printed. All operation keywords are accessible as 0-argument -methods. +This type cannot be printed. The following methods are defined. + +* `current_operation() -> Boolean` +* `description() -> String` +* `id() -> OperationId` +* `tags() -> String` +* `time() -> TimestampRange` +* `user() -> String` +* `root() -> Boolean`: True if the commit is the root commit. ### OperationId type