History

Compute branch diff statuses from worktree contents

Replace the status-combination table with a real merge-base-to-worktree tree diff, make GitStore share one DiffBufferList per repository with the branch diff view, keep repo_snapshots as index/worktree truth with separate display status APIs, and make non-HEAD gutter hunks read-only. The git.diff_base setting values are now "head" and "default_branch", applied live and toggleable from the editor controls menu. git::Diff follows the setting; git::DiffHead always opens the HEAD diff; and git::BranchDiff is renamed to git::DiffBranch with a deprecated alias.

Ben Kunkle committed 3 months ago

Commit ecb8e7e1 parent b10f68333 files · +1552 −1324Browse files

Showing the changes to crates/buffer_diff/src/buffer_diff.rs (1 of 33 files). Show all

Unified · Split

crates/buffer_diff/src/buffer_diff.rs+40−4
@@ -25,6 +25,23 @@ pub struct BufferDiff { · 24 unmodified lines
25 diff_snapshot: Option<BufferDiffSnapshot>,25 diff_snapshot: Option<BufferDiffSnapshot>,
26 secondary_diff: Option<Entity<BufferDiff>>,26 secondary_diff: Option<Entity<BufferDiff>>,
27 buffer_snapshot: text::BufferSnapshot,27 buffer_snapshot: text::BufferSnapshot,
28 base_kind: DiffBaseKind,
29}
30
31/// Where this diff's base text came from. Only diffs whose base is HEAD
32/// support staging and restoring hunks; a diff against any other base (e.g.
33/// the merge base with another branch) would rewrite committed work.
34#[derive(Clone, Copy, Debug, PartialEq, Eq)]
35pub enum DiffBaseKind {
36 /// The buffer's committed (HEAD) content.
37 Head,
38 /// The buffer's index (staged) content.
39 Index,
40 /// An arbitrary blob, such as the merge base with another branch.
41 Oid,
42 /// Arbitrary caller-provided text, such as an agent's original text,
43 /// the clipboard, or another file.
44 Custom,
28}45}
29 46
30#[derive(Clone)]47#[derive(Clone)]
@@ -1553,6 +1570,7 @@ impl BufferDiff { · 1522 unmodified lines
1553 buffer: &text::BufferSnapshot,1570 buffer: &text::BufferSnapshot,
1554 language: Option<Arc<Language>>,1571 language: Option<Arc<Language>>,
1555 language_registry: Option<Arc<LanguageRegistry>>,1572 language_registry: Option<Arc<LanguageRegistry>>,
1573 base_kind: DiffBaseKind,
1556 cx: &mut App,1574 cx: &mut App,
1557 ) -> Self {1575 ) -> Self {
1558 let base_text = cx.new(|cx| {1576 let base_text = cx.new(|cx| {
@@ -1571,12 +1589,14 @@ impl BufferDiff { · 12 unmodified lines
1571 diff_snapshot: None,1589 diff_snapshot: None,
1572 buffer_snapshot: buffer.clone(),1590 buffer_snapshot: buffer.clone(),
1573 secondary_diff: None,1591 secondary_diff: None,
1592 base_kind,
1574 }1593 }
1575 }1594 }
1576 1595
1577 pub fn new_with_base_text_buffer(1596 pub fn new_with_base_text_buffer(
1578 buffer: &text::BufferSnapshot,1597 buffer: &text::BufferSnapshot,
1579 base_text_buffer: Entity<language::Buffer>,1598 base_text_buffer: Entity<language::Buffer>,
1599 base_kind: DiffBaseKind,
1580 _cx: &mut App,1600 _cx: &mut App,
1581 ) -> Self {1601 ) -> Self {
1582 BufferDiff {1602 BufferDiff {
@@ -1585,6 +1605,7 @@ impl BufferDiff { · 2 unmodified lines
1585 diff_snapshot: None,1605 diff_snapshot: None,
1586 buffer_snapshot: buffer.clone(),1606 buffer_snapshot: buffer.clone(),
1587 secondary_diff: None,1607 secondary_diff: None,
1608 base_kind,
1588 }1609 }
1589 }1610 }
1590 1611
@@ -1592,6 +1613,7 @@ impl BufferDiff { · 1 unmodified line
1592 buffer: &text::BufferSnapshot,1613 buffer: &text::BufferSnapshot,
1593 language: Option<Arc<Language>>,1614 language: Option<Arc<Language>>,
1594 language_registry: Option<Arc<LanguageRegistry>>,1615 language_registry: Option<Arc<LanguageRegistry>>,
1616 base_kind: DiffBaseKind,
1595 cx: &mut Context<Self>,1617 cx: &mut Context<Self>,
1596 ) -> Self {1618 ) -> Self {
1597 let base_text = buffer.text();1619 let base_text = buffer.text();
@@ -1622,6 +1644,7 @@ impl BufferDiff { · 24 unmodified lines
1622 diff_snapshot: Some(diff_snapshot),1644 diff_snapshot: Some(diff_snapshot),
1623 buffer_snapshot: buffer.clone(),1645 buffer_snapshot: buffer.clone(),
1624 secondary_diff: None,1646 secondary_diff: None,
1647 base_kind,
1625 }1648 }
1626 }1649 }
1627 1650
@@ -1631,7 +1654,7 @@ impl BufferDiff { · 3 unmodified lines
1631 buffer: &text::BufferSnapshot,1654 buffer: &text::BufferSnapshot,
1632 cx: &mut Context<Self>,1655 cx: &mut Context<Self>,
1633 ) -> Self {1656 ) -> Self {
1634 let mut this = BufferDiff::new(buffer, None, None, cx);1657 let mut this = BufferDiff::new(buffer, None, None, DiffBaseKind::Head, cx);
1635 let mut base_text = base_text.to_owned();1658 let mut base_text = base_text.to_owned();
1636 text::LineEnding::normalize(&mut base_text);1659 text::LineEnding::normalize(&mut base_text);
1637 let base_text_buffer = cx.new(|cx| {1660 let base_text_buffer = cx.new(|cx| {
@@ -1655,6 +1678,16 @@ impl BufferDiff { · 17 unmodified lines
1655 self.secondary_diff = Some(diff);1678 self.secondary_diff = Some(diff);
1656 }1679 }
1657 1680
1681 pub fn base_kind(&self) -> DiffBaseKind {
1682 self.base_kind
1683 }
1684
1685 /// Whether hunks in this diff can be staged or restored: true only when
1686 /// the diff's base is HEAD.
1687 pub fn is_stageable(&self) -> bool {
1688 self.base_kind == DiffBaseKind::Head
1689 }
1690
1658 pub fn secondary_diff(&self) -> Option<Entity<BufferDiff>> {1691 pub fn secondary_diff(&self) -> Option<Entity<BufferDiff>> {
1659 self.secondary_diff.clone()1692 self.secondary_diff.clone()
1660 }1693 }
@@ -2449,7 +2482,8 @@ mod tests { · 788 unmodified lines
2449 ],2482 ],
2450 );2483 );
2451 2484
2452 diff = cx.update(|cx| BufferDiff::new(&buffer, None, None, cx).snapshot(cx));2485 diff = cx
2486 .update(|cx| BufferDiff::new(&buffer, None, None, DiffBaseKind::Head, cx).snapshot(cx));
2453 assert_hunks::<&str, _>(2487 assert_hunks::<&str, _>(
2454 diff.hunks_intersecting_range(2488 diff.hunks_intersecting_range(
2455 Anchor::min_max_range_for_buffer(buffer.remote_id()),2489 Anchor::min_max_range_for_buffer(buffer.remote_id()),
@@ -3154,7 +3188,8 @@ mod tests { · 698 unmodified lines
3154 3188
3155 let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), buffer_text_1);3189 let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), buffer_text_1);
3156 3190
3157 let empty_diff = cx.update(|cx| BufferDiff::new(&buffer, None, None, cx).snapshot(cx));3191 let empty_diff = cx
3192 .update(|cx| BufferDiff::new(&buffer, None, None, DiffBaseKind::Head, cx).snapshot(cx));
3158 let diff_1 = BufferDiffSnapshot::new_sync(&buffer, base_text.clone(), cx);3193 let diff_1 = BufferDiffSnapshot::new_sync(&buffer, base_text.clone(), cx);
3159 let DiffChanged {3194 let DiffChanged {
3160 changed_range,3195 changed_range,
@@ -4312,7 +4347,8 @@ mod tests { · 1151 unmodified lines
4312 );4347 );
4313 let buffer_snapshot = buffer.snapshot();4348 let buffer_snapshot = buffer.snapshot();
4314 4349
4315 let diff = cx.new(|cx| BufferDiff::new(&buffer_snapshot, None, None, cx));4350 let diff =
4351 cx.new(|cx| BufferDiff::new(&buffer_snapshot, None, None, DiffBaseKind::Head, cx));
4316 diff.update(cx, |diff, cx| {4352 diff.update(cx, |diff, cx| {
4317 diff.set_base_text(Some(Arc::from(base_text_crlf)), buffer_snapshot.clone(), cx)4353 diff.set_base_text(Some(Arc::from(base_text_crlf)), buffer_snapshot.clone(), cx)
4318 })4354 })