git-ents.gitmain
⌘K
foforge
commit 8f5861b
roots: list only blobs in the commit diff, not every subdirectory

The tree walk names each intermediate directory as its own change; those rendered as bare file headers per subdirectory.

Assisted-by: Claude:claude-fable-5

Joseph D. Carpinelli · 1 month ago

Reviews

No reviews of this commit yet — record a verdict below.

Start a review

verdict

crates/cli/ents-web/tests/router.rs @@ -1705,6 +1705,45 @@ ); } +/// `GET /commit/{oid}` renders one `.file` header per changed blob and +/// none for the intermediate directories the tree walk also names -- +/// each subdirectory used to appear as its own bare file section. +#[tokio::test] +async fn commit_diff_lists_files_not_intermediate_directories() { + let dir = seed_repo(&[("crates/foo/src/lib.rs", "pub fn f() {}\n")]); + let oid = head_oid(dir.path()); + let state = build_state_at( + FixtureIdentity { + name: "local-user", + key: Keypair::from_seed(1), + }, + dir.path().to_owned(), + ); + let router = ents_web::router(state); + + let response = router + .oneshot( + Request::get(format!("/commit/{oid}")) + .body(Body::empty()) + .expect("request"), + ) + .await + .expect("in-process call"); + assert_eq!(response.status(), StatusCode::OK); + let body = response + .into_body() + .collect() + .await + .expect("body") + .to_bytes(); + let body = String::from_utf8(body.to_vec()).expect("utf8 html"); + assert_eq!( + body.matches("class=\"ln file\"").count(), + 1, + "one changed blob means exactly one file header" + ); +} + /// `GET /commit/{oid}` lists, under a "conversation" heading, every /// comment whose anchor was captured against that exact commit -- and /// none captured against a different one, even a later commit on the same
crates/cli/ents-web/src/pages/commits.rs @@ -596,6 +596,13 @@ if truncated { return Ok::<_, std::convert::Infallible>(std::ops::ControlFlow::Break(())); } + // The walk yields every intermediate directory as its own tree + // change; only blob (and link) entries are files a reader can + // diff, so a tree entry renders nothing rather than a bare + // header per subdirectory. + if is_tree_change(&change) { + return Ok(std::ops::ControlFlow::Continue(())); + } let (section, bytes) = render_change(repo, &change); total = total.saturating_add(bytes); sections.push(section); @@ -607,6 +614,18 @@ (html! { @for section in &sections { (section) } }, truncated) } +/// Whether `change` is a tree (directory) entry rather than a blob or +/// link -- [`diff_sections`] skips these, since the walk names every +/// intermediate directory on the way to a changed file. +fn is_tree_change(change: &Change<'_, '_, '_>) -> bool { + match *change { + Change::Addition { entry_mode, .. } + | Change::Deletion { entry_mode, .. } + | Change::Modification { entry_mode, .. } + | Change::Rewrite { entry_mode, .. } => entry_mode.is_tree(), + } +} + /// One changed file's `.diff` section: a `.file`-classed header naming the /// path (and, on a rename, the old path it moved from), followed by either /// a `.meta`-classed "binary file changed" notice or the colorized unified