mirror of
https://github.com/martinvonz/jj.git
synced 2025-02-01 00:50:57 +00:00
Make node symbols templatable in the graphs.
Adds config options * templates.log_graph_node * templates.log_graph_node_elided * templates.op_log_graph_node
This commit is contained in:
parent
9b1a8e2480
commit
e2eb5bddf9
11 changed files with 188 additions and 73 deletions
|
@ -20,7 +20,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
* `ui.default-command` now accepts multiple string arguments, for more complex
|
* `ui.default-command` now accepts multiple string arguments, for more complex
|
||||||
default `jj` commands.
|
default `jj` commands.
|
||||||
|
|
||||||
* Graph node symbols are now configurable via `ui.graph.default_node` and `ui.graph.elided_node`.
|
* Graph node symbols are now configurable via templates
|
||||||
|
* `templates.log_node`
|
||||||
|
* `templates.op_log_node`
|
||||||
|
* `templates.log_node_elided`
|
||||||
|
|
||||||
|
|
||||||
* `jj log` now includes synthetic nodes in the graph where some revisions were
|
* `jj log` now includes synthetic nodes in the graph where some revisions were
|
||||||
elided.
|
elided.
|
||||||
|
|
|
@ -904,14 +904,19 @@ Set which revision the branch points to with `jj branch set {branch_name} -r <RE
|
||||||
&self,
|
&self,
|
||||||
template_text: &str,
|
template_text: &str,
|
||||||
) -> Result<Box<dyn Template<Commit> + '_>, CommandError> {
|
) -> Result<Box<dyn Template<Commit> + '_>, CommandError> {
|
||||||
let language = CommitTemplateLanguage::new(
|
let language = self.commit_template_language()?;
|
||||||
|
self.parse_template(&language, template_text)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates commit template language environment for this workspace.
|
||||||
|
pub fn commit_template_language(&self) -> Result<CommitTemplateLanguage<'_>, CommandError> {
|
||||||
|
Ok(CommitTemplateLanguage::new(
|
||||||
self.repo().as_ref(),
|
self.repo().as_ref(),
|
||||||
self.workspace_id(),
|
self.workspace_id(),
|
||||||
self.revset_parse_context(),
|
self.revset_parse_context(),
|
||||||
self.id_prefix_context()?,
|
self.id_prefix_context()?,
|
||||||
self.commit_template_extension.as_deref(),
|
self.commit_template_extension.as_deref(),
|
||||||
);
|
))
|
||||||
self.parse_template(&language, template_text)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Template for one-line summary of a commit.
|
/// Template for one-line summary of a commit.
|
||||||
|
@ -2309,6 +2314,14 @@ pub fn parse_args(
|
||||||
Ok((matches, args))
|
Ok((matches, args))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn format_template<T>(ui: &Ui, arg: &T, template: &dyn Template<T>) -> String {
|
||||||
|
let mut output = vec![];
|
||||||
|
template
|
||||||
|
.format(arg, ui.new_formatter(&mut output).as_mut())
|
||||||
|
.expect("write() to vec backed formatter should never fail");
|
||||||
|
String::from_utf8(output).expect("template output should be utf-8 bytes")
|
||||||
|
}
|
||||||
|
|
||||||
/// CLI command builder and runner.
|
/// CLI command builder and runner.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct CliRunner {
|
pub struct CliRunner {
|
||||||
|
|
|
@ -21,10 +21,12 @@ use jj_lib::revset_graph::{
|
||||||
};
|
};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use crate::cli_util::{CommandHelper, LogContentFormat, RevisionArg};
|
use crate::cli_util::{format_template, CommandHelper, LogContentFormat, RevisionArg};
|
||||||
use crate::command_error::CommandError;
|
use crate::command_error::CommandError;
|
||||||
use crate::diff_util::{self, DiffFormatArgs};
|
use crate::diff_util::{self, DiffFormatArgs};
|
||||||
|
use crate::generic_templater::GenericTemplateLanguage;
|
||||||
use crate::graphlog::{get_graphlog, Edge};
|
use crate::graphlog::{get_graphlog, Edge};
|
||||||
|
use crate::templater::Template;
|
||||||
use crate::ui::Ui;
|
use crate::ui::Ui;
|
||||||
|
|
||||||
/// Show revision history
|
/// Show revision history
|
||||||
|
@ -94,7 +96,6 @@ pub(crate) fn cmd_log(
|
||||||
expression
|
expression
|
||||||
};
|
};
|
||||||
let repo = workspace_command.repo();
|
let repo = workspace_command.repo();
|
||||||
let wc_commit_id = workspace_command.get_wc_commit_id();
|
|
||||||
let matcher = workspace_command.matcher_from_values(&args.paths)?;
|
let matcher = workspace_command.matcher_from_values(&args.paths)?;
|
||||||
let revset = workspace_command.evaluate_revset(revset_expression)?;
|
let revset = workspace_command.evaluate_revset(revset_expression)?;
|
||||||
|
|
||||||
|
@ -102,17 +103,30 @@ pub(crate) fn cmd_log(
|
||||||
let diff_formats =
|
let diff_formats =
|
||||||
diff_util::diff_formats_for_log(command.settings(), &args.diff_format, args.patch)?;
|
diff_util::diff_formats_for_log(command.settings(), &args.diff_format, args.patch)?;
|
||||||
|
|
||||||
let template_string = match &args.template {
|
|
||||||
Some(value) => value.to_string(),
|
|
||||||
None => command.settings().config().get_string("templates.log")?,
|
|
||||||
};
|
|
||||||
let use_elided_nodes = command
|
let use_elided_nodes = command
|
||||||
.settings()
|
.settings()
|
||||||
.config()
|
.config()
|
||||||
.get_bool("ui.log-synthetic-elided-nodes")?;
|
.get_bool("ui.log-synthetic-elided-nodes")?;
|
||||||
let template = workspace_command.parse_commit_template(&template_string)?;
|
|
||||||
let with_content_format = LogContentFormat::new(ui, command.settings())?;
|
let with_content_format = LogContentFormat::new(ui, command.settings())?;
|
||||||
|
|
||||||
|
let template;
|
||||||
|
let commit_node_template;
|
||||||
|
{
|
||||||
|
let language = workspace_command.commit_template_language()?;
|
||||||
|
let template_string = match &args.template {
|
||||||
|
Some(value) => value.to_string(),
|
||||||
|
None => command.settings().config().get_string("templates.log")?,
|
||||||
|
};
|
||||||
|
template = workspace_command.parse_template(&language, &template_string)?;
|
||||||
|
commit_node_template = workspace_command
|
||||||
|
.parse_template(&language, &command.settings().commit_node_template())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let elided_node_template = workspace_command.parse_template(
|
||||||
|
&GenericTemplateLanguage::new(),
|
||||||
|
&command.settings().elided_node_template(),
|
||||||
|
)?;
|
||||||
|
|
||||||
{
|
{
|
||||||
ui.request_pager();
|
ui.request_pager();
|
||||||
let mut formatter = ui.stdout_formatter();
|
let mut formatter = ui.stdout_formatter();
|
||||||
|
@ -120,8 +134,6 @@ pub(crate) fn cmd_log(
|
||||||
|
|
||||||
if !args.no_graph {
|
if !args.no_graph {
|
||||||
let mut graph = get_graphlog(command.settings(), formatter.raw());
|
let mut graph = get_graphlog(command.settings(), formatter.raw());
|
||||||
let default_node_symbol = command.settings().default_node_symbol();
|
|
||||||
let elided_node_symbol = command.settings().elided_node_symbol();
|
|
||||||
let forward_iter = TopoGroupedRevsetGraphIterator::new(revset.iter_graph());
|
let forward_iter = TopoGroupedRevsetGraphIterator::new(revset.iter_graph());
|
||||||
let iter: Box<dyn Iterator<Item = _>> = if args.reversed {
|
let iter: Box<dyn Iterator<Item = _>> = if args.reversed {
|
||||||
Box::new(ReverseRevsetGraphIterator::new(forward_iter))
|
Box::new(ReverseRevsetGraphIterator::new(forward_iter))
|
||||||
|
@ -179,16 +191,12 @@ pub(crate) fn cmd_log(
|
||||||
&diff_formats,
|
&diff_formats,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
let node_symbol = if Some(&key.0) == wc_commit_id {
|
|
||||||
"@"
|
|
||||||
} else {
|
|
||||||
&default_node_symbol
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let node_symbol = format_template(ui, &commit, commit_node_template.as_ref());
|
||||||
graph.add_node(
|
graph.add_node(
|
||||||
&key,
|
&key,
|
||||||
&graphlog_edges,
|
&graphlog_edges,
|
||||||
node_symbol,
|
&node_symbol,
|
||||||
&String::from_utf8_lossy(&buffer),
|
&String::from_utf8_lossy(&buffer),
|
||||||
)?;
|
)?;
|
||||||
for elided_target in elided_targets {
|
for elided_target in elided_targets {
|
||||||
|
@ -201,10 +209,11 @@ pub(crate) fn cmd_log(
|
||||||
|formatter| writeln!(formatter.labeled("elided"), "(elided revisions)"),
|
|formatter| writeln!(formatter.labeled("elided"), "(elided revisions)"),
|
||||||
|| graph.width(&elided_key, &edges),
|
|| graph.width(&elided_key, &edges),
|
||||||
)?;
|
)?;
|
||||||
|
let node_symbol = format_template(ui, &(), elided_node_template.as_ref());
|
||||||
graph.add_node(
|
graph.add_node(
|
||||||
&elided_key,
|
&elided_key,
|
||||||
&edges,
|
&edges,
|
||||||
&elided_node_symbol,
|
&node_symbol,
|
||||||
&String::from_utf8_lossy(&buffer),
|
&String::from_utf8_lossy(&buffer),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,9 @@ use jj_lib::matchers::EverythingMatcher;
|
||||||
use jj_lib::rewrite::rebase_to_dest_parent;
|
use jj_lib::rewrite::rebase_to_dest_parent;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use crate::cli_util::{CommandHelper, LogContentFormat, RevisionArg, WorkspaceCommandHelper};
|
use crate::cli_util::{
|
||||||
|
format_template, CommandHelper, LogContentFormat, RevisionArg, WorkspaceCommandHelper,
|
||||||
|
};
|
||||||
use crate::command_error::CommandError;
|
use crate::command_error::CommandError;
|
||||||
use crate::diff_util::{self, DiffFormat, DiffFormatArgs};
|
use crate::diff_util::{self, DiffFormat, DiffFormatArgs};
|
||||||
use crate::formatter::Formatter;
|
use crate::formatter::Formatter;
|
||||||
|
@ -63,17 +65,23 @@ pub(crate) fn cmd_obslog(
|
||||||
let workspace_command = command.workspace_helper(ui)?;
|
let workspace_command = command.workspace_helper(ui)?;
|
||||||
|
|
||||||
let start_commit = workspace_command.resolve_single_rev(&args.revision)?;
|
let start_commit = workspace_command.resolve_single_rev(&args.revision)?;
|
||||||
let wc_commit_id = workspace_command.get_wc_commit_id();
|
|
||||||
|
|
||||||
let diff_formats =
|
let diff_formats =
|
||||||
diff_util::diff_formats_for_log(command.settings(), &args.diff_format, args.patch)?;
|
diff_util::diff_formats_for_log(command.settings(), &args.diff_format, args.patch)?;
|
||||||
|
let with_content_format = LogContentFormat::new(ui, command.settings())?;
|
||||||
|
|
||||||
|
let template;
|
||||||
|
let commit_node_template;
|
||||||
|
{
|
||||||
|
let language = workspace_command.commit_template_language()?;
|
||||||
let template_string = match &args.template {
|
let template_string = match &args.template {
|
||||||
Some(value) => value.to_string(),
|
Some(value) => value.to_string(),
|
||||||
None => command.settings().config().get_string("templates.log")?,
|
None => command.settings().config().get_string("templates.log")?,
|
||||||
};
|
};
|
||||||
let template = workspace_command.parse_commit_template(&template_string)?;
|
template = workspace_command.parse_template(&language, &template_string)?;
|
||||||
let with_content_format = LogContentFormat::new(ui, command.settings())?;
|
commit_node_template = workspace_command
|
||||||
|
.parse_template(&language, &command.settings().commit_node_template())?;
|
||||||
|
}
|
||||||
|
|
||||||
ui.request_pager();
|
ui.request_pager();
|
||||||
let mut formatter = ui.stdout_formatter();
|
let mut formatter = ui.stdout_formatter();
|
||||||
|
@ -90,7 +98,6 @@ pub(crate) fn cmd_obslog(
|
||||||
}
|
}
|
||||||
if !args.no_graph {
|
if !args.no_graph {
|
||||||
let mut graph = get_graphlog(command.settings(), formatter.raw());
|
let mut graph = get_graphlog(command.settings(), formatter.raw());
|
||||||
let default_node_symbol = command.settings().default_node_symbol();
|
|
||||||
for commit in commits {
|
for commit in commits {
|
||||||
let mut edges = vec![];
|
let mut edges = vec![];
|
||||||
for predecessor in &commit.predecessors() {
|
for predecessor in &commit.predecessors() {
|
||||||
|
@ -115,15 +122,11 @@ pub(crate) fn cmd_obslog(
|
||||||
&diff_formats,
|
&diff_formats,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
let node_symbol = if Some(commit.id()) == wc_commit_id {
|
let node_symbol = format_template(ui, &commit, commit_node_template.as_ref());
|
||||||
"@"
|
|
||||||
} else {
|
|
||||||
&default_node_symbol
|
|
||||||
};
|
|
||||||
graph.add_node(
|
graph.add_node(
|
||||||
commit.id(),
|
commit.id(),
|
||||||
&edges,
|
&edges,
|
||||||
node_symbol,
|
&node_symbol,
|
||||||
&String::from_utf8_lossy(&buffer),
|
&String::from_utf8_lossy(&buffer),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,11 @@ use jj_lib::op_walk;
|
||||||
use jj_lib::operation::Operation;
|
use jj_lib::operation::Operation;
|
||||||
use jj_lib::repo::Repo;
|
use jj_lib::repo::Repo;
|
||||||
|
|
||||||
use crate::cli_util::{short_operation_hash, CommandHelper, LogContentFormat};
|
use crate::cli_util::{format_template, short_operation_hash, CommandHelper, LogContentFormat};
|
||||||
use crate::command_error::{user_error, user_error_with_hint, CommandError};
|
use crate::command_error::{user_error, user_error_with_hint, CommandError};
|
||||||
use crate::graphlog::{get_graphlog, Edge};
|
use crate::graphlog::{get_graphlog, Edge};
|
||||||
use crate::operation_templater::OperationTemplateLanguage;
|
use crate::operation_templater::OperationTemplateLanguage;
|
||||||
use crate::templater::Template as _;
|
use crate::templater::Template;
|
||||||
use crate::ui::Ui;
|
use crate::ui::Ui;
|
||||||
|
|
||||||
/// Commands for working with the operation log
|
/// Commands for working with the operation log
|
||||||
|
@ -157,8 +157,11 @@ fn cmd_op_log(
|
||||||
[op] => Some(op.id()),
|
[op] => Some(op.id()),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
let with_content_format = LogContentFormat::new(ui, command.settings())?;
|
||||||
|
|
||||||
let template = {
|
let template;
|
||||||
|
let op_node_template;
|
||||||
|
{
|
||||||
let language = OperationTemplateLanguage::new(
|
let language = OperationTemplateLanguage::new(
|
||||||
repo_loader.op_store().root_operation_id(),
|
repo_loader.op_store().root_operation_id(),
|
||||||
current_op_id,
|
current_op_id,
|
||||||
|
@ -168,9 +171,10 @@ fn cmd_op_log(
|
||||||
Some(value) => value.to_owned(),
|
Some(value) => value.to_owned(),
|
||||||
None => command.settings().config().get_string("templates.op_log")?,
|
None => command.settings().config().get_string("templates.op_log")?,
|
||||||
};
|
};
|
||||||
command.parse_template(ui, &language, &text)?
|
template = command.parse_template(ui, &language, &text)?;
|
||||||
};
|
op_node_template =
|
||||||
let with_content_format = LogContentFormat::new(ui, command.settings())?;
|
command.parse_template(ui, &language, &command.settings().op_node_template())?;
|
||||||
|
}
|
||||||
|
|
||||||
ui.request_pager();
|
ui.request_pager();
|
||||||
let mut formatter = ui.stdout_formatter();
|
let mut formatter = ui.stdout_formatter();
|
||||||
|
@ -178,14 +182,12 @@ fn cmd_op_log(
|
||||||
let iter = op_walk::walk_ancestors(&head_ops).take(args.limit.unwrap_or(usize::MAX));
|
let iter = op_walk::walk_ancestors(&head_ops).take(args.limit.unwrap_or(usize::MAX));
|
||||||
if !args.no_graph {
|
if !args.no_graph {
|
||||||
let mut graph = get_graphlog(command.settings(), formatter.raw());
|
let mut graph = get_graphlog(command.settings(), formatter.raw());
|
||||||
let default_node_symbol = command.settings().default_node_symbol();
|
|
||||||
for op in iter {
|
for op in iter {
|
||||||
let op = op?;
|
let op = op?;
|
||||||
let mut edges = vec![];
|
let mut edges = vec![];
|
||||||
for id in op.parent_ids() {
|
for id in op.parent_ids() {
|
||||||
edges.push(Edge::Direct(id.clone()));
|
edges.push(Edge::Direct(id.clone()));
|
||||||
}
|
}
|
||||||
let is_current_op = Some(op.id()) == current_op_id;
|
|
||||||
let mut buffer = vec![];
|
let mut buffer = vec![];
|
||||||
with_content_format.write_graph_text(
|
with_content_format.write_graph_text(
|
||||||
ui.new_formatter(&mut buffer).as_mut(),
|
ui.new_formatter(&mut buffer).as_mut(),
|
||||||
|
@ -197,15 +199,11 @@ fn cmd_op_log(
|
||||||
if !buffer.ends_with(b"\n") {
|
if !buffer.ends_with(b"\n") {
|
||||||
buffer.push(b'\n');
|
buffer.push(b'\n');
|
||||||
}
|
}
|
||||||
let node_symbol = if is_current_op {
|
let node_symbol = format_template(ui, &op, &op_node_template);
|
||||||
"@"
|
|
||||||
} else {
|
|
||||||
&default_node_symbol
|
|
||||||
};
|
|
||||||
graph.add_node(
|
graph.add_node(
|
||||||
op.id(),
|
op.id(),
|
||||||
&edges,
|
&edges,
|
||||||
node_symbol,
|
&node_symbol,
|
||||||
&String::from_utf8_lossy(&buffer),
|
&String::from_utf8_lossy(&buffer),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,14 +122,6 @@
|
||||||
"ascii-large"
|
"ascii-large"
|
||||||
],
|
],
|
||||||
"default": "curved"
|
"default": "curved"
|
||||||
},
|
|
||||||
"default_node": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The symbol used as the default symbol for nodes."
|
|
||||||
},
|
|
||||||
"elided_node": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The symbol used for elided nodes."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1409,7 +1409,7 @@ fn test_elided() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_custom_symbols() {
|
fn test_log_with_custom_symbols() {
|
||||||
// Test that elided commits are shown as synthetic nodes.
|
// Test that elided commits are shown as synthetic nodes.
|
||||||
let test_env = TestEnvironment::default();
|
let test_env = TestEnvironment::default();
|
||||||
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
|
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
|
||||||
|
@ -1435,11 +1435,11 @@ fn test_custom_symbols() {
|
||||||
// Simple test with showing default and elided nodes.
|
// Simple test with showing default and elided nodes.
|
||||||
test_env.add_config(concat!(
|
test_env.add_config(concat!(
|
||||||
"ui.log-synthetic-elided-nodes = true\n",
|
"ui.log-synthetic-elided-nodes = true\n",
|
||||||
"ui.graph.default_node = '┝'\n",
|
"templates.log_node = 'if(current_working_copy, \"$\", if(root, \"┴\", \"┝\"))'\n",
|
||||||
"ui.graph.elided_node = '🮀'",
|
"templates.log_node_elided = '\"🮀\"'",
|
||||||
));
|
));
|
||||||
insta::assert_snapshot!(get_log("@ | @- | description(initial)"), @r###"
|
insta::assert_snapshot!(get_log("@ | @- | description(initial) | root()"), @r###"
|
||||||
@ merge
|
$ merge
|
||||||
├─╮
|
├─╮
|
||||||
│ ┝ side branch 2
|
│ ┝ side branch 2
|
||||||
│ │
|
│ │
|
||||||
|
@ -1450,18 +1450,18 @@ fn test_custom_symbols() {
|
||||||
├─╯
|
├─╯
|
||||||
┝ initial
|
┝ initial
|
||||||
│
|
│
|
||||||
~
|
┴
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
// Simple test with showing default and elided nodes, ascii style.
|
// Simple test with showing default and elided nodes, ascii style.
|
||||||
test_env.add_config(concat!(
|
test_env.add_config(concat!(
|
||||||
"ui.log-synthetic-elided-nodes = true\n",
|
"ui.log-synthetic-elided-nodes = true\n",
|
||||||
"ui.graph.style = 'ascii'\n",
|
"ui.graph.style = 'ascii'\n",
|
||||||
"ui.graph.default_node = '*'\n",
|
"templates.log_node = 'if(current_working_copy, \"$\", if(root, \"^\", \"*\"))'\n",
|
||||||
"ui.graph.elided_node = ':'",
|
"templates.log_node_elided = '\":\"'",
|
||||||
));
|
));
|
||||||
insta::assert_snapshot!(get_log("@ | @- | description(initial)"), @r###"
|
insta::assert_snapshot!(get_log("@ | @- | description(initial) | root()"), @r###"
|
||||||
@ merge
|
$ merge
|
||||||
|\
|
|\
|
||||||
| * side branch 2
|
| * side branch 2
|
||||||
| |
|
| |
|
||||||
|
@ -1472,6 +1472,6 @@ fn test_custom_symbols() {
|
||||||
|/
|
|/
|
||||||
* initial
|
* initial
|
||||||
|
|
|
|
||||||
~
|
^
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,6 +142,35 @@ fn test_obslog_with_or_without_diff() {
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_obslog_with_custom_symbols() {
|
||||||
|
let test_env = TestEnvironment::default();
|
||||||
|
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
|
||||||
|
let repo_path = test_env.env_root().join("repo");
|
||||||
|
|
||||||
|
std::fs::write(repo_path.join("file1"), "foo\n").unwrap();
|
||||||
|
test_env.jj_cmd_ok(&repo_path, &["new", "-m", "my description"]);
|
||||||
|
std::fs::write(repo_path.join("file1"), "foo\nbar\n").unwrap();
|
||||||
|
std::fs::write(repo_path.join("file2"), "foo\n").unwrap();
|
||||||
|
test_env.jj_cmd_ok(&repo_path, &["rebase", "-r", "@", "-d", "root()"]);
|
||||||
|
std::fs::write(repo_path.join("file1"), "resolved\n").unwrap();
|
||||||
|
|
||||||
|
let toml = concat!("templates.log_node = 'if(current_working_copy, \"$\", \"┝\")'\n",);
|
||||||
|
|
||||||
|
let stdout = test_env.jj_cmd_success(&repo_path, &["obslog", "--config-toml", toml]);
|
||||||
|
|
||||||
|
insta::assert_snapshot!(stdout, @r###"
|
||||||
|
$ rlvkpnrz test.user@example.com 2001-02-03 08:05:10 66b42ad3
|
||||||
|
│ my description
|
||||||
|
┝ rlvkpnrz hidden test.user@example.com 2001-02-03 08:05:09 ebc23d4b conflict
|
||||||
|
│ my description
|
||||||
|
┝ rlvkpnrz hidden test.user@example.com 2001-02-03 08:05:09 6fbba7bc
|
||||||
|
│ my description
|
||||||
|
┝ rlvkpnrz hidden test.user@example.com 2001-02-03 08:05:08 eac0d0da
|
||||||
|
(empty) my description
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_obslog_word_wrap() {
|
fn test_obslog_word_wrap() {
|
||||||
let test_env = TestEnvironment::default();
|
let test_env = TestEnvironment::default();
|
||||||
|
|
|
@ -93,6 +93,37 @@ fn test_op_log() {
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_op_log_with_custom_symbols() {
|
||||||
|
let test_env = TestEnvironment::default();
|
||||||
|
test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);
|
||||||
|
let repo_path = test_env.env_root().join("repo");
|
||||||
|
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "description 0"]);
|
||||||
|
|
||||||
|
let stdout = test_env.jj_cmd_success(
|
||||||
|
&repo_path,
|
||||||
|
&[
|
||||||
|
"op",
|
||||||
|
"log",
|
||||||
|
"--config-toml",
|
||||||
|
concat!(
|
||||||
|
"template-aliases.'format_time_range(x)' = 'x'\n",
|
||||||
|
"templates.op_log_node = 'if(current_operation, \"$\", if(root, \"┴\", \"┝\"))'",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
insta::assert_snapshot!(&stdout, @r###"
|
||||||
|
$ 52ac15d375ba test-username@host.example.com 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00
|
||||||
|
│ describe commit 230dd059e1b059aefc0da06a2e5a7dbf22362f22
|
||||||
|
│ args: jj describe -m 'description 0'
|
||||||
|
┝ b51416386f26 test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00
|
||||||
|
│ add workspace 'default'
|
||||||
|
┝ 9a7d829846af test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00
|
||||||
|
│ initialize repo
|
||||||
|
┴ 000000000000 root()
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_op_log_with_no_template() {
|
fn test_op_log_with_no_template() {
|
||||||
let test_env = TestEnvironment::default();
|
let test_env = TestEnvironment::default();
|
||||||
|
|
|
@ -229,6 +229,30 @@ revsets.log = "main@origin.."
|
||||||
ui.graph.style = "square"
|
ui.graph.style = "square"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Node style
|
||||||
|
|
||||||
|
The symbols used to represent commits or operations can be customized via
|
||||||
|
templates.
|
||||||
|
|
||||||
|
* `templates.log_node` for commits (with `Commit` keywords)
|
||||||
|
* `templates.op_log_node` for operations (with `Operation` keywords)
|
||||||
|
* `templates.log_node_elided` for elided nodes
|
||||||
|
|
||||||
|
For example:
|
||||||
|
```toml
|
||||||
|
[templates]
|
||||||
|
log_node = '''
|
||||||
|
if(current_working_copy, "@",
|
||||||
|
if(root, "┴",
|
||||||
|
if(immutable, "●", "○")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
op_log_node = 'if(current_operation, "@", "○")'
|
||||||
|
log_node_elided = '"🮀"'
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
### Wrap log content
|
### Wrap log content
|
||||||
|
|
||||||
If enabled, `log`/`obslog`/`op log` content will be wrapped based on
|
If enabled, `log`/`obslog`/`op log` content will be wrapped based on
|
||||||
|
|
|
@ -242,12 +242,24 @@ impl UserSettings {
|
||||||
.unwrap_or_else(|_| "curved".to_string())
|
.unwrap_or_else(|_| "curved".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_node_symbol(&self) -> String {
|
pub fn commit_node_template(&self) -> String {
|
||||||
self.node_symbol_for_key("ui.graph.default_node", "◉", "o")
|
self.node_template_for_key(
|
||||||
|
"templates.log_node",
|
||||||
|
r#"if(current_working_copy, "@", "◉")"#,
|
||||||
|
r#"if(current_working_copy, "@", "o")"#,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn elided_node_symbol(&self) -> String {
|
pub fn op_node_template(&self) -> String {
|
||||||
self.node_symbol_for_key("ui.graph.elided_node", "◌", ".")
|
self.node_template_for_key(
|
||||||
|
"templates.op_log_node",
|
||||||
|
r#"if(current_operation, "@", "◉")"#,
|
||||||
|
r#"if(current_operation, "@", "o")"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn elided_node_template(&self) -> String {
|
||||||
|
self.node_template_for_key("templates.log_node_elided", r#""◌""#, r#"".""#)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_new_file_size(&self) -> Result<u64, config::ConfigError> {
|
pub fn max_new_file_size(&self) -> Result<u64, config::ConfigError> {
|
||||||
|
@ -273,7 +285,7 @@ impl UserSettings {
|
||||||
SignSettings::from_settings(self)
|
SignSettings::from_settings(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_symbol_for_key(&self, key: &str, fallback: &str, ascii_fallback: &str) -> String {
|
fn node_template_for_key(&self, key: &str, fallback: &str, ascii_fallback: &str) -> String {
|
||||||
let symbol = self.config.get_string(key);
|
let symbol = self.config.get_string(key);
|
||||||
match self.graph_style().as_str() {
|
match self.graph_style().as_str() {
|
||||||
"ascii" | "ascii-large" => symbol.unwrap_or_else(|_| ascii_fallback.to_owned()),
|
"ascii" | "ascii-large" => symbol.unwrap_or_else(|_| ascii_fallback.to_owned()),
|
||||||
|
|
Loading…
Reference in a new issue