git: Revert "Ignore whitespace in git blame invocation" (#44648)

Reverts zed-industries/zed#35960
cc @cole-miller

---------

Co-authored-by: Cole Miller <cole@zed.dev>
This commit is contained in:
Piotr Osiewicz 2025-12-12 14:28:25 +01:00 committed by GitHub
parent 18d344e118
commit 47c30b6da7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 50 additions and 29 deletions

View file

@ -23,6 +23,7 @@ use std::{
path::PathBuf,
sync::{Arc, LazyLock},
};
use text::LineEnding;
use util::{paths::PathStyle, rel_path::RelPath};
pub static LOAD_INDEX_TEXT_TASK: LazyLock<TaskLabel> = LazyLock::new(TaskLabel::new);
@ -452,7 +453,12 @@ impl GitRepository for FakeGitRepository {
})
}
fn blame(&self, path: RepoPath, _content: Rope) -> BoxFuture<'_, Result<git::blame::Blame>> {
fn blame(
&self,
path: RepoPath,
_content: Rope,
_line_ending: LineEnding,
) -> BoxFuture<'_, Result<git::blame::Blame>> {
self.with_state_async(false, move |state| {
state
.blames

View file

@ -803,7 +803,7 @@ impl Fs for RealFs {
}
let file = smol::fs::File::create(path).await?;
let mut writer = smol::io::BufWriter::with_capacity(buffer_size, file);
for chunk in chunks(text, line_ending) {
for chunk in text::chunks_with_line_ending(text, line_ending) {
writer.write_all(chunk.as_bytes()).await?;
}
writer.flush().await?;
@ -2555,7 +2555,7 @@ impl Fs for FakeFs {
async fn save(&self, path: &Path, text: &Rope, line_ending: LineEnding) -> Result<()> {
self.simulate_random_delay().await;
let path = normalize_path(path);
let content = chunks(text, line_ending).collect::<String>();
let content = text::chunks_with_line_ending(text, line_ending).collect::<String>();
if let Some(path) = path.parent() {
self.create_dir(path).await?;
}
@ -2773,25 +2773,6 @@ impl Fs for FakeFs {
}
}
fn chunks(rope: &Rope, line_ending: LineEnding) -> impl Iterator<Item = &str> {
rope.chunks().flat_map(move |chunk| {
let mut newline = false;
let end_with_newline = chunk.ends_with('\n').then_some(line_ending.as_str());
chunk
.lines()
.flat_map(move |line| {
let ending = if newline {
Some(line_ending.as_str())
} else {
None
};
newline = true;
ending.into_iter().chain([line])
})
.chain(end_with_newline)
})
}
pub fn normalize_path(path: &Path) -> PathBuf {
let mut components = path.components().peekable();
let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {

View file

@ -8,7 +8,7 @@ use gpui::SharedString;
use serde::{Deserialize, Serialize};
use std::process::Stdio;
use std::{ops::Range, path::Path};
use text::Rope;
use text::{LineEnding, Rope};
use time::OffsetDateTime;
use time::UtcOffset;
use time::macros::format_description;
@ -35,8 +35,10 @@ impl Blame {
working_directory: &Path,
path: &RepoPath,
content: &Rope,
line_ending: LineEnding,
) -> Result<Self> {
let output = run_git_blame(git_binary, working_directory, path, content).await?;
let output =
run_git_blame(git_binary, working_directory, path, content, line_ending).await?;
let mut entries = parse_git_blame(&output)?;
entries.sort_unstable_by(|a, b| a.range.start.cmp(&b.range.start));
@ -63,12 +65,12 @@ async fn run_git_blame(
working_directory: &Path,
path: &RepoPath,
contents: &Rope,
line_ending: LineEnding,
) -> Result<String> {
let mut child = util::command::new_smol_command(git_binary)
.current_dir(working_directory)
.arg("blame")
.arg("--incremental")
.arg("-w")
.arg("--contents")
.arg("-")
.arg(path.as_unix_str())
@ -83,7 +85,7 @@ async fn run_git_blame(
.as_mut()
.context("failed to get pipe to stdin of git blame command")?;
for chunk in contents.chunks() {
for chunk in text::chunks_with_line_ending(contents, line_ending) {
stdin.write_all(chunk.as_bytes()).await?;
}
stdin.flush().await?;

View file

@ -14,6 +14,7 @@ use rope::Rope;
use schemars::JsonSchema;
use serde::Deserialize;
use smol::io::{AsyncBufReadExt, AsyncReadExt, BufReader};
use text::LineEnding;
use std::collections::HashSet;
use std::ffi::{OsStr, OsString};
@ -487,7 +488,12 @@ pub trait GitRepository: Send + Sync {
fn show(&self, commit: String) -> BoxFuture<'_, Result<CommitDetails>>;
fn load_commit(&self, commit: String, cx: AsyncApp) -> BoxFuture<'_, Result<CommitDiff>>;
fn blame(&self, path: RepoPath, content: Rope) -> BoxFuture<'_, Result<crate::blame::Blame>>;
fn blame(
&self,
path: RepoPath,
content: Rope,
line_ending: LineEnding,
) -> BoxFuture<'_, Result<crate::blame::Blame>>;
fn file_history(&self, path: RepoPath) -> BoxFuture<'_, Result<FileHistory>>;
fn file_history_paginated(
&self,
@ -1512,7 +1518,12 @@ impl GitRepository for RealGitRepository {
.boxed()
}
fn blame(&self, path: RepoPath, content: Rope) -> BoxFuture<'_, Result<crate::blame::Blame>> {
fn blame(
&self,
path: RepoPath,
content: Rope,
line_ending: LineEnding,
) -> BoxFuture<'_, Result<crate::blame::Blame>> {
let working_directory = self.working_directory();
let git_binary_path = self.any_git_binary_path.clone();
let executor = self.executor.clone();
@ -1524,6 +1535,7 @@ impl GitRepository for RealGitRepository {
&working_directory?,
&path,
&content,
line_ending,
)
.await
})

View file

@ -1031,6 +1031,7 @@ impl GitStore {
Some(version) => buffer.rope_for_version(version),
None => buffer.as_rope().clone(),
};
let line_ending = buffer.line_ending();
let version = version.unwrap_or(buffer.version());
let buffer_id = buffer.remote_id();
@ -1042,7 +1043,7 @@ impl GitStore {
.map_err(|err| anyhow::anyhow!(err))?;
match repository_state {
RepositoryState::Local(LocalRepositoryState { backend, .. }) => backend
.blame(repo_path.clone(), content)
.blame(repo_path.clone(), content, line_ending)
.await
.with_context(|| format!("Failed to blame {:?}", repo_path.as_ref()))
.map(Some),

View file

@ -3387,6 +3387,25 @@ impl LineEnding {
}
}
pub fn chunks_with_line_ending(rope: &Rope, line_ending: LineEnding) -> impl Iterator<Item = &str> {
rope.chunks().flat_map(move |chunk| {
let mut newline = false;
let end_with_newline = chunk.ends_with('\n').then_some(line_ending.as_str());
chunk
.lines()
.flat_map(move |line| {
let ending = if newline {
Some(line_ending.as_str())
} else {
None
};
newline = true;
ending.into_iter().chain([line])
})
.chain(end_with_newline)
})
}
#[cfg(debug_assertions)]
pub mod debug {
use super::*;