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.
Showing the changes to crates/buffer_diff/src/buffer_diff.rs (1 of 33 files). Show all
Unified · Split
| @@ -25,6 +25,23 @@ pub struct BufferDiff { · 24 unmodified lines | ||
| 25 | 25 | diff_snapshot: Option<BufferDiffSnapshot>, |
| 26 | 26 | secondary_diff: Option<Entity<BufferDiff>>, |
| 27 | 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)] | |
| 35 | +pub 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 | 47 | #[derive(Clone)] |
| @@ -1553,6 +1570,7 @@ impl BufferDiff { · 1522 unmodified lines | ||
| 1553 | 1570 | buffer: &text::BufferSnapshot, |
| 1554 | 1571 | language: Option<Arc<Language>>, |
| 1555 | 1572 | language_registry: Option<Arc<LanguageRegistry>>, |
| 1573 | + base_kind: DiffBaseKind, | |
| 1556 | 1574 | cx: &mut App, |
| 1557 | 1575 | ) -> Self { |
| 1558 | 1576 | let base_text = cx.new(|cx| { |
| @@ -1571,12 +1589,14 @@ impl BufferDiff { · 12 unmodified lines | ||
| 1571 | 1589 | diff_snapshot: None, |
| 1572 | 1590 | buffer_snapshot: buffer.clone(), |
| 1573 | 1591 | secondary_diff: None, |
| 1592 | + base_kind, | |
| 1574 | 1593 | } |
| 1575 | 1594 | } |
| 1576 | 1595 | |
| 1577 | 1596 | pub fn new_with_base_text_buffer( |
| 1578 | 1597 | buffer: &text::BufferSnapshot, |
| 1579 | 1598 | base_text_buffer: Entity<language::Buffer>, |
| 1599 | + base_kind: DiffBaseKind, | |
| 1580 | 1600 | _cx: &mut App, |
| 1581 | 1601 | ) -> Self { |
| 1582 | 1602 | BufferDiff { |
| @@ -1585,6 +1605,7 @@ impl BufferDiff { · 2 unmodified lines | ||
| 1585 | 1605 | diff_snapshot: None, |
| 1586 | 1606 | buffer_snapshot: buffer.clone(), |
| 1587 | 1607 | secondary_diff: None, |
| 1608 | + base_kind, | |
| 1588 | 1609 | } |
| 1589 | 1610 | } |
| 1590 | 1611 | |
| @@ -1592,6 +1613,7 @@ impl BufferDiff { · 1 unmodified line | ||
| 1592 | 1613 | buffer: &text::BufferSnapshot, |
| 1593 | 1614 | language: Option<Arc<Language>>, |
| 1594 | 1615 | language_registry: Option<Arc<LanguageRegistry>>, |
| 1616 | + base_kind: DiffBaseKind, | |
| 1595 | 1617 | cx: &mut Context<Self>, |
| 1596 | 1618 | ) -> Self { |
| 1597 | 1619 | let base_text = buffer.text(); |
| @@ -1622,6 +1644,7 @@ impl BufferDiff { · 24 unmodified lines | ||
| 1622 | 1644 | diff_snapshot: Some(diff_snapshot), |
| 1623 | 1645 | buffer_snapshot: buffer.clone(), |
| 1624 | 1646 | secondary_diff: None, |
| 1647 | + base_kind, | |
| 1625 | 1648 | } |
| 1626 | 1649 | } |
| 1627 | 1650 | |
| @@ -1631,7 +1654,7 @@ impl BufferDiff { · 3 unmodified lines | ||
| 1631 | 1654 | buffer: &text::BufferSnapshot, |
| 1632 | 1655 | cx: &mut Context<Self>, |
| 1633 | 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 | 1658 | let mut base_text = base_text.to_owned(); |
| 1636 | 1659 | text::LineEnding::normalize(&mut base_text); |
| 1637 | 1660 | let base_text_buffer = cx.new(|cx| { |
| @@ -1655,6 +1678,16 @@ impl BufferDiff { · 17 unmodified lines | ||
| 1655 | 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 | 1691 | pub fn secondary_diff(&self) -> Option<Entity<BufferDiff>> { |
| 1659 | 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 | 2487 | assert_hunks::<&str, _>( |
| 2454 | 2488 | diff.hunks_intersecting_range( |
| 2455 | 2489 | Anchor::min_max_range_for_buffer(buffer.remote_id()), |
| @@ -3154,7 +3188,8 @@ mod tests { · 698 unmodified lines | ||
| 3154 | 3188 | |
| 3155 | 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 | 3193 | let diff_1 = BufferDiffSnapshot::new_sync(&buffer, base_text.clone(), cx); |
| 3159 | 3194 | let DiffChanged { |
| 3160 | 3195 | changed_range, |
| @@ -4312,7 +4347,8 @@ mod tests { · 1151 unmodified lines | ||
| 4312 | 4347 | ); |
| 4313 | 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 | 4352 | diff.update(cx, |diff, cx| { |
| 4317 | 4353 | diff.set_base_text(Some(Arc::from(base_text_crlf)), buffer_snapshot.clone(), cx) |
| 4318 | 4354 | }) |