Skip to content

Commit

Permalink
evolog: Implement --reversed flag
Browse files Browse the repository at this point in the history
Adds some additional helper functions for converting between jj_lib's
GraphEdge and the graphlog's Edge type.
  • Loading branch information
JDSeiler committed Dec 28, 2024
1 parent 4af39e2 commit a903115
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
below it, similar to a "scissor line" in git. When editing multiple commits,
only ignore until the next `JJ: describe` line.

* `jj evolog` now accepts `--reversed`.

### Fixed bugs

* The `$NO_COLOR` environment variable must now be non-empty to be respected.
Expand Down
49 changes: 42 additions & 7 deletions cli/src/commands/evolog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::convert::Infallible;

use clap_complete::ArgValueCandidates;
use itertools::Itertools;
use jj_lib::backend::CommitId;
use jj_lib::commit::Commit;
use jj_lib::dag_walk::topo_order_reverse_ok;
use jj_lib::graph::reverse_graph;
use jj_lib::graph::GraphEdge;
use jj_lib::graph::GraphNode;
use jj_lib::matchers::EverythingMatcher;
use tracing::instrument;

Expand All @@ -28,6 +34,7 @@ use crate::command_error::CommandError;
use crate::commit_templater::CommitTemplateLanguage;
use crate::complete;
use crate::diff_util::DiffFormatArgs;
use crate::graphlog::convert_edge_type;
use crate::graphlog::get_graphlog;
use crate::graphlog::Edge;
use crate::graphlog::GraphStyle;
Expand Down Expand Up @@ -57,6 +64,9 @@ pub(crate) struct EvologArgs {
value_name = "LIMIT"
)]
deprecated_limit: Option<usize>,
/// Show revisions in the opposite order (older revisions first)
#[arg(long)]
reversed: bool,
/// Don't show the graph, show a flat list of revisions
#[arg(long)]
no_graph: bool,
Expand Down Expand Up @@ -151,14 +161,35 @@ pub(crate) fn cmd_evolog(
if !args.no_graph {
let mut raw_output = formatter.raw()?;
let mut graph = get_graphlog(graph_style, raw_output.as_mut());
for commit in commits {
let edges = commit
.predecessor_ids()

let commit_dag: Vec<Result<GraphNode<Commit>, Infallible>> = commits
.iter()
.map(|c| {
let edges = c
.predecessors()
.map(|p| GraphEdge::direct(p.unwrap().clone()))
.collect_vec();
Ok((c.clone(), edges))
})
.collect_vec();

let iter_nodes = if args.reversed {
reverse_graph(commit_dag.into_iter()).unwrap()
} else {
commit_dag.into_iter().map(Result::unwrap).collect_vec()
};

for node in iter_nodes {
let (commit, edges) = node;
// Slightly different edge type used for display.
let graphlog_edges: Vec<Edge<CommitId>> = edges
.iter()
.map(|id| Edge::Direct(id.clone()))
.collect_vec();
.cloned()
.map(|e| convert_edge_type(e).map(|e| e.id().clone()))
.collect();
let mut buffer = vec![];
let within_graph = with_content_format.sub_width(graph.width(commit.id(), &edges));
let within_graph =
with_content_format.sub_width(graph.width(commit.id(), &graphlog_edges));
within_graph.write(ui.new_formatter(&mut buffer).as_mut(), |formatter| {
template.format(&commit, formatter)
})?;
Expand All @@ -180,12 +211,16 @@ pub(crate) fn cmd_evolog(
let node_symbol = format_template(ui, &Some(commit.clone()), &node_template);
graph.add_node(
commit.id(),
&edges,
&graphlog_edges,
&node_symbol,
&String::from_utf8_lossy(&buffer),
)?;
}
} else {
if args.reversed {
commits.reverse();
}

for commit in commits {
with_content_format
.write(formatter, |formatter| template.format(&commit, formatter))?;
Expand Down
24 changes: 24 additions & 0 deletions cli/src/graphlog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use std::io::Write;

use itertools::Itertools;
use jj_lib::config::ConfigGetError;
use jj_lib::graph::GraphEdge;
use jj_lib::graph::GraphEdgeType;
use jj_lib::settings::UserSettings;
use renderdag::Ancestor;
use renderdag::GraphRowRenderer;
Expand All @@ -31,6 +33,28 @@ pub enum Edge<T> {
Missing,
}

impl<T> Edge<T> {
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Edge<U> {
match self {
Edge::Direct(inner) => Edge::Direct(f(inner)),
Edge::Indirect(inner) => Edge::Indirect(f(inner)),
Edge::Missing => Edge::Missing,
}
}
}

/// Used to convert a jj_lib GraphEdge into a graphlog Edge.
pub fn convert_edge_type<N>(e: GraphEdge<N>) -> Edge<N> {
// TODO: Is it possible for the ClI to use the GraphEdge type directly?
// These two types seem to correspond exactly, only differing in minor
// implementation details.
match e.edge_type {
GraphEdgeType::Missing => Edge::Missing,
GraphEdgeType::Direct => Edge::Direct(e.target),
GraphEdgeType::Indirect => Edge::Indirect(e.target),
}
}

pub trait GraphLog<K: Clone + Eq + Hash> {
fn add_node(
&mut self,
Expand Down
1 change: 1 addition & 0 deletions cli/tests/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,7 @@ Lists the previous commits which a change has pointed to. The current commit of
Default value: `@`
* `-n`, `--limit <LIMIT>` — Limit number of revisions to show
* `--reversed` — Show revisions in the opposite order (older revisions first)
* `--no-graph` — Don't show the graph, show a flat list of revisions
* `-T`, `--template <TEMPLATE>` — Render each revision using the given template
Expand Down
67 changes: 67 additions & 0 deletions cli/tests/test_evolog_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,70 @@ fn test_evolog_with_no_template() {
- name_placeholder
"#);
}

#[test]
fn test_evolog_reversed_no_graph() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");

test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "a"]);
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "b"]);
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "c"]);
let stdout = test_env.jj_cmd_success(&repo_path, &["evolog", "--reversed", "--no-graph"]);
insta::assert_snapshot!(stdout, @r"
qpvuntsm hidden [email protected] 2001-02-03 08:05:07 230dd059
(empty) (no description set)
qpvuntsm hidden [email protected] 2001-02-03 08:05:08 d8d5f980
(empty) a
qpvuntsm hidden [email protected] 2001-02-03 08:05:09 b4584f54
(empty) b
qpvuntsm [email protected] 2001-02-03 08:05:10 5cb22a87
(empty) c
");
}

#[test]
fn test_evolog_reverse_with_graph() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
let repo_path = test_env.env_root().join("repo");

test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "a"]);
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "b"]);
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "c"]);
test_env.jj_cmd_ok(&repo_path, &["new", "-r", "description(c)", "-m", "d"]);
test_env.jj_cmd_ok(&repo_path, &["new", "-r", "description(c)", "-m", "e"]);
test_env.jj_cmd_ok(
&repo_path,
&[
"squash",
"--from",
"description(d)|description(e)",
"--to",
"description(c)",
"-m",
"c+d+e",
],
);
let stdout = test_env.jj_cmd_success(
&repo_path,
&["evolog", "-r", "description(c+d+e)", "--reversed"],
);
insta::assert_snapshot!(stdout, @r"
○ qpvuntsm hidden [email protected] 2001-02-03 08:05:07 230dd059
│ (empty) (no description set)
○ qpvuntsm hidden [email protected] 2001-02-03 08:05:08 d8d5f980
│ (empty) a
○ qpvuntsm hidden [email protected] 2001-02-03 08:05:09 b4584f54
│ (empty) b
○ qpvuntsm hidden [email protected] 2001-02-03 08:05:10 5cb22a87
│ (empty) c
│ ○ mzvwutvl hidden [email protected] 2001-02-03 08:05:11 280cbb6e
├─╯ (empty) d
│ ○ royxmykx hidden [email protected] 2001-02-03 08:05:12 031df638
├─╯ (empty) e
○ qpvuntsm [email protected] 2001-02-03 08:05:13 a177c2f2
(empty) c+d+e
");
}

0 comments on commit a903115

Please sign in to comment.