Add staged status information to diff hunks (#24475)
Release Notes: - Render unstaged hunks in the project diff editor with a slashed background --------- Co-authored-by: maxbrunsfeld <max@zed.dev> Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
a9de9e3cb4
commit
8f75fe25e5
28 changed files with 1132 additions and 753 deletions
48
Cargo.lock
generated
48
Cargo.lock
generated
|
@ -2024,6 +2024,24 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "buffer_diff"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures 0.3.31",
|
||||
"git2",
|
||||
"gpui",
|
||||
"language",
|
||||
"pretty_assertions",
|
||||
"rope",
|
||||
"serde_json",
|
||||
"sum_tree",
|
||||
"text",
|
||||
"unindent",
|
||||
"util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "built"
|
||||
version = "0.7.5"
|
||||
|
@ -2742,6 +2760,7 @@ dependencies = [
|
|||
"axum",
|
||||
"axum-extra",
|
||||
"base64 0.22.1",
|
||||
"buffer_diff",
|
||||
"call",
|
||||
"channel",
|
||||
"chrono",
|
||||
|
@ -2753,7 +2772,6 @@ dependencies = [
|
|||
"ctor",
|
||||
"dashmap 6.1.0",
|
||||
"derive_more",
|
||||
"diff 0.1.0",
|
||||
"editor",
|
||||
"env_logger 0.11.6",
|
||||
"envy",
|
||||
|
@ -3860,24 +3878,6 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"futures 0.3.31",
|
||||
"git2",
|
||||
"gpui",
|
||||
"language",
|
||||
"log",
|
||||
"pretty_assertions",
|
||||
"rope",
|
||||
"serde_json",
|
||||
"sum_tree",
|
||||
"text",
|
||||
"unindent",
|
||||
"util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.13"
|
||||
|
@ -4041,6 +4041,7 @@ dependencies = [
|
|||
"aho-corasick",
|
||||
"anyhow",
|
||||
"assets",
|
||||
"buffer_diff",
|
||||
"chrono",
|
||||
"client",
|
||||
"clock",
|
||||
|
@ -4048,7 +4049,6 @@ dependencies = [
|
|||
"convert_case 0.7.1",
|
||||
"ctor",
|
||||
"db",
|
||||
"diff 0.1.0",
|
||||
"emojis",
|
||||
"env_logger 0.11.6",
|
||||
"file_icons",
|
||||
|
@ -5347,9 +5347,9 @@ name = "git_ui"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"buffer_diff",
|
||||
"collections",
|
||||
"db",
|
||||
"diff 0.1.0",
|
||||
"editor",
|
||||
"feature_flags",
|
||||
"futures 0.3.31",
|
||||
|
@ -7980,10 +7980,10 @@ name = "multi_buffer"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"buffer_diff",
|
||||
"clock",
|
||||
"collections",
|
||||
"ctor",
|
||||
"diff 0.1.0",
|
||||
"env_logger 0.11.6",
|
||||
"futures 0.3.31",
|
||||
"gpui",
|
||||
|
@ -9995,7 +9995,7 @@ version = "1.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
|
||||
dependencies = [
|
||||
"diff 0.1.13",
|
||||
"diff",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
|
@ -10088,10 +10088,10 @@ dependencies = [
|
|||
"aho-corasick",
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"buffer_diff",
|
||||
"client",
|
||||
"clock",
|
||||
"collections",
|
||||
"diff 0.1.0",
|
||||
"env_logger 0.11.6",
|
||||
"fancy-regex 0.14.0",
|
||||
"fs",
|
||||
|
|
|
@ -34,7 +34,7 @@ members = [
|
|||
"crates/db",
|
||||
"crates/deepseek",
|
||||
"crates/diagnostics",
|
||||
"crates/diff",
|
||||
"crates/buffer_diff",
|
||||
"crates/docs_preprocessor",
|
||||
"crates/editor",
|
||||
"crates/evals",
|
||||
|
@ -235,7 +235,7 @@ copilot = { path = "crates/copilot" }
|
|||
db = { path = "crates/db" }
|
||||
deepseek = { path = "crates/deepseek" }
|
||||
diagnostics = { path = "crates/diagnostics" }
|
||||
diff = { path = "crates/diff" }
|
||||
buffer_diff = { path = "crates/buffer_diff" }
|
||||
editor = { path = "crates/editor" }
|
||||
extension = { path = "crates/extension" }
|
||||
extension_host = { path = "crates/extension_host" }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "diff"
|
||||
name = "buffer_diff"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
|
@ -9,17 +9,17 @@ license = "GPL-3.0-or-later"
|
|||
workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/diff.rs"
|
||||
path = "src/buffer_diff.rs"
|
||||
|
||||
[features]
|
||||
test-support = []
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
futures.workspace = true
|
||||
git2.workspace = true
|
||||
gpui.workspace = true
|
||||
language.workspace = true
|
||||
log.workspace = true
|
||||
rope.workspace = true
|
||||
sum_tree.workspace = true
|
||||
text.workspace = true
|
||||
|
@ -29,4 +29,5 @@ util.workspace = true
|
|||
pretty_assertions.workspace = true
|
||||
serde_json.workspace = true
|
||||
text = { workspace = true, features = ["test-support"] }
|
||||
gpui = { workspace = true, features = ["test-support"] }
|
||||
unindent.workspace = true
|
File diff suppressed because it is too large
Load diff
|
@ -33,7 +33,7 @@ clock.workspace = true
|
|||
collections.workspace = true
|
||||
dashmap.workspace = true
|
||||
derive_more.workspace = true
|
||||
diff.workspace = true
|
||||
buffer_diff.workspace = true
|
||||
envy = "0.4.2"
|
||||
futures.workspace = true
|
||||
google_ai.workspace = true
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::{
|
|||
use anyhow::{anyhow, Result};
|
||||
use assistant_context_editor::ContextStore;
|
||||
use assistant_slash_command::SlashCommandWorkingSet;
|
||||
use buffer_diff::{assert_hunks, DiffHunkSecondaryStatus, DiffHunkStatus};
|
||||
use call::{room, ActiveCall, ParticipantLocation, Room};
|
||||
use client::{User, RECEIVE_TIMEOUT};
|
||||
use collections::{HashMap, HashSet};
|
||||
|
@ -2613,11 +2614,11 @@ async fn test_git_diff_base_change(
|
|||
diff.base_text_string().as_deref(),
|
||||
Some(staged_text.as_str())
|
||||
);
|
||||
diff::assert_hunks(
|
||||
diff.snapshot.hunks_in_row_range(0..4, buffer),
|
||||
assert_hunks(
|
||||
diff.hunks_in_row_range(0..4, buffer, cx),
|
||||
buffer,
|
||||
&diff.base_text_string().unwrap(),
|
||||
&[(1..2, "", "two\n")],
|
||||
&[(1..2, "", "two\n", DiffHunkStatus::added())],
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -2641,11 +2642,11 @@ async fn test_git_diff_base_change(
|
|||
diff.base_text_string().as_deref(),
|
||||
Some(staged_text.as_str())
|
||||
);
|
||||
diff::assert_hunks(
|
||||
diff.snapshot.hunks_in_row_range(0..4, buffer),
|
||||
assert_hunks(
|
||||
diff.hunks_in_row_range(0..4, buffer, cx),
|
||||
buffer,
|
||||
&diff.base_text_string().unwrap(),
|
||||
&[(1..2, "", "two\n")],
|
||||
&[(1..2, "", "two\n", DiffHunkStatus::added())],
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -2663,11 +2664,16 @@ async fn test_git_diff_base_change(
|
|||
diff.base_text_string().as_deref(),
|
||||
Some(committed_text.as_str())
|
||||
);
|
||||
diff::assert_hunks(
|
||||
diff.snapshot.hunks_in_row_range(0..4, buffer),
|
||||
assert_hunks(
|
||||
diff.hunks_in_row_range(0..4, buffer, cx),
|
||||
buffer,
|
||||
&diff.base_text_string().unwrap(),
|
||||
&[(1..2, "TWO\n", "two\n")],
|
||||
&[(
|
||||
1..2,
|
||||
"TWO\n",
|
||||
"two\n",
|
||||
DiffHunkStatus::Modified(DiffHunkSecondaryStatus::HasSecondaryHunk),
|
||||
)],
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -2689,11 +2695,11 @@ async fn test_git_diff_base_change(
|
|||
diff.base_text_string().as_deref(),
|
||||
Some(new_staged_text.as_str())
|
||||
);
|
||||
diff::assert_hunks(
|
||||
diff.snapshot.hunks_in_row_range(0..4, buffer),
|
||||
assert_hunks(
|
||||
diff.hunks_in_row_range(0..4, buffer, cx),
|
||||
buffer,
|
||||
&diff.base_text_string().unwrap(),
|
||||
&[(2..3, "", "three\n")],
|
||||
&[(2..3, "", "three\n", DiffHunkStatus::added())],
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -2703,11 +2709,11 @@ async fn test_git_diff_base_change(
|
|||
diff.base_text_string().as_deref(),
|
||||
Some(new_staged_text.as_str())
|
||||
);
|
||||
diff::assert_hunks(
|
||||
diff.snapshot.hunks_in_row_range(0..4, buffer),
|
||||
assert_hunks(
|
||||
diff.hunks_in_row_range(0..4, buffer, cx),
|
||||
buffer,
|
||||
&diff.base_text_string().unwrap(),
|
||||
&[(2..3, "", "three\n")],
|
||||
&[(2..3, "", "three\n", DiffHunkStatus::added())],
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -2717,11 +2723,16 @@ async fn test_git_diff_base_change(
|
|||
diff.base_text_string().as_deref(),
|
||||
Some(new_committed_text.as_str())
|
||||
);
|
||||
diff::assert_hunks(
|
||||
diff.snapshot.hunks_in_row_range(0..4, buffer),
|
||||
assert_hunks(
|
||||
diff.hunks_in_row_range(0..4, buffer, cx),
|
||||
buffer,
|
||||
&diff.base_text_string().unwrap(),
|
||||
&[(1..2, "TWO_HUNDRED\n", "two\n")],
|
||||
&[(
|
||||
1..2,
|
||||
"TWO_HUNDRED\n",
|
||||
"two\n",
|
||||
DiffHunkStatus::Modified(DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk),
|
||||
)],
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -2763,11 +2774,11 @@ async fn test_git_diff_base_change(
|
|||
diff.base_text_string().as_deref(),
|
||||
Some(staged_text.as_str())
|
||||
);
|
||||
diff::assert_hunks(
|
||||
diff.snapshot.hunks_in_row_range(0..4, buffer),
|
||||
assert_hunks(
|
||||
diff.hunks_in_row_range(0..4, buffer, cx),
|
||||
buffer,
|
||||
&diff.base_text_string().unwrap(),
|
||||
&[(1..2, "", "two\n")],
|
||||
&[(1..2, "", "two\n", DiffHunkStatus::added())],
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -2790,11 +2801,11 @@ async fn test_git_diff_base_change(
|
|||
diff.base_text_string().as_deref(),
|
||||
Some(staged_text.as_str())
|
||||
);
|
||||
diff::assert_hunks(
|
||||
diff.snapshot.hunks_in_row_range(0..4, buffer),
|
||||
assert_hunks(
|
||||
diff.hunks_in_row_range(0..4, buffer, cx),
|
||||
buffer,
|
||||
&staged_text,
|
||||
&[(1..2, "", "two\n")],
|
||||
&[(1..2, "", "two\n", DiffHunkStatus::added())],
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -2812,11 +2823,11 @@ async fn test_git_diff_base_change(
|
|||
diff.base_text_string().as_deref(),
|
||||
Some(new_staged_text.as_str())
|
||||
);
|
||||
diff::assert_hunks(
|
||||
diff.snapshot.hunks_in_row_range(0..4, buffer),
|
||||
assert_hunks(
|
||||
diff.hunks_in_row_range(0..4, buffer, cx),
|
||||
buffer,
|
||||
&new_staged_text,
|
||||
&[(2..3, "", "three\n")],
|
||||
&[(2..3, "", "three\n", DiffHunkStatus::added())],
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -2826,11 +2837,11 @@ async fn test_git_diff_base_change(
|
|||
diff.base_text_string().as_deref(),
|
||||
Some(new_staged_text.as_str())
|
||||
);
|
||||
diff::assert_hunks(
|
||||
diff.snapshot.hunks_in_row_range(0..4, buffer),
|
||||
assert_hunks(
|
||||
diff.hunks_in_row_range(0..4, buffer, cx),
|
||||
buffer,
|
||||
&new_staged_text,
|
||||
&[(2..3, "", "three\n")],
|
||||
&[(2..3, "", "three\n", DiffHunkStatus::added())],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ clock.workspace = true
|
|||
collections.workspace = true
|
||||
convert_case.workspace = true
|
||||
db.workspace = true
|
||||
diff.workspace = true
|
||||
buffer_diff.workspace = true
|
||||
emojis.workspace = true
|
||||
file_icons.workspace = true
|
||||
futures.workspace = true
|
||||
|
|
|
@ -73,17 +73,16 @@ use code_context_menus::{
|
|||
AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
|
||||
CompletionsMenu, ContextMenuOrigin,
|
||||
};
|
||||
use diff::DiffHunkStatus;
|
||||
use git::blame::GitBlame;
|
||||
use gpui::{
|
||||
div, impl_actions, linear_color_stop, linear_gradient, point, prelude::*, pulsating_between,
|
||||
px, relative, size, Action, Animation, AnimationExt, AnyElement, App, AsyncWindowContext,
|
||||
AvailableSpace, Bounds, ClipboardEntry, ClipboardItem, Context, DispatchPhase, ElementId,
|
||||
Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent, Focusable, FontId,
|
||||
FontWeight, Global, HighlightStyle, Hsla, InteractiveText, KeyContext, Modifiers, MouseButton,
|
||||
MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, SharedString, Size, Styled,
|
||||
StyledText, Subscription, Task, TextRun, TextStyle, TextStyleRefinement, UTF16Selection,
|
||||
UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
|
||||
AvailableSpace, Background, Bounds, ClipboardEntry, ClipboardItem, Context, DispatchPhase,
|
||||
ElementId, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent, Focusable,
|
||||
FontId, FontWeight, Global, HighlightStyle, Hsla, InteractiveText, KeyContext, Modifiers,
|
||||
MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, SharedString, Size,
|
||||
Styled, StyledText, Subscription, Task, TextRun, TextStyle, TextStyleRefinement,
|
||||
UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
|
||||
};
|
||||
use highlight_matching_bracket::refresh_matching_bracket_highlights;
|
||||
use hover_popover::{hide_hover, HoverState};
|
||||
|
@ -722,6 +721,7 @@ pub struct Editor {
|
|||
show_git_blame_gutter: bool,
|
||||
show_git_blame_inline: bool,
|
||||
show_git_blame_inline_delay_task: Option<Task<()>>,
|
||||
distinguish_unstaged_diff_hunks: bool,
|
||||
git_blame_inline_enabled: bool,
|
||||
serialize_dirty_buffers: bool,
|
||||
show_selection_menu: Option<bool>,
|
||||
|
@ -1418,6 +1418,7 @@ impl Editor {
|
|||
custom_context_menu: None,
|
||||
show_git_blame_gutter: false,
|
||||
show_git_blame_inline: false,
|
||||
distinguish_unstaged_diff_hunks: false,
|
||||
show_selection_menu: None,
|
||||
show_git_blame_inline_delay_task: None,
|
||||
git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
|
||||
|
@ -6878,8 +6879,7 @@ impl Editor {
|
|||
let buffer = buffer.read(cx);
|
||||
let original_text = diff
|
||||
.read(cx)
|
||||
.snapshot
|
||||
.base_text
|
||||
.base_text()
|
||||
.as_ref()?
|
||||
.as_rope()
|
||||
.slice(hunk.diff_base_byte_range.clone());
|
||||
|
@ -12290,6 +12290,10 @@ impl Editor {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn set_distinguish_unstaged_diff_hunks(&mut self) {
|
||||
self.distinguish_unstaged_diff_hunks = true;
|
||||
}
|
||||
|
||||
pub fn expand_all_diff_hunks(
|
||||
&mut self,
|
||||
_: &ExpandAllHunkDiffs,
|
||||
|
@ -13332,14 +13336,14 @@ impl Editor {
|
|||
&self,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> BTreeMap<DisplayRow, Hsla> {
|
||||
) -> BTreeMap<DisplayRow, Background> {
|
||||
let snapshot = self.snapshot(window, cx);
|
||||
let mut used_highlight_orders = HashMap::default();
|
||||
self.highlighted_rows
|
||||
.iter()
|
||||
.flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
|
||||
.fold(
|
||||
BTreeMap::<DisplayRow, Hsla>::new(),
|
||||
BTreeMap::<DisplayRow, Background>::new(),
|
||||
|mut unique_rows, highlight| {
|
||||
let start = highlight.range.start.to_display_point(&snapshot);
|
||||
let end = highlight.range.end.to_display_point(&snapshot);
|
||||
|
@ -13356,7 +13360,7 @@ impl Editor {
|
|||
used_highlight_orders.entry(row).or_insert(highlight.index);
|
||||
if highlight.index >= *used_index {
|
||||
*used_index = highlight.index;
|
||||
unique_rows.insert(DisplayRow(row), highlight.color);
|
||||
unique_rows.insert(DisplayRow(row), highlight.color.into());
|
||||
}
|
||||
}
|
||||
unique_rows
|
||||
|
@ -15518,7 +15522,7 @@ impl EditorSnapshot {
|
|||
) {
|
||||
// Deleted hunk is an empty row range, no caret can be placed there and Zed allows to revert it
|
||||
// when the caret is just above or just below the deleted hunk.
|
||||
let allow_adjacent = hunk.status() == DiffHunkStatus::Removed;
|
||||
let allow_adjacent = hunk.status().is_removed();
|
||||
let related_to_selection = if allow_adjacent {
|
||||
hunk.row_range.overlaps(&query_rows)
|
||||
|| hunk.row_range.start == query_rows.end
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
},
|
||||
JoinLines,
|
||||
};
|
||||
use diff::{BufferDiff, DiffHunkStatus};
|
||||
use buffer_diff::{BufferDiff, DiffHunkStatus};
|
||||
use futures::StreamExt;
|
||||
use gpui::{
|
||||
div, BackgroundExecutor, SemanticVersion, TestAppContext, UpdateGlobal, VisualTestContext,
|
||||
|
@ -11989,7 +11989,7 @@ async fn test_addition_reverts(cx: &mut gpui::TestAppContext) {
|
|||
struct Row9.2;
|
||||
struct Row9.3;
|
||||
struct Row10;"#},
|
||||
vec![DiffHunkStatus::Added, DiffHunkStatus::Added],
|
||||
vec![DiffHunkStatus::added(), DiffHunkStatus::added()],
|
||||
indoc! {r#"struct Row;
|
||||
struct Row1;
|
||||
struct Row1.1;
|
||||
|
@ -12027,7 +12027,7 @@ async fn test_addition_reverts(cx: &mut gpui::TestAppContext) {
|
|||
struct Row8;
|
||||
struct Row9;
|
||||
struct Row10;"#},
|
||||
vec![DiffHunkStatus::Added, DiffHunkStatus::Added],
|
||||
vec![DiffHunkStatus::added(), DiffHunkStatus::added()],
|
||||
indoc! {r#"struct Row;
|
||||
struct Row1;
|
||||
struct Row2;
|
||||
|
@ -12074,11 +12074,11 @@ async fn test_addition_reverts(cx: &mut gpui::TestAppContext) {
|
|||
«ˇ// something on bottom»
|
||||
struct Row10;"#},
|
||||
vec![
|
||||
DiffHunkStatus::Added,
|
||||
DiffHunkStatus::Added,
|
||||
DiffHunkStatus::Added,
|
||||
DiffHunkStatus::Added,
|
||||
DiffHunkStatus::Added,
|
||||
DiffHunkStatus::added(),
|
||||
DiffHunkStatus::added(),
|
||||
DiffHunkStatus::added(),
|
||||
DiffHunkStatus::added(),
|
||||
DiffHunkStatus::added(),
|
||||
],
|
||||
indoc! {r#"struct Row;
|
||||
ˇstruct Row1;
|
||||
|
@ -12126,7 +12126,7 @@ async fn test_modification_reverts(cx: &mut gpui::TestAppContext) {
|
|||
struct Row99;
|
||||
struct Row9;
|
||||
struct Row10;"#},
|
||||
vec![DiffHunkStatus::Modified, DiffHunkStatus::Modified],
|
||||
vec![DiffHunkStatus::modified(), DiffHunkStatus::modified()],
|
||||
indoc! {r#"struct Row;
|
||||
struct Row1;
|
||||
struct Row33;
|
||||
|
@ -12153,7 +12153,7 @@ async fn test_modification_reverts(cx: &mut gpui::TestAppContext) {
|
|||
struct Row99;
|
||||
struct Row9;
|
||||
struct Row10;"#},
|
||||
vec![DiffHunkStatus::Modified, DiffHunkStatus::Modified],
|
||||
vec![DiffHunkStatus::modified(), DiffHunkStatus::modified()],
|
||||
indoc! {r#"struct Row;
|
||||
struct Row1;
|
||||
struct Row33;
|
||||
|
@ -12182,12 +12182,12 @@ async fn test_modification_reverts(cx: &mut gpui::TestAppContext) {
|
|||
struct Row9;
|
||||
struct Row1011;ˇ"#},
|
||||
vec![
|
||||
DiffHunkStatus::Modified,
|
||||
DiffHunkStatus::Modified,
|
||||
DiffHunkStatus::Modified,
|
||||
DiffHunkStatus::Modified,
|
||||
DiffHunkStatus::Modified,
|
||||
DiffHunkStatus::Modified,
|
||||
DiffHunkStatus::modified(),
|
||||
DiffHunkStatus::modified(),
|
||||
DiffHunkStatus::modified(),
|
||||
DiffHunkStatus::modified(),
|
||||
DiffHunkStatus::modified(),
|
||||
DiffHunkStatus::modified(),
|
||||
],
|
||||
indoc! {r#"struct Row;
|
||||
ˇstruct Row1;
|
||||
|
@ -12265,7 +12265,7 @@ struct Row10;"#};
|
|||
ˇ
|
||||
struct Row8;
|
||||
struct Row10;"#},
|
||||
vec![DiffHunkStatus::Removed, DiffHunkStatus::Removed],
|
||||
vec![DiffHunkStatus::removed(), DiffHunkStatus::removed()],
|
||||
indoc! {r#"struct Row;
|
||||
struct Row2;
|
||||
|
||||
|
@ -12288,7 +12288,7 @@ struct Row10;"#};
|
|||
ˇ»
|
||||
struct Row8;
|
||||
struct Row10;"#},
|
||||
vec![DiffHunkStatus::Removed, DiffHunkStatus::Removed],
|
||||
vec![DiffHunkStatus::removed(), DiffHunkStatus::removed()],
|
||||
indoc! {r#"struct Row;
|
||||
struct Row2;
|
||||
|
||||
|
@ -12313,7 +12313,7 @@ struct Row10;"#};
|
|||
|
||||
struct Row8;ˇ
|
||||
struct Row10;"#},
|
||||
vec![DiffHunkStatus::Removed, DiffHunkStatus::Removed],
|
||||
vec![DiffHunkStatus::removed(), DiffHunkStatus::removed()],
|
||||
indoc! {r#"struct Row;
|
||||
struct Row1;
|
||||
ˇstruct Row2;
|
||||
|
@ -12338,9 +12338,9 @@ struct Row10;"#};
|
|||
struct Row8;ˇ»
|
||||
struct Row10;"#},
|
||||
vec![
|
||||
DiffHunkStatus::Removed,
|
||||
DiffHunkStatus::Removed,
|
||||
DiffHunkStatus::Removed,
|
||||
DiffHunkStatus::removed(),
|
||||
DiffHunkStatus::removed(),
|
||||
DiffHunkStatus::removed(),
|
||||
],
|
||||
indoc! {r#"struct Row;
|
||||
struct Row1;
|
||||
|
|
|
@ -25,21 +25,21 @@ use crate::{
|
|||
EDIT_PREDICTION_REQUIRES_MODIFIER_KEY_CONTEXT, FILE_HEADER_HEIGHT,
|
||||
GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN, MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
|
||||
};
|
||||
use buffer_diff::{DiffHunkSecondaryStatus, DiffHunkStatus};
|
||||
use client::ParticipantIndex;
|
||||
use collections::{BTreeMap, HashMap, HashSet};
|
||||
use diff::DiffHunkStatus;
|
||||
use file_icons::FileIcons;
|
||||
use git::{blame::BlameEntry, Oid};
|
||||
use gpui::{
|
||||
anchored, deferred, div, fill, linear_color_stop, linear_gradient, outline, point, px, quad,
|
||||
relative, size, svg, transparent_black, Action, AnyElement, App, AvailableSpace, Axis, Bounds,
|
||||
ClickEvent, ClipboardItem, ContentMask, Context, Corner, Corners, CursorStyle, DispatchPhase,
|
||||
Edges, Element, ElementInputHandler, Entity, Focusable as _, FontId, GlobalElementId, Hitbox,
|
||||
Hsla, InteractiveElement, IntoElement, KeyBindingContextPredicate, Keystroke, Length,
|
||||
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad,
|
||||
ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString, Size,
|
||||
StatefulInteractiveElement, Style, Styled, Subscription, TextRun, TextStyleRefinement,
|
||||
WeakEntity, Window,
|
||||
anchored, deferred, div, fill, linear_color_stop, linear_gradient, outline, pattern_slash,
|
||||
point, px, quad, relative, size, svg, transparent_black, Action, AnyElement, App,
|
||||
AvailableSpace, Axis, Bounds, ClickEvent, ClipboardItem, ContentMask, Context, Corner, Corners,
|
||||
CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity, Focusable as _,
|
||||
FontId, GlobalElementId, Hitbox, Hsla, InteractiveElement, IntoElement,
|
||||
KeyBindingContextPredicate, Keystroke, Length, ModifiersChangedEvent, MouseButton,
|
||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, ParentElement, Pixels, ScrollDelta,
|
||||
ScrollWheelEvent, ShapedLine, SharedString, Size, StatefulInteractiveElement, Style, Styled,
|
||||
Subscription, TextRun, TextStyleRefinement, WeakEntity, Window,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use language::{
|
||||
|
@ -85,7 +85,6 @@ enum DisplayDiffHunk {
|
|||
Folded {
|
||||
display_row: DisplayRow,
|
||||
},
|
||||
|
||||
Unfolded {
|
||||
diff_base_byte_range: Range<usize>,
|
||||
display_row_range: Range<DisplayRow>,
|
||||
|
@ -2116,7 +2115,7 @@ impl EditorElement {
|
|||
.get(&display_row)
|
||||
.unwrap_or(&non_relative_number);
|
||||
write!(&mut line_number, "{number}").unwrap();
|
||||
if row_info.diff_status == Some(DiffHunkStatus::Removed) {
|
||||
if matches!(row_info.diff_status, Some(DiffHunkStatus::Removed(_))) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -4007,8 +4006,10 @@ impl EditorElement {
|
|||
if row_infos[row_ix].diff_status.is_none() {
|
||||
continue;
|
||||
}
|
||||
if row_infos[row_ix].diff_status == Some(DiffHunkStatus::Added)
|
||||
&& *status != DiffHunkStatus::Added
|
||||
if matches!(
|
||||
row_infos[row_ix].diff_status,
|
||||
Some(DiffHunkStatus::Added(_))
|
||||
) && !matches!(*status, DiffHunkStatus::Added(_))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -4191,26 +4192,26 @@ impl EditorElement {
|
|||
window.paint_quad(fill(Bounds { origin, size }, color));
|
||||
};
|
||||
|
||||
let mut current_paint: Option<(Hsla, Range<DisplayRow>)> = None;
|
||||
for (&new_row, &new_color) in &layout.highlighted_rows {
|
||||
let mut current_paint: Option<(gpui::Background, Range<DisplayRow>)> = None;
|
||||
for (&new_row, &new_background) in &layout.highlighted_rows {
|
||||
match &mut current_paint {
|
||||
Some((current_color, current_range)) => {
|
||||
let current_color = *current_color;
|
||||
let new_range_started = current_color != new_color
|
||||
Some((current_background, current_range)) => {
|
||||
let current_background = *current_background;
|
||||
let new_range_started = current_background != new_background
|
||||
|| current_range.end.next_row() != new_row;
|
||||
if new_range_started {
|
||||
paint_highlight(
|
||||
current_range.start,
|
||||
current_range.end,
|
||||
current_color,
|
||||
current_background,
|
||||
);
|
||||
current_paint = Some((new_color, new_row..new_row));
|
||||
current_paint = Some((new_background, new_row..new_row));
|
||||
continue;
|
||||
} else {
|
||||
current_range.end = current_range.end.next_row();
|
||||
}
|
||||
}
|
||||
None => current_paint = Some((new_color, new_row..new_row)),
|
||||
None => current_paint = Some((new_background, new_row..new_row)),
|
||||
};
|
||||
}
|
||||
if let Some((color, range)) = current_paint {
|
||||
|
@ -4409,6 +4410,7 @@ impl EditorElement {
|
|||
hunk_bounds,
|
||||
cx.theme().status().modified,
|
||||
Corners::all(px(0.)),
|
||||
&DiffHunkSecondaryStatus::None,
|
||||
))
|
||||
}
|
||||
DisplayDiffHunk::Unfolded {
|
||||
|
@ -4416,22 +4418,29 @@ impl EditorElement {
|
|||
display_row_range,
|
||||
..
|
||||
} => hitbox.as_ref().map(|hunk_hitbox| match status {
|
||||
DiffHunkStatus::Added => (
|
||||
DiffHunkStatus::Added(secondary_status) => (
|
||||
hunk_hitbox.bounds,
|
||||
cx.theme().status().created,
|
||||
Corners::all(px(0.)),
|
||||
secondary_status,
|
||||
),
|
||||
DiffHunkStatus::Modified => (
|
||||
DiffHunkStatus::Modified(secondary_status) => (
|
||||
hunk_hitbox.bounds,
|
||||
cx.theme().status().modified,
|
||||
Corners::all(px(0.)),
|
||||
secondary_status,
|
||||
),
|
||||
DiffHunkStatus::Removed if !display_row_range.is_empty() => (
|
||||
hunk_hitbox.bounds,
|
||||
cx.theme().status().deleted,
|
||||
Corners::all(px(0.)),
|
||||
),
|
||||
DiffHunkStatus::Removed => (
|
||||
DiffHunkStatus::Removed(secondary_status)
|
||||
if !display_row_range.is_empty() =>
|
||||
{
|
||||
(
|
||||
hunk_hitbox.bounds,
|
||||
cx.theme().status().deleted,
|
||||
Corners::all(px(0.)),
|
||||
secondary_status,
|
||||
)
|
||||
}
|
||||
DiffHunkStatus::Removed(secondary_status) => (
|
||||
Bounds::new(
|
||||
point(
|
||||
hunk_hitbox.origin.x - hunk_hitbox.size.width,
|
||||
|
@ -4441,11 +4450,17 @@ impl EditorElement {
|
|||
),
|
||||
cx.theme().status().deleted,
|
||||
Corners::all(1. * line_height),
|
||||
secondary_status,
|
||||
),
|
||||
}),
|
||||
};
|
||||
|
||||
if let Some((hunk_bounds, background_color, corner_radii)) = hunk_to_paint {
|
||||
if let Some((hunk_bounds, mut background_color, corner_radii, secondary_status)) =
|
||||
hunk_to_paint
|
||||
{
|
||||
if *secondary_status != DiffHunkSecondaryStatus::None {
|
||||
background_color.a *= 0.6;
|
||||
}
|
||||
window.paint_quad(quad(
|
||||
hunk_bounds,
|
||||
corner_radii,
|
||||
|
@ -4481,7 +4496,7 @@ impl EditorElement {
|
|||
status,
|
||||
..
|
||||
} => {
|
||||
if *status == DiffHunkStatus::Removed && display_row_range.is_empty() {
|
||||
if status.is_removed() && display_row_range.is_empty() {
|
||||
let row = display_row_range.start;
|
||||
|
||||
let offset = line_height / 2.;
|
||||
|
@ -5128,9 +5143,9 @@ impl EditorElement {
|
|||
end_display_row.0 -= 1;
|
||||
}
|
||||
let color = match &hunk.status() {
|
||||
DiffHunkStatus::Added => theme.status().created,
|
||||
DiffHunkStatus::Modified => theme.status().modified,
|
||||
DiffHunkStatus::Removed => theme.status().deleted,
|
||||
DiffHunkStatus::Added(_) => theme.status().created,
|
||||
DiffHunkStatus::Modified(_) => theme.status().modified,
|
||||
DiffHunkStatus::Removed(_) => theme.status().deleted,
|
||||
};
|
||||
ColoredRange {
|
||||
start: start_display_row,
|
||||
|
@ -6798,19 +6813,46 @@ impl Element for EditorElement {
|
|||
)
|
||||
};
|
||||
|
||||
let mut highlighted_rows = self
|
||||
.editor
|
||||
.update(cx, |editor, cx| editor.highlighted_display_rows(window, cx));
|
||||
let (mut highlighted_rows, distinguish_unstaged_hunks) =
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
(
|
||||
editor.highlighted_display_rows(window, cx),
|
||||
editor.distinguish_unstaged_diff_hunks,
|
||||
)
|
||||
});
|
||||
|
||||
for (ix, row_info) in row_infos.iter().enumerate() {
|
||||
let color = match row_info.diff_status {
|
||||
Some(DiffHunkStatus::Added) => style.status.created_background,
|
||||
Some(DiffHunkStatus::Removed) => style.status.deleted_background,
|
||||
let background = match row_info.diff_status {
|
||||
Some(DiffHunkStatus::Added(secondary_status)) => {
|
||||
let color = style.status.created_background;
|
||||
match secondary_status {
|
||||
DiffHunkSecondaryStatus::HasSecondaryHunk
|
||||
| DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk
|
||||
if distinguish_unstaged_hunks =>
|
||||
{
|
||||
pattern_slash(color, line_height.0 / 4.0)
|
||||
}
|
||||
_ => color.into(),
|
||||
}
|
||||
}
|
||||
Some(DiffHunkStatus::Removed(secondary_status)) => {
|
||||
let color = style.status.deleted_background;
|
||||
match secondary_status {
|
||||
DiffHunkSecondaryStatus::HasSecondaryHunk
|
||||
| DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk
|
||||
if distinguish_unstaged_hunks =>
|
||||
{
|
||||
pattern_slash(color, line_height.0 / 4.0)
|
||||
}
|
||||
_ => color.into(),
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
highlighted_rows
|
||||
.entry(start_row + DisplayRow(ix as u32))
|
||||
.or_insert(color);
|
||||
.or_insert(background);
|
||||
}
|
||||
|
||||
let highlighted_ranges = self.editor.read(cx).background_highlights_in_range(
|
||||
|
@ -7643,7 +7685,7 @@ pub struct EditorLayout {
|
|||
indent_guides: Option<Vec<IndentGuideLayout>>,
|
||||
visible_display_row_range: Range<DisplayRow>,
|
||||
active_rows: BTreeMap<DisplayRow, bool>,
|
||||
highlighted_rows: BTreeMap<DisplayRow, Hsla>,
|
||||
highlighted_rows: BTreeMap<DisplayRow, gpui::Background>,
|
||||
line_elements: SmallVec<[AnyElement; 1]>,
|
||||
line_numbers: Arc<HashMap<MultiBufferRow, LineNumberLayout>>,
|
||||
display_hunks: Vec<(DisplayDiffHunk, Option<Hitbox>)>,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{ApplyAllDiffHunks, Editor, EditorEvent, SemanticsProvider};
|
||||
use buffer_diff::BufferDiff;
|
||||
use collections::HashSet;
|
||||
use diff::BufferDiff;
|
||||
use futures::{channel::mpsc, future::join_all};
|
||||
use gpui::{App, Entity, EventEmitter, Focusable, Render, Subscription, Task};
|
||||
use language::{Buffer, BufferEvent, Capability};
|
||||
|
@ -185,7 +185,7 @@ impl ProposedChangesEditor {
|
|||
} else {
|
||||
branch_buffer = location.buffer.update(cx, |buffer, cx| buffer.branch(cx));
|
||||
new_diffs.push(cx.new(|cx| {
|
||||
let mut diff = BufferDiff::new(&branch_buffer, cx);
|
||||
let mut diff = BufferDiff::new(branch_buffer.read(cx));
|
||||
let _ = diff.set_base_text(
|
||||
location.buffer.clone(),
|
||||
branch_buffer.read(cx).text_snapshot(),
|
||||
|
|
|
@ -2,8 +2,8 @@ use crate::{
|
|||
display_map::ToDisplayPoint, AnchorRangeExt, Autoscroll, DisplayPoint, Editor, MultiBuffer,
|
||||
RowExt,
|
||||
};
|
||||
use buffer_diff::DiffHunkStatus;
|
||||
use collections::BTreeMap;
|
||||
use diff::DiffHunkStatus;
|
||||
use futures::Future;
|
||||
|
||||
use gpui::{
|
||||
|
@ -459,9 +459,9 @@ pub fn assert_state_with_diff(
|
|||
.zip(line_infos)
|
||||
.map(|(line, info)| {
|
||||
let mut marker = match info.diff_status {
|
||||
Some(DiffHunkStatus::Added) => "+ ",
|
||||
Some(DiffHunkStatus::Removed) => "- ",
|
||||
Some(DiffHunkStatus::Modified) => unreachable!(),
|
||||
Some(DiffHunkStatus::Added(_)) => "+ ",
|
||||
Some(DiffHunkStatus::Removed(_)) => "- ",
|
||||
Some(DiffHunkStatus::Modified(_)) => unreachable!(),
|
||||
None => {
|
||||
if has_diff {
|
||||
" "
|
||||
|
|
|
@ -16,7 +16,7 @@ path = "src/git_ui.rs"
|
|||
anyhow.workspace = true
|
||||
collections.workspace = true
|
||||
db.workspace = true
|
||||
diff.workspace = true
|
||||
buffer_diff.workspace = true
|
||||
editor.workspace = true
|
||||
feature_flags.workspace = true
|
||||
futures.workspace = true
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::any::{Any, TypeId};
|
||||
|
||||
use anyhow::Result;
|
||||
use buffer_diff::BufferDiff;
|
||||
use collections::HashSet;
|
||||
use diff::BufferDiff;
|
||||
use editor::{scroll::Autoscroll, Editor, EditorEvent};
|
||||
use feature_flags::FeatureFlagViewExt;
|
||||
use futures::StreamExt;
|
||||
|
@ -126,6 +126,7 @@ impl ProjectDiff {
|
|||
window,
|
||||
cx,
|
||||
);
|
||||
diff_display_editor.set_distinguish_unstaged_diff_hunks();
|
||||
diff_display_editor.set_expand_all_diff_hunks(cx);
|
||||
diff_display_editor.register_addon(GitPanelAddon {
|
||||
git_panel: git_panel.clone(),
|
||||
|
@ -317,10 +318,10 @@ impl ProjectDiff {
|
|||
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
let diff = diff.read(cx);
|
||||
let diff_hunk_ranges = if diff.snapshot.base_text.is_none() {
|
||||
let diff_hunk_ranges = if diff.base_text().is_none() {
|
||||
vec![Point::zero()..snapshot.max_point()]
|
||||
} else {
|
||||
diff.diff_hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot)
|
||||
diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot, cx)
|
||||
.map(|diff_hunk| diff_hunk.buffer_range.to_point(&snapshot))
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
|
|
@ -25,10 +25,30 @@ impl Render for PatternExample {
|
|||
.flex_col()
|
||||
.border_1()
|
||||
.border_color(gpui::blue())
|
||||
.child(div().w(px(54.0)).h(px(18.0)).bg(pattern_slash(gpui::red())))
|
||||
.child(div().w(px(54.0)).h(px(18.0)).bg(pattern_slash(gpui::red())))
|
||||
.child(div().w(px(54.0)).h(px(18.0)).bg(pattern_slash(gpui::red())))
|
||||
.child(div().w(px(54.0)).h(px(18.0)).bg(pattern_slash(gpui::red()))),
|
||||
.child(
|
||||
div()
|
||||
.w(px(54.0))
|
||||
.h(px(18.0))
|
||||
.bg(pattern_slash(gpui::red(), 18.0 / 2.0)),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.w(px(54.0))
|
||||
.h(px(18.0))
|
||||
.bg(pattern_slash(gpui::red(), 18.0 / 2.0)),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.w(px(54.0))
|
||||
.h(px(18.0))
|
||||
.bg(pattern_slash(gpui::red(), 18.0 / 2.0)),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.w(px(54.0))
|
||||
.h(px(18.0))
|
||||
.bg(pattern_slash(gpui::red(), 18.0 / 2.0)),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
|
@ -42,25 +62,25 @@ impl Render for PatternExample {
|
|||
div()
|
||||
.w(px(256.0))
|
||||
.h(px(56.0))
|
||||
.bg(pattern_slash(gpui::red())),
|
||||
.bg(pattern_slash(gpui::red(), 56.0 / 3.0)),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.w(px(256.0))
|
||||
.h(px(56.0))
|
||||
.bg(pattern_slash(gpui::green())),
|
||||
.bg(pattern_slash(gpui::green(), 56.0 / 3.0)),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.w(px(256.0))
|
||||
.h(px(56.0))
|
||||
.bg(pattern_slash(gpui::blue())),
|
||||
.bg(pattern_slash(gpui::blue(), 56.0 / 3.0)),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.w(px(256.0))
|
||||
.h(px(26.0))
|
||||
.bg(pattern_slash(gpui::yellow())),
|
||||
.bg(pattern_slash(gpui::yellow(), 56.0 / 3.0)),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
|
|
|
@ -587,7 +587,7 @@ pub struct Background {
|
|||
pub(crate) tag: BackgroundTag,
|
||||
pub(crate) color_space: ColorSpace,
|
||||
pub(crate) solid: Hsla,
|
||||
pub(crate) angle: f32,
|
||||
pub(crate) gradient_angle_or_pattern_height: f32,
|
||||
pub(crate) colors: [LinearColorStop; 2],
|
||||
/// Padding for alignment for repr(C) layout.
|
||||
pad: u32,
|
||||
|
@ -600,7 +600,7 @@ impl Default for Background {
|
|||
tag: BackgroundTag::Solid,
|
||||
solid: Hsla::default(),
|
||||
color_space: ColorSpace::default(),
|
||||
angle: 0.0,
|
||||
gradient_angle_or_pattern_height: 0.0,
|
||||
colors: [LinearColorStop::default(), LinearColorStop::default()],
|
||||
pad: 0,
|
||||
}
|
||||
|
@ -608,10 +608,11 @@ impl Default for Background {
|
|||
}
|
||||
|
||||
/// Creates a hash pattern background
|
||||
pub fn pattern_slash(color: Hsla) -> Background {
|
||||
pub fn pattern_slash(color: Hsla, thickness: f32) -> Background {
|
||||
Background {
|
||||
tag: BackgroundTag::PatternSlash,
|
||||
solid: color,
|
||||
gradient_angle_or_pattern_height: thickness,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
@ -630,7 +631,7 @@ pub fn linear_gradient(
|
|||
) -> Background {
|
||||
Background {
|
||||
tag: BackgroundTag::LinearGradient,
|
||||
angle,
|
||||
gradient_angle_or_pattern_height: angle,
|
||||
colors: [from.into(), to.into()],
|
||||
..Default::default()
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ struct Background {
|
|||
// 1u is Oklab color
|
||||
color_space: u32,
|
||||
solid: Hsla,
|
||||
angle: f32,
|
||||
gradient_angle_or_pattern_height: f32,
|
||||
colors: array<LinearColorStop, 2>,
|
||||
pad: u32,
|
||||
}
|
||||
|
@ -310,17 +310,18 @@ fn prepare_gradient_color(tag: u32, color_space: u32,
|
|||
}
|
||||
|
||||
fn gradient_color(background: Background, position: vec2<f32>, bounds: Bounds,
|
||||
sold_color: vec4<f32>, color0: vec4<f32>, color1: vec4<f32>) -> vec4<f32> {
|
||||
solid_color: vec4<f32>, color0: vec4<f32>, color1: vec4<f32>) -> vec4<f32> {
|
||||
var background_color = vec4<f32>(0.0);
|
||||
|
||||
switch (background.tag) {
|
||||
default: {
|
||||
return sold_color;
|
||||
return solid_color;
|
||||
}
|
||||
case 1u: {
|
||||
// Linear gradient background.
|
||||
// -90 degrees to match the CSS gradient angle.
|
||||
let radians = (background.angle % 360.0 - 90.0) * M_PI_F / 180.0;
|
||||
let angle = background.gradient_angle_or_pattern_height;
|
||||
let radians = (angle % 360.0 - 90.0) * M_PI_F / 180.0;
|
||||
var direction = vec2<f32>(cos(radians), sin(radians));
|
||||
let stop0_percentage = background.colors[0].percentage;
|
||||
let stop1_percentage = background.colors[1].percentage;
|
||||
|
@ -359,19 +360,18 @@ fn gradient_color(background: Background, position: vec2<f32>, bounds: Bounds,
|
|||
}
|
||||
}
|
||||
case 2u: {
|
||||
let base_pattern_size = bounds.size.y / 5.0;
|
||||
let width = base_pattern_size * 0.5;
|
||||
let slash_spacing = 0.89;
|
||||
let radians = M_PI_F / 4.0;
|
||||
let pattern_height = background.gradient_angle_or_pattern_height;
|
||||
let stripe_angle = M_PI_F / 4.0;
|
||||
let pattern_period = pattern_height * sin(stripe_angle);
|
||||
let rotation = mat2x2<f32>(
|
||||
cos(radians), -sin(radians),
|
||||
sin(radians), cos(radians)
|
||||
cos(stripe_angle), -sin(stripe_angle),
|
||||
sin(stripe_angle), cos(stripe_angle)
|
||||
);
|
||||
let relative_position = position - bounds.origin;
|
||||
let rotated_point = rotation * relative_position;
|
||||
let pattern = (rotated_point.x / slash_spacing) % (base_pattern_size * 2.0);
|
||||
let distance = min(pattern, base_pattern_size * 2.0 - pattern) - width;
|
||||
background_color = sold_color;
|
||||
let pattern = rotated_point.x % pattern_period;
|
||||
let distance = min(pattern, pattern_period - pattern) - pattern_period / 4;
|
||||
background_color = solid_color;
|
||||
background_color.a *= saturate(0.5 - distance);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -833,7 +833,8 @@ float4 fill_color(Background background,
|
|||
break;
|
||||
case 1: {
|
||||
// -90 degrees to match the CSS gradient angle.
|
||||
float radians = (fmod(background.angle, 360.0) - 90.0) * (M_PI_F / 180.0);
|
||||
float gradient_angle = background.gradient_angle_or_pattern_height;
|
||||
float radians = (fmod(gradient_angle, 360.0) - 90.0) * (M_PI_F / 180.0);
|
||||
float2 direction = float2(cos(radians), sin(radians));
|
||||
|
||||
// Expand the short side to be the same as the long side
|
||||
|
@ -874,19 +875,14 @@ float4 fill_color(Background background,
|
|||
break;
|
||||
}
|
||||
case 2: {
|
||||
// This pattern is full of magic numbers to make it line up perfectly
|
||||
// when vertically stacked. Make sure you know what you are doing
|
||||
// if you change this!
|
||||
|
||||
float base_pattern_size = bounds.size.height / 5;
|
||||
float width = base_pattern_size * 0.5;
|
||||
float slash_spacing = .89;
|
||||
float radians = M_PI_F / 4.0;
|
||||
float2x2 rotation = rotate2d(radians);
|
||||
float pattern_height = background.gradient_angle_or_pattern_height;
|
||||
float stripe_angle = M_PI_F / 4.0;
|
||||
float pattern_period = pattern_height * sin(stripe_angle);
|
||||
float2x2 rotation = rotate2d(stripe_angle);
|
||||
float2 relative_position = position - float2(bounds.origin.x, bounds.origin.y);
|
||||
float2 rotated_point = rotation * relative_position;
|
||||
float pattern = fmod(rotated_point.x / slash_spacing, base_pattern_size * 2.0);
|
||||
float distance = min(pattern, base_pattern_size * 2.0 - pattern) - width;
|
||||
float pattern = fmod(rotated_point.x, pattern_period);
|
||||
float distance = min(pattern, pattern_period - pattern) - pattern_period / 4.0;
|
||||
color = solid_color;
|
||||
color.a *= saturate(0.5 - distance);
|
||||
break;
|
||||
|
|
|
@ -14,7 +14,7 @@ doctest = false
|
|||
|
||||
[features]
|
||||
test-support = [
|
||||
"diff/test-support",
|
||||
"buffer_diff/test-support",
|
||||
"gpui/test-support",
|
||||
"language/test-support",
|
||||
"text/test-support",
|
||||
|
@ -26,7 +26,7 @@ anyhow.workspace = true
|
|||
clock.workspace = true
|
||||
collections.workspace = true
|
||||
ctor.workspace = true
|
||||
diff.workspace = true
|
||||
buffer_diff.workspace = true
|
||||
env_logger.workspace = true
|
||||
futures.workspace = true
|
||||
gpui.workspace = true
|
||||
|
@ -47,7 +47,7 @@ tree-sitter.workspace = true
|
|||
util.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
diff = { workspace = true, features = ["test-support"] }
|
||||
buffer_diff = { workspace = true, features = ["test-support"] }
|
||||
gpui = { workspace = true, features = ["test-support"] }
|
||||
indoc.workspace = true
|
||||
language = { workspace = true, features = ["test-support"] }
|
||||
|
|
|
@ -73,7 +73,7 @@ impl Anchor {
|
|||
if let Some(base_text) = snapshot
|
||||
.diffs
|
||||
.get(&excerpt.buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
.and_then(|diff| diff.base_text())
|
||||
{
|
||||
let self_anchor = self.diff_base_anchor.filter(|a| base_text.can_resolve(a));
|
||||
let other_anchor = other.diff_base_anchor.filter(|a| base_text.can_resolve(a));
|
||||
|
@ -110,7 +110,7 @@ impl Anchor {
|
|||
if let Some(base_text) = snapshot
|
||||
.diffs
|
||||
.get(&excerpt.buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
.and_then(|diff| diff.base_text())
|
||||
{
|
||||
if a.buffer_id == Some(base_text.remote_id()) {
|
||||
return a.bias_left(base_text);
|
||||
|
@ -135,7 +135,7 @@ impl Anchor {
|
|||
if let Some(base_text) = snapshot
|
||||
.diffs
|
||||
.get(&excerpt.buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
.and_then(|diff| diff.base_text())
|
||||
{
|
||||
if a.buffer_id == Some(base_text.remote_id()) {
|
||||
return a.bias_right(&base_text);
|
||||
|
|
|
@ -7,9 +7,11 @@ pub use anchor::{Anchor, AnchorRangeExt, Offset};
|
|||
pub use position::{TypedOffset, TypedPoint, TypedRow};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use buffer_diff::{
|
||||
BufferDiff, BufferDiffEvent, BufferDiffSnapshot, DiffHunkSecondaryStatus, DiffHunkStatus,
|
||||
};
|
||||
use clock::ReplicaId;
|
||||
use collections::{BTreeMap, Bound, HashMap, HashSet};
|
||||
use diff::{BufferDiff, BufferDiffEvent, BufferDiffSnapshot, DiffHunkStatus};
|
||||
use futures::{channel::mpsc, SinkExt};
|
||||
use gpui::{App, Context, Entity, EntityId, EventEmitter, Task};
|
||||
use itertools::Itertools;
|
||||
|
@ -129,16 +131,18 @@ pub struct MultiBufferDiffHunk {
|
|||
pub excerpt_id: ExcerptId,
|
||||
/// The range within the buffer's diff base that this hunk corresponds to.
|
||||
pub diff_base_byte_range: Range<usize>,
|
||||
/// Whether or not this hunk also appears in the 'secondary diff'.
|
||||
pub secondary_status: DiffHunkSecondaryStatus,
|
||||
}
|
||||
|
||||
impl MultiBufferDiffHunk {
|
||||
pub fn status(&self) -> DiffHunkStatus {
|
||||
if self.buffer_range.start == self.buffer_range.end {
|
||||
DiffHunkStatus::Removed
|
||||
DiffHunkStatus::Removed(self.secondary_status)
|
||||
} else if self.diff_base_byte_range.is_empty() {
|
||||
DiffHunkStatus::Added
|
||||
DiffHunkStatus::Added(self.secondary_status)
|
||||
} else {
|
||||
DiffHunkStatus::Modified
|
||||
DiffHunkStatus::Modified(self.secondary_status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +229,14 @@ impl DiffState {
|
|||
DiffState {
|
||||
_subscription: cx.subscribe(&diff, |this, diff, event, cx| match event {
|
||||
BufferDiffEvent::DiffChanged { changed_range } => {
|
||||
this.buffer_diff_changed(diff, changed_range.clone(), cx)
|
||||
let changed_range = if let Some(changed_range) = changed_range {
|
||||
changed_range.clone()
|
||||
} else if diff.read(cx).base_text().is_none() && this.all_diff_hunks_expanded {
|
||||
text::Anchor::MIN..text::Anchor::MAX
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
this.buffer_diff_changed(diff, changed_range, cx)
|
||||
}
|
||||
BufferDiffEvent::LanguageChanged => this.buffer_diff_language_changed(diff, cx),
|
||||
}),
|
||||
|
@ -241,7 +252,7 @@ pub struct MultiBufferSnapshot {
|
|||
excerpts: SumTree<Excerpt>,
|
||||
excerpt_ids: SumTree<ExcerptIdMapping>,
|
||||
diffs: TreeMap<BufferId, BufferDiffSnapshot>,
|
||||
pub diff_transforms: SumTree<DiffTransform>,
|
||||
diff_transforms: SumTree<DiffTransform>,
|
||||
trailing_excerpt_update_count: usize,
|
||||
non_text_state_update_count: usize,
|
||||
edit_count: usize,
|
||||
|
@ -252,20 +263,27 @@ pub struct MultiBufferSnapshot {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DiffTransform {
|
||||
enum DiffTransform {
|
||||
BufferContent {
|
||||
summary: TextSummary,
|
||||
inserted_hunk_anchor: Option<(ExcerptId, text::Anchor)>,
|
||||
inserted_hunk_info: Option<DiffTransformHunkInfo>,
|
||||
},
|
||||
DeletedHunk {
|
||||
summary: TextSummary,
|
||||
buffer_id: BufferId,
|
||||
hunk_anchor: (ExcerptId, text::Anchor),
|
||||
hunk_info: DiffTransformHunkInfo,
|
||||
base_text_byte_range: Range<usize>,
|
||||
has_trailing_newline: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
struct DiffTransformHunkInfo {
|
||||
excerpt_id: ExcerptId,
|
||||
hunk_start_anchor: text::Anchor,
|
||||
hunk_secondary_status: DiffHunkSecondaryStatus,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ExcerptInfo {
|
||||
pub id: ExcerptId,
|
||||
|
@ -310,7 +328,7 @@ pub struct RowInfo {
|
|||
pub buffer_id: Option<BufferId>,
|
||||
pub buffer_row: Option<u32>,
|
||||
pub multibuffer_row: Option<MultiBufferRow>,
|
||||
pub diff_status: Option<diff::DiffHunkStatus>,
|
||||
pub diff_status: Option<buffer_diff::DiffHunkStatus>,
|
||||
}
|
||||
|
||||
/// A slice into a [`Buffer`] that is being edited in a [`MultiBuffer`].
|
||||
|
@ -431,7 +449,7 @@ struct MultiBufferCursor<'a, D: TextDimension> {
|
|||
struct MultiBufferRegion<'a, D: TextDimension> {
|
||||
buffer: &'a BufferSnapshot,
|
||||
is_main_buffer: bool,
|
||||
is_inserted_hunk: bool,
|
||||
diff_hunk_status: Option<DiffHunkStatus>,
|
||||
excerpt: &'a Excerpt,
|
||||
buffer_range: Range<D>,
|
||||
range: Range<D>,
|
||||
|
@ -2146,7 +2164,7 @@ impl MultiBuffer {
|
|||
let mut snapshot = self.snapshot.borrow_mut();
|
||||
let diff = diff.read(cx);
|
||||
let buffer_id = diff.buffer_id;
|
||||
let diff = diff.snapshot.clone();
|
||||
let diff = diff.snapshot(cx);
|
||||
snapshot.diffs.insert(buffer_id, diff);
|
||||
}
|
||||
|
||||
|
@ -2160,36 +2178,29 @@ impl MultiBuffer {
|
|||
|
||||
let diff = diff.read(cx);
|
||||
let buffer_id = diff.buffer_id;
|
||||
let mut diff = diff.snapshot.clone();
|
||||
if diff.base_text.is_none() && self.all_diff_hunks_expanded {
|
||||
diff = BufferDiffSnapshot::new_with_single_insertion(cx);
|
||||
}
|
||||
|
||||
let mut snapshot = self.snapshot.borrow_mut();
|
||||
let base_text_changed =
|
||||
snapshot
|
||||
.diffs
|
||||
.get(&buffer_id)
|
||||
.map_or(true, |diff_snapshot| {
|
||||
match (&diff_snapshot.base_text, &diff.base_text) {
|
||||
(None, None) => false,
|
||||
(None, Some(_)) => true,
|
||||
(Some(_), None) => true,
|
||||
(Some(old), Some(new)) => {
|
||||
let (old_id, old_empty) = (old.remote_id(), old.is_empty());
|
||||
let (new_id, new_empty) = (new.remote_id(), new.is_empty());
|
||||
new_id != old_id && (!new_empty || !old_empty)
|
||||
}
|
||||
}
|
||||
});
|
||||
snapshot.diffs.insert(buffer_id, diff);
|
||||
|
||||
let buffers = self.buffers.borrow();
|
||||
let Some(buffer_state) = buffers.get(&buffer_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let diff_change_range = range.to_offset(buffer_state.buffer.read(cx));
|
||||
let buffer = buffer_state.buffer.read(cx);
|
||||
let diff_change_range = range.to_offset(buffer);
|
||||
|
||||
let mut new_diff = diff.snapshot(cx);
|
||||
if new_diff.base_text().is_none() && self.all_diff_hunks_expanded {
|
||||
let secondary_diff_insertion = new_diff
|
||||
.secondary_diff()
|
||||
.map_or(true, |secondary_diff| secondary_diff.base_text().is_none());
|
||||
new_diff = BufferDiff::build_with_single_insertion(secondary_diff_insertion, cx);
|
||||
}
|
||||
|
||||
let mut snapshot = self.snapshot.borrow_mut();
|
||||
let base_text_changed = snapshot
|
||||
.diffs
|
||||
.get(&buffer_id)
|
||||
.map_or(true, |old_diff| !new_diff.base_texts_eq(old_diff));
|
||||
|
||||
snapshot.diffs.insert(buffer_id, new_diff);
|
||||
|
||||
let mut excerpt_edits = Vec::new();
|
||||
for locator in &buffer_state.excerpts {
|
||||
|
@ -2367,7 +2378,7 @@ impl MultiBuffer {
|
|||
if *cursor.start() >= end {
|
||||
break;
|
||||
}
|
||||
if item.hunk_anchor().is_some() {
|
||||
if item.hunk_info().is_some() {
|
||||
return true;
|
||||
}
|
||||
cursor.next(&());
|
||||
|
@ -2820,11 +2831,11 @@ impl MultiBuffer {
|
|||
let keep_next_old_transform = (old_diff_transforms.start().0 >= edit.old.end)
|
||||
&& match old_diff_transforms.item() {
|
||||
Some(DiffTransform::BufferContent {
|
||||
inserted_hunk_anchor: Some(hunk_anchor),
|
||||
inserted_hunk_info: Some(hunk),
|
||||
..
|
||||
}) => excerpts
|
||||
.item()
|
||||
.is_some_and(|excerpt| hunk_anchor.1.is_valid(&excerpt.buffer)),
|
||||
}) => excerpts.item().is_some_and(|excerpt| {
|
||||
hunk.hunk_start_anchor.is_valid(&excerpt.buffer)
|
||||
}),
|
||||
_ => true,
|
||||
};
|
||||
|
||||
|
@ -2853,7 +2864,7 @@ impl MultiBuffer {
|
|||
new_diff_transforms.push(
|
||||
DiffTransform::BufferContent {
|
||||
summary: Default::default(),
|
||||
inserted_hunk_anchor: None,
|
||||
inserted_hunk_info: None,
|
||||
},
|
||||
&(),
|
||||
);
|
||||
|
@ -2876,8 +2887,8 @@ impl MultiBuffer {
|
|||
excerpts: &mut Cursor<Excerpt, TypedOffset<Excerpt>>,
|
||||
old_diff_transforms: &mut Cursor<DiffTransform, (TypedOffset<Excerpt>, usize)>,
|
||||
new_diff_transforms: &mut SumTree<DiffTransform>,
|
||||
end_of_current_insert: &mut Option<(TypedOffset<Excerpt>, ExcerptId, text::Anchor)>,
|
||||
old_expanded_hunks: &mut HashSet<(ExcerptId, text::Anchor)>,
|
||||
end_of_current_insert: &mut Option<(TypedOffset<Excerpt>, DiffTransformHunkInfo)>,
|
||||
old_expanded_hunks: &mut HashSet<DiffTransformHunkInfo>,
|
||||
snapshot: &MultiBufferSnapshot,
|
||||
change_kind: DiffChangeKind,
|
||||
) -> bool {
|
||||
|
@ -2889,12 +2900,12 @@ impl MultiBuffer {
|
|||
|
||||
// Record which hunks were previously expanded.
|
||||
while let Some(item) = old_diff_transforms.item() {
|
||||
if let Some(hunk_anchor) = item.hunk_anchor() {
|
||||
if let Some(hunk_info) = item.hunk_info() {
|
||||
log::trace!(
|
||||
"previously expanded hunk at {}",
|
||||
old_diff_transforms.start().0
|
||||
);
|
||||
old_expanded_hunks.insert(hunk_anchor);
|
||||
old_expanded_hunks.insert(hunk_info);
|
||||
}
|
||||
if old_diff_transforms.end(&()).0 > edit.old.end {
|
||||
break;
|
||||
|
@ -2918,7 +2929,7 @@ impl MultiBuffer {
|
|||
if let Some((diff, base_text)) = snapshot
|
||||
.diffs
|
||||
.get(&excerpt.buffer_id)
|
||||
.and_then(|diff| Some((diff, diff.base_text.as_ref()?)))
|
||||
.and_then(|diff| Some((diff, diff.base_text()?)))
|
||||
{
|
||||
let buffer = &excerpt.buffer;
|
||||
let excerpt_start = *excerpts.start();
|
||||
|
@ -2936,7 +2947,11 @@ impl MultiBuffer {
|
|||
for hunk in diff.hunks_intersecting_range(edit_anchor_range, buffer) {
|
||||
let hunk_buffer_range = hunk.buffer_range.to_offset(buffer);
|
||||
|
||||
let hunk_anchor = (excerpt.id, hunk.buffer_range.start);
|
||||
let hunk_info = DiffTransformHunkInfo {
|
||||
excerpt_id: excerpt.id,
|
||||
hunk_start_anchor: hunk.buffer_range.start,
|
||||
hunk_secondary_status: hunk.secondary_status,
|
||||
};
|
||||
if hunk_buffer_range.start < excerpt_buffer_start {
|
||||
log::trace!("skipping hunk that starts before excerpt");
|
||||
continue;
|
||||
|
@ -2960,7 +2975,7 @@ impl MultiBuffer {
|
|||
|
||||
// For every existing hunk, determine if it was previously expanded
|
||||
// and if it should currently be expanded.
|
||||
let was_previously_expanded = old_expanded_hunks.contains(&hunk_anchor);
|
||||
let was_previously_expanded = old_expanded_hunks.contains(&hunk_info);
|
||||
let should_expand_hunk = match &change_kind {
|
||||
DiffChangeKind::DiffUpdated { base_changed: true } => {
|
||||
self.all_diff_hunks_expanded
|
||||
|
@ -3008,7 +3023,7 @@ impl MultiBuffer {
|
|||
base_text_byte_range: hunk.diff_base_byte_range.clone(),
|
||||
summary: base_text_summary,
|
||||
buffer_id: excerpt.buffer_id,
|
||||
hunk_anchor,
|
||||
hunk_info,
|
||||
has_trailing_newline,
|
||||
},
|
||||
&(),
|
||||
|
@ -3016,11 +3031,8 @@ impl MultiBuffer {
|
|||
}
|
||||
|
||||
if !hunk_buffer_range.is_empty() {
|
||||
*end_of_current_insert = Some((
|
||||
hunk_excerpt_end.min(excerpt_end),
|
||||
hunk_anchor.0,
|
||||
hunk_anchor.1,
|
||||
));
|
||||
*end_of_current_insert =
|
||||
Some((hunk_excerpt_end.min(excerpt_end), hunk_info));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3042,13 +3054,13 @@ impl MultiBuffer {
|
|||
subtree: SumTree<DiffTransform>,
|
||||
) {
|
||||
if let Some(DiffTransform::BufferContent {
|
||||
inserted_hunk_anchor,
|
||||
inserted_hunk_info,
|
||||
summary,
|
||||
}) = subtree.first()
|
||||
{
|
||||
if self.extend_last_buffer_content_transform(
|
||||
new_transforms,
|
||||
*inserted_hunk_anchor,
|
||||
*inserted_hunk_info,
|
||||
*summary,
|
||||
) {
|
||||
let mut cursor = subtree.cursor::<()>(&());
|
||||
|
@ -3067,7 +3079,7 @@ impl MultiBuffer {
|
|||
transform: DiffTransform,
|
||||
) {
|
||||
if let DiffTransform::BufferContent {
|
||||
inserted_hunk_anchor,
|
||||
inserted_hunk_info: inserted_hunk_anchor,
|
||||
summary,
|
||||
} = transform
|
||||
{
|
||||
|
@ -3087,19 +3099,14 @@ impl MultiBuffer {
|
|||
old_snapshot: &MultiBufferSnapshot,
|
||||
new_transforms: &mut SumTree<DiffTransform>,
|
||||
end_offset: ExcerptOffset,
|
||||
current_inserted_hunk: Option<(ExcerptOffset, ExcerptId, text::Anchor)>,
|
||||
current_inserted_hunk: Option<(ExcerptOffset, DiffTransformHunkInfo)>,
|
||||
) {
|
||||
let inserted_region =
|
||||
current_inserted_hunk.map(|(insertion_end_offset, excerpt_id, anchor)| {
|
||||
(
|
||||
end_offset.min(insertion_end_offset),
|
||||
Some((excerpt_id, anchor)),
|
||||
)
|
||||
});
|
||||
let inserted_region = current_inserted_hunk.map(|(insertion_end_offset, hunk_info)| {
|
||||
(end_offset.min(insertion_end_offset), Some(hunk_info))
|
||||
});
|
||||
let unchanged_region = [(end_offset, None)];
|
||||
|
||||
for (end_offset, inserted_hunk_anchor) in
|
||||
inserted_region.into_iter().chain(unchanged_region)
|
||||
for (end_offset, inserted_hunk_info) in inserted_region.into_iter().chain(unchanged_region)
|
||||
{
|
||||
let start_offset = new_transforms.summary().excerpt_len();
|
||||
if end_offset <= start_offset {
|
||||
|
@ -3110,13 +3117,13 @@ impl MultiBuffer {
|
|||
|
||||
if !self.extend_last_buffer_content_transform(
|
||||
new_transforms,
|
||||
inserted_hunk_anchor,
|
||||
inserted_hunk_info,
|
||||
summary_to_add,
|
||||
) {
|
||||
new_transforms.push(
|
||||
DiffTransform::BufferContent {
|
||||
summary: summary_to_add,
|
||||
inserted_hunk_anchor,
|
||||
inserted_hunk_info,
|
||||
},
|
||||
&(),
|
||||
)
|
||||
|
@ -3127,7 +3134,7 @@ impl MultiBuffer {
|
|||
fn extend_last_buffer_content_transform(
|
||||
&self,
|
||||
new_transforms: &mut SumTree<DiffTransform>,
|
||||
new_inserted_hunk_anchor: Option<(ExcerptId, text::Anchor)>,
|
||||
new_inserted_hunk_info: Option<DiffTransformHunkInfo>,
|
||||
summary_to_add: TextSummary,
|
||||
) -> bool {
|
||||
let mut did_extend = false;
|
||||
|
@ -3135,10 +3142,10 @@ impl MultiBuffer {
|
|||
|last_transform| {
|
||||
if let DiffTransform::BufferContent {
|
||||
summary,
|
||||
inserted_hunk_anchor,
|
||||
inserted_hunk_info: inserted_hunk_anchor,
|
||||
} = last_transform
|
||||
{
|
||||
if *inserted_hunk_anchor == new_inserted_hunk_anchor {
|
||||
if *inserted_hunk_anchor == new_inserted_hunk_info {
|
||||
*summary += summary_to_add;
|
||||
did_extend = true;
|
||||
}
|
||||
|
@ -3469,6 +3476,7 @@ impl MultiBufferSnapshot {
|
|||
excerpt_id: excerpt.id,
|
||||
buffer_range: hunk.buffer_range.clone(),
|
||||
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
|
||||
secondary_status: hunk.secondary_status,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -3837,6 +3845,7 @@ impl MultiBufferSnapshot {
|
|||
excerpt_id: excerpt.id,
|
||||
buffer_range: hunk.buffer_range.clone(),
|
||||
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
|
||||
secondary_status: hunk.secondary_status,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -4309,10 +4318,7 @@ impl MultiBufferSnapshot {
|
|||
} => {
|
||||
let buffer_start = base_text_byte_range.start + start_overshoot;
|
||||
let mut buffer_end = base_text_byte_range.start + end_overshoot;
|
||||
let Some(base_text) = self
|
||||
.diffs
|
||||
.get(buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
let Some(base_text) = self.diffs.get(buffer_id).and_then(|diff| diff.base_text())
|
||||
else {
|
||||
panic!("{:?} is in non-existent deleted hunk", range.start)
|
||||
};
|
||||
|
@ -4361,10 +4367,7 @@ impl MultiBufferSnapshot {
|
|||
..
|
||||
} => {
|
||||
let buffer_end = base_text_byte_range.start + overshoot;
|
||||
let Some(base_text) = self
|
||||
.diffs
|
||||
.get(buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
let Some(base_text) = self.diffs.get(buffer_id).and_then(|diff| diff.base_text())
|
||||
else {
|
||||
panic!("{:?} is in non-existent deleted hunk", range.end)
|
||||
};
|
||||
|
@ -4469,10 +4472,8 @@ impl MultiBufferSnapshot {
|
|||
}) => {
|
||||
let mut in_deleted_hunk = false;
|
||||
if let Some(diff_base_anchor) = &anchor.diff_base_anchor {
|
||||
if let Some(base_text) = self
|
||||
.diffs
|
||||
.get(buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
if let Some(base_text) =
|
||||
self.diffs.get(buffer_id).and_then(|diff| diff.base_text())
|
||||
{
|
||||
if base_text.can_resolve(&diff_base_anchor) {
|
||||
let base_text_offset = diff_base_anchor.to_offset(&base_text);
|
||||
|
@ -4809,7 +4810,7 @@ impl MultiBufferSnapshot {
|
|||
let base_text = self
|
||||
.diffs
|
||||
.get(buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
.and_then(|diff| diff.base_text())
|
||||
.expect("missing diff base");
|
||||
if offset_in_transform > base_text_byte_range.len() {
|
||||
debug_assert!(*has_trailing_newline);
|
||||
|
@ -5969,17 +5970,17 @@ impl MultiBufferSnapshot {
|
|||
for item in self.diff_transforms.iter() {
|
||||
if let DiffTransform::BufferContent {
|
||||
summary,
|
||||
inserted_hunk_anchor,
|
||||
inserted_hunk_info,
|
||||
} = item
|
||||
{
|
||||
if let Some(DiffTransform::BufferContent {
|
||||
inserted_hunk_anchor: prev_inserted_hunk_anchor,
|
||||
inserted_hunk_info: prev_inserted_hunk_info,
|
||||
..
|
||||
}) = prev_transform
|
||||
{
|
||||
if *inserted_hunk_anchor == *prev_inserted_hunk_anchor {
|
||||
if *inserted_hunk_info == *prev_inserted_hunk_info {
|
||||
panic!(
|
||||
"multiple adjacent buffer content transforms with is_inserted_hunk = {inserted_hunk_anchor:?}. transforms: {:+?}",
|
||||
"multiple adjacent buffer content transforms with is_inserted_hunk = {inserted_hunk_info:?}. transforms: {:+?}",
|
||||
self.diff_transforms.items(&()));
|
||||
}
|
||||
}
|
||||
|
@ -6149,10 +6150,11 @@ where
|
|||
buffer_id,
|
||||
base_text_byte_range,
|
||||
has_trailing_newline,
|
||||
hunk_info,
|
||||
..
|
||||
} => {
|
||||
let diff = self.diffs.get(&buffer_id)?;
|
||||
let buffer = diff.base_text.as_ref()?;
|
||||
let buffer = diff.base_text()?;
|
||||
let mut rope_cursor = buffer.as_rope().cursor(0);
|
||||
let buffer_start = rope_cursor.summary::<D>(base_text_byte_range.start);
|
||||
let buffer_range_len = rope_cursor.summary::<D>(base_text_byte_range.end);
|
||||
|
@ -6165,14 +6167,15 @@ where
|
|||
excerpt,
|
||||
has_trailing_newline: *has_trailing_newline,
|
||||
is_main_buffer: false,
|
||||
is_inserted_hunk: false,
|
||||
diff_hunk_status: Some(DiffHunkStatus::Removed(
|
||||
hunk_info.hunk_secondary_status,
|
||||
)),
|
||||
buffer_range: buffer_start..buffer_end,
|
||||
range: start..end,
|
||||
});
|
||||
}
|
||||
DiffTransform::BufferContent {
|
||||
inserted_hunk_anchor,
|
||||
..
|
||||
inserted_hunk_info, ..
|
||||
} => {
|
||||
let buffer = &excerpt.buffer;
|
||||
let buffer_context_start = excerpt.range.context.start.summary::<D>(buffer);
|
||||
|
@ -6209,7 +6212,8 @@ where
|
|||
excerpt,
|
||||
has_trailing_newline,
|
||||
is_main_buffer: true,
|
||||
is_inserted_hunk: inserted_hunk_anchor.is_some(),
|
||||
diff_hunk_status: inserted_hunk_info
|
||||
.map(|info| DiffHunkStatus::Added(info.hunk_secondary_status)),
|
||||
buffer_range: buffer_start..buffer_end,
|
||||
range: start..end,
|
||||
})
|
||||
|
@ -6717,13 +6721,12 @@ impl sum_tree::KeyedItem for ExcerptIdMapping {
|
|||
}
|
||||
|
||||
impl DiffTransform {
|
||||
fn hunk_anchor(&self) -> Option<(ExcerptId, text::Anchor)> {
|
||||
fn hunk_info(&self) -> Option<DiffTransformHunkInfo> {
|
||||
match self {
|
||||
DiffTransform::DeletedHunk { hunk_anchor, .. } => Some(*hunk_anchor),
|
||||
DiffTransform::DeletedHunk { hunk_info, .. } => Some(*hunk_info),
|
||||
DiffTransform::BufferContent {
|
||||
inserted_hunk_anchor,
|
||||
..
|
||||
} => *inserted_hunk_anchor,
|
||||
inserted_hunk_info, ..
|
||||
} => *inserted_hunk_info,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7020,13 +7023,9 @@ impl<'a> Iterator for MultiBufferRows<'a> {
|
|||
buffer_id: Some(region.buffer.remote_id()),
|
||||
buffer_row: Some(buffer_point.row),
|
||||
multibuffer_row: Some(MultiBufferRow(self.point.row)),
|
||||
diff_status: if region.is_inserted_hunk && self.point < region.range.end {
|
||||
Some(DiffHunkStatus::Added)
|
||||
} else if !region.is_main_buffer {
|
||||
Some(DiffHunkStatus::Removed)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
diff_status: region
|
||||
.diff_hunk_status
|
||||
.filter(|_| self.point < region.range.end),
|
||||
});
|
||||
self.point += Point::new(1, 0);
|
||||
result
|
||||
|
@ -7194,7 +7193,7 @@ impl<'a> Iterator for MultiBufferChunks<'a> {
|
|||
}
|
||||
chunks
|
||||
} else {
|
||||
let base_buffer = &self.diffs.get(&buffer_id)?.base_text.as_ref()?;
|
||||
let base_buffer = &self.diffs.get(&buffer_id)?.base_text()?;
|
||||
base_buffer.chunks(base_text_start..base_text_end, self.language_aware)
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::*;
|
||||
use diff::DiffHunkStatus;
|
||||
use buffer_diff::DiffHunkStatus;
|
||||
use gpui::{App, TestAppContext};
|
||||
use indoc::indoc;
|
||||
use language::{Buffer, Rope};
|
||||
|
@ -979,8 +979,6 @@ fn test_empty_diff_excerpt(cx: &mut TestAppContext) {
|
|||
|
||||
let diff = cx.new(|cx| BufferDiff::new_with_base_text(base_text, &buffer, cx));
|
||||
multibuffer.update(cx, |multibuffer, cx| {
|
||||
multibuffer.set_all_diff_hunks_expanded(cx);
|
||||
multibuffer.add_diff(diff.clone(), cx);
|
||||
multibuffer.push_excerpts(
|
||||
buffer.clone(),
|
||||
[ExcerptRange {
|
||||
|
@ -989,6 +987,8 @@ fn test_empty_diff_excerpt(cx: &mut TestAppContext) {
|
|||
}],
|
||||
cx,
|
||||
);
|
||||
multibuffer.set_all_diff_hunks_expanded(cx);
|
||||
multibuffer.add_diff(diff.clone(), cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
|
@ -1325,13 +1325,13 @@ fn test_basic_diff_hunks(cx: &mut TestAppContext) {
|
|||
.map(|info| (info.buffer_row, info.diff_status))
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
(Some(0), Some(DiffHunkStatus::Added)),
|
||||
(Some(0), Some(DiffHunkStatus::added())),
|
||||
(Some(1), None),
|
||||
(Some(1), Some(DiffHunkStatus::Removed)),
|
||||
(Some(2), Some(DiffHunkStatus::Added)),
|
||||
(Some(1), Some(DiffHunkStatus::removed())),
|
||||
(Some(2), Some(DiffHunkStatus::added())),
|
||||
(Some(3), None),
|
||||
(Some(3), Some(DiffHunkStatus::Removed)),
|
||||
(Some(4), Some(DiffHunkStatus::Removed)),
|
||||
(Some(3), Some(DiffHunkStatus::removed())),
|
||||
(Some(4), Some(DiffHunkStatus::removed())),
|
||||
(Some(4), None),
|
||||
(Some(5), None)
|
||||
]
|
||||
|
@ -1999,12 +1999,8 @@ fn test_diff_hunks_with_multiple_excerpts(cx: &mut TestAppContext) {
|
|||
|
||||
let id_1 = buffer_1.read_with(cx, |buffer, _| buffer.remote_id());
|
||||
let id_2 = buffer_2.read_with(cx, |buffer, _| buffer.remote_id());
|
||||
let base_id_1 = diff_1.read_with(cx, |diff, _| {
|
||||
diff.snapshot.base_text.as_ref().unwrap().remote_id()
|
||||
});
|
||||
let base_id_2 = diff_2.read_with(cx, |diff, _| {
|
||||
diff.snapshot.base_text.as_ref().unwrap().remote_id()
|
||||
});
|
||||
let base_id_1 = diff_1.read_with(cx, |diff, _| diff.base_text().as_ref().unwrap().remote_id());
|
||||
let base_id_2 = diff_2.read_with(cx, |diff, _| diff.base_text().as_ref().unwrap().remote_id());
|
||||
|
||||
let buffer_lines = (0..=snapshot.max_row().0)
|
||||
.map(|row| {
|
||||
|
@ -2191,9 +2187,8 @@ impl ReferenceMultibuffer {
|
|||
let Some(diff) = self.diffs.get(&buffer_id) else {
|
||||
return;
|
||||
};
|
||||
let diff = diff.read(cx).snapshot.clone();
|
||||
let excerpt_range = excerpt.range.to_offset(&buffer);
|
||||
for hunk in diff.hunks_intersecting_range(range, &buffer) {
|
||||
for hunk in diff.read(cx).hunks_intersecting_range(range, &buffer, cx) {
|
||||
let hunk_range = hunk.buffer_range.to_offset(&buffer);
|
||||
if hunk_range.start < excerpt_range.start || hunk_range.start > excerpt_range.end {
|
||||
continue;
|
||||
|
@ -2226,12 +2221,12 @@ impl ReferenceMultibuffer {
|
|||
let buffer = excerpt.buffer.read(cx);
|
||||
let buffer_range = excerpt.range.to_offset(buffer);
|
||||
let diff = self.diffs.get(&buffer.remote_id()).unwrap().read(cx);
|
||||
let diff = diff.snapshot.clone();
|
||||
let base_buffer = diff.base_text.as_ref().unwrap();
|
||||
// let diff = diff.snapshot.clone();
|
||||
let base_buffer = diff.base_text().unwrap();
|
||||
|
||||
let mut offset = buffer_range.start;
|
||||
let mut hunks = diff
|
||||
.hunks_intersecting_range(excerpt.range.clone(), buffer)
|
||||
.hunks_intersecting_range(excerpt.range.clone(), buffer, cx)
|
||||
.peekable();
|
||||
|
||||
while let Some(hunk) = hunks.next() {
|
||||
|
@ -2284,7 +2279,7 @@ impl ReferenceMultibuffer {
|
|||
buffer_start: Some(
|
||||
base_buffer.offset_to_point(hunk.diff_base_byte_range.start),
|
||||
),
|
||||
status: Some(DiffHunkStatus::Removed),
|
||||
status: Some(DiffHunkStatus::Removed(hunk.secondary_status)),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2299,7 +2294,7 @@ impl ReferenceMultibuffer {
|
|||
buffer_id: Some(buffer.remote_id()),
|
||||
range: len..text.len(),
|
||||
buffer_start: Some(buffer.offset_to_point(offset)),
|
||||
status: Some(DiffHunkStatus::Added),
|
||||
status: Some(DiffHunkStatus::Added(hunk.secondary_status)),
|
||||
});
|
||||
offset = hunk_range.end;
|
||||
}
|
||||
|
@ -2365,8 +2360,8 @@ impl ReferenceMultibuffer {
|
|||
let buffer = excerpt.buffer.read(cx).snapshot();
|
||||
let excerpt_range = excerpt.range.to_offset(&buffer);
|
||||
let buffer_id = buffer.remote_id();
|
||||
let diff = &self.diffs.get(&buffer_id).unwrap().read(cx).snapshot;
|
||||
let mut hunks = diff.hunks_in_row_range(0..u32::MAX, &buffer).peekable();
|
||||
let diff = self.diffs.get(&buffer_id).unwrap().read(cx);
|
||||
let mut hunks = diff.hunks_in_row_range(0..u32::MAX, &buffer, cx).peekable();
|
||||
excerpt.expanded_diff_hunks.retain(|hunk_anchor| {
|
||||
if !hunk_anchor.is_valid(&buffer) {
|
||||
return false;
|
||||
|
@ -2670,7 +2665,7 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
|
|||
expected_row_infos
|
||||
.into_iter()
|
||||
.filter_map(
|
||||
|info| if info.diff_status == Some(DiffHunkStatus::Removed) {
|
||||
|info| if matches!(info.diff_status, Some(DiffHunkStatus::Removed(_))) {
|
||||
None
|
||||
} else {
|
||||
info.buffer_row
|
||||
|
@ -3027,9 +3022,9 @@ fn format_diff(
|
|||
.zip(row_infos)
|
||||
.map(|((ix, line), info)| {
|
||||
let marker = match info.diff_status {
|
||||
Some(DiffHunkStatus::Added) => "+ ",
|
||||
Some(DiffHunkStatus::Removed) => "- ",
|
||||
Some(DiffHunkStatus::Modified) => unreachable!(),
|
||||
Some(DiffHunkStatus::Added(_)) => "+ ",
|
||||
Some(DiffHunkStatus::Removed(_)) => "- ",
|
||||
Some(DiffHunkStatus::Modified(_)) => unreachable!(),
|
||||
None => {
|
||||
if has_diff && !line.is_empty() {
|
||||
" "
|
||||
|
|
|
@ -30,7 +30,7 @@ async-trait.workspace = true
|
|||
client.workspace = true
|
||||
clock.workspace = true
|
||||
collections.workspace = true
|
||||
diff.workspace = true
|
||||
buffer_diff.workspace = true
|
||||
fs.workspace = true
|
||||
futures.workspace = true
|
||||
fuzzy.workspace = true
|
||||
|
@ -78,7 +78,7 @@ fancy-regex.workspace = true
|
|||
[dev-dependencies]
|
||||
client = { workspace = true, features = ["test-support"] }
|
||||
collections = { workspace = true, features = ["test-support"] }
|
||||
diff = { workspace = true, features = ["test-support"] }
|
||||
buffer_diff = { workspace = true, features = ["test-support"] }
|
||||
env_logger.workspace = true
|
||||
fs = { workspace = true, features = ["test-support"] }
|
||||
git2.workspace = true
|
||||
|
|
|
@ -6,9 +6,9 @@ use crate::{
|
|||
};
|
||||
use ::git::{parse_git_remote_url, BuildPermalinkParams, GitHostingProviderRegistry};
|
||||
use anyhow::{anyhow, bail, Context as _, Result};
|
||||
use buffer_diff::{BufferDiff, BufferDiffEvent};
|
||||
use client::Client;
|
||||
use collections::{hash_map, HashMap, HashSet};
|
||||
use diff::{BufferDiff, BufferDiffEvent, BufferDiffSnapshot};
|
||||
use fs::Fs;
|
||||
use futures::{channel::oneshot, future::Shared, Future, FutureExt as _, StreamExt};
|
||||
use git::{blame::Blame, repository::RepoPath};
|
||||
|
@ -207,72 +207,74 @@ impl BufferDiffState {
|
|||
_ => false,
|
||||
};
|
||||
self.recalculate_diff_task = Some(cx.spawn(|this, mut cx| async move {
|
||||
let mut unstaged_changed_range = None;
|
||||
if let Some(unstaged_diff) = &unstaged_diff {
|
||||
let snapshot = if index_changed || language_changed {
|
||||
cx.update(|cx| {
|
||||
BufferDiffSnapshot::build(
|
||||
buffer.clone(),
|
||||
index,
|
||||
language.clone(),
|
||||
language_registry.clone(),
|
||||
cx,
|
||||
)
|
||||
})?
|
||||
.await
|
||||
} else {
|
||||
unstaged_diff
|
||||
.read_with(&cx, |changes, cx| {
|
||||
BufferDiffSnapshot::build_with_base_buffer(
|
||||
buffer.clone(),
|
||||
index,
|
||||
changes.snapshot.base_text.clone(),
|
||||
cx,
|
||||
)
|
||||
})?
|
||||
.await
|
||||
};
|
||||
unstaged_changed_range = BufferDiff::update_diff(
|
||||
unstaged_diff.clone(),
|
||||
buffer.clone(),
|
||||
index,
|
||||
index_changed,
|
||||
language_changed,
|
||||
language.clone(),
|
||||
language_registry.clone(),
|
||||
&mut cx,
|
||||
)
|
||||
.await?;
|
||||
|
||||
unstaged_diff.update(&mut cx, |unstaged_diff, cx| {
|
||||
unstaged_diff.set_state(snapshot, &buffer, cx);
|
||||
unstaged_diff.update(&mut cx, |_, cx| {
|
||||
if language_changed {
|
||||
cx.emit(BufferDiffEvent::LanguageChanged);
|
||||
}
|
||||
if let Some(changed_range) = unstaged_changed_range.clone() {
|
||||
cx.emit(BufferDiffEvent::DiffChanged {
|
||||
changed_range: Some(changed_range),
|
||||
})
|
||||
}
|
||||
})?;
|
||||
}
|
||||
|
||||
if let Some(uncommitted_diff) = &uncommitted_diff {
|
||||
let snapshot =
|
||||
let uncommitted_changed_range =
|
||||
if let (Some(unstaged_diff), true) = (&unstaged_diff, index_matches_head) {
|
||||
unstaged_diff.read_with(&cx, |diff, _| diff.snapshot.clone())?
|
||||
} else if head_changed || language_changed {
|
||||
cx.update(|cx| {
|
||||
BufferDiffSnapshot::build(
|
||||
buffer.clone(),
|
||||
head,
|
||||
language.clone(),
|
||||
language_registry.clone(),
|
||||
cx,
|
||||
)
|
||||
uncommitted_diff.update(&mut cx, |uncommitted_diff, cx| {
|
||||
uncommitted_diff.update_diff_from(&buffer, unstaged_diff, cx)
|
||||
})?
|
||||
.await
|
||||
} else {
|
||||
uncommitted_diff
|
||||
.read_with(&cx, |changes, cx| {
|
||||
BufferDiffSnapshot::build_with_base_buffer(
|
||||
buffer.clone(),
|
||||
head,
|
||||
changes.snapshot.base_text.clone(),
|
||||
cx,
|
||||
)
|
||||
})?
|
||||
.await
|
||||
BufferDiff::update_diff(
|
||||
uncommitted_diff.clone(),
|
||||
buffer.clone(),
|
||||
head,
|
||||
head_changed,
|
||||
language_changed,
|
||||
language.clone(),
|
||||
language_registry.clone(),
|
||||
&mut cx,
|
||||
)
|
||||
.await?
|
||||
};
|
||||
|
||||
uncommitted_diff.update(&mut cx, |diff, cx| {
|
||||
diff.set_state(snapshot, &buffer, cx);
|
||||
uncommitted_diff.update(&mut cx, |uncommitted_diff, cx| {
|
||||
if language_changed {
|
||||
cx.emit(BufferDiffEvent::LanguageChanged);
|
||||
}
|
||||
let changed_range = match (unstaged_changed_range, uncommitted_changed_range) {
|
||||
(None, None) => None,
|
||||
(Some(unstaged_range), None) => {
|
||||
uncommitted_diff.range_to_hunk_range(unstaged_range, &buffer, cx)
|
||||
}
|
||||
(None, Some(uncommitted_range)) => Some(uncommitted_range),
|
||||
(Some(unstaged_range), Some(uncommitted_range)) => maybe!({
|
||||
let expanded_range = uncommitted_diff.range_to_hunk_range(
|
||||
unstaged_range,
|
||||
&buffer,
|
||||
cx,
|
||||
)?;
|
||||
let start = expanded_range.start.min(&uncommitted_range.start, &buffer);
|
||||
let end = expanded_range.end.max(&uncommitted_range.end, &buffer);
|
||||
Some(start..end)
|
||||
}),
|
||||
};
|
||||
cx.emit(BufferDiffEvent::DiffChanged { changed_range });
|
||||
})?;
|
||||
}
|
||||
|
||||
|
@ -280,6 +282,7 @@ impl BufferDiffState {
|
|||
this.update(&mut cx, |this, _| {
|
||||
this.index_changed = false;
|
||||
this.head_changed = false;
|
||||
this.language_changed = false;
|
||||
for tx in this.diff_updated_futures.drain(..) {
|
||||
tx.send(()).ok();
|
||||
}
|
||||
|
@ -1478,29 +1481,19 @@ impl BufferStore {
|
|||
diff_state.language = language;
|
||||
diff_state.language_registry = language_registry;
|
||||
|
||||
let diff = cx.new(|_| BufferDiff {
|
||||
buffer_id,
|
||||
snapshot: BufferDiffSnapshot::new(&text_snapshot),
|
||||
unstaged_diff: None,
|
||||
});
|
||||
let diff = cx.new(|_| BufferDiff::new(&text_snapshot));
|
||||
match kind {
|
||||
DiffKind::Unstaged => diff_state.unstaged_diff = Some(diff.downgrade()),
|
||||
DiffKind::Uncommitted => {
|
||||
let unstaged_diff = if let Some(diff) = diff_state.unstaged_diff() {
|
||||
diff
|
||||
} else {
|
||||
let unstaged_diff = cx.new(|_| BufferDiff {
|
||||
buffer_id,
|
||||
snapshot: BufferDiffSnapshot::new(&text_snapshot),
|
||||
unstaged_diff: None,
|
||||
});
|
||||
let unstaged_diff = cx.new(|_| BufferDiff::new(&text_snapshot));
|
||||
diff_state.unstaged_diff = Some(unstaged_diff.downgrade());
|
||||
unstaged_diff
|
||||
};
|
||||
|
||||
diff.update(cx, |diff, _| {
|
||||
diff.unstaged_diff = Some(unstaged_diff);
|
||||
});
|
||||
diff.update(cx, |diff, _| diff.set_secondary_diff(unstaged_diff));
|
||||
diff_state.uncommitted_diff = Some(diff.downgrade())
|
||||
}
|
||||
};
|
||||
|
@ -2397,9 +2390,8 @@ impl BufferStore {
|
|||
shared.diff = Some(diff.clone());
|
||||
}
|
||||
})?;
|
||||
let staged_text = diff.read_with(&cx, |diff, _| {
|
||||
diff.snapshot.base_text.as_ref().map(|buffer| buffer.text())
|
||||
})?;
|
||||
let staged_text =
|
||||
diff.read_with(&cx, |diff, _| diff.base_text().map(|buffer| buffer.text()))?;
|
||||
Ok(proto::OpenUnstagedDiffResponse { staged_text })
|
||||
}
|
||||
|
||||
|
@ -2430,14 +2422,13 @@ impl BufferStore {
|
|||
use proto::open_uncommitted_diff_response::Mode;
|
||||
|
||||
let staged_buffer = diff
|
||||
.unstaged_diff
|
||||
.as_ref()
|
||||
.and_then(|diff| diff.read(cx).snapshot.base_text.as_ref());
|
||||
.secondary_diff()
|
||||
.and_then(|diff| diff.read(cx).base_text());
|
||||
|
||||
let mode;
|
||||
let staged_text;
|
||||
let committed_text;
|
||||
if let Some(committed_buffer) = &diff.snapshot.base_text {
|
||||
if let Some(committed_buffer) = diff.base_text() {
|
||||
committed_text = Some(committed_buffer.text());
|
||||
if let Some(staged_buffer) = staged_buffer {
|
||||
if staged_buffer.remote_id() == committed_buffer.remote_id() {
|
||||
|
|
|
@ -21,7 +21,7 @@ mod project_tests;
|
|||
|
||||
mod direnv;
|
||||
mod environment;
|
||||
use diff::BufferDiff;
|
||||
use buffer_diff::BufferDiff;
|
||||
pub use environment::EnvironmentErrorMessage;
|
||||
use git::Repository;
|
||||
pub mod search_history;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{Event, *};
|
||||
use diff::assert_hunks;
|
||||
use buffer_diff::{assert_hunks, DiffHunkSecondaryStatus, DiffHunkStatus};
|
||||
use fs::FakeFs;
|
||||
use futures::{future, StreamExt};
|
||||
use gpui::{App, SemanticVersion, UpdateGlobal};
|
||||
|
@ -5692,15 +5692,16 @@ async fn test_unstaged_diff_for_buffer(cx: &mut gpui::TestAppContext) {
|
|||
unstaged_diff.update(cx, |unstaged_diff, cx| {
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
assert_hunks(
|
||||
unstaged_diff.diff_hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot),
|
||||
unstaged_diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot, cx),
|
||||
&snapshot,
|
||||
&unstaged_diff.base_text_string().unwrap(),
|
||||
&[
|
||||
(0..1, "", "// print goodbye\n"),
|
||||
(0..1, "", "// print goodbye\n", DiffHunkStatus::added()),
|
||||
(
|
||||
2..3,
|
||||
" println!(\"hello world\");\n",
|
||||
" println!(\"goodbye world\");\n",
|
||||
DiffHunkStatus::modified(),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
@ -5722,10 +5723,15 @@ async fn test_unstaged_diff_for_buffer(cx: &mut gpui::TestAppContext) {
|
|||
unstaged_diff.update(cx, |unstaged_diff, cx| {
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
assert_hunks(
|
||||
unstaged_diff.diff_hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot),
|
||||
unstaged_diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot, cx),
|
||||
&snapshot,
|
||||
&unstaged_diff.snapshot.base_text.as_ref().unwrap().text(),
|
||||
&[(2..3, "", " println!(\"goodbye world\");\n")],
|
||||
&unstaged_diff.base_text().unwrap().text(),
|
||||
&[(
|
||||
2..3,
|
||||
"",
|
||||
" println!(\"goodbye world\");\n",
|
||||
DiffHunkStatus::added(),
|
||||
)],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -5795,10 +5801,7 @@ async fn test_uncommitted_diff_for_buffer(cx: &mut gpui::TestAppContext) {
|
|||
|
||||
uncommitted_diff.read_with(cx, |diff, _| {
|
||||
assert_eq!(
|
||||
diff.snapshot
|
||||
.base_text
|
||||
.as_ref()
|
||||
.and_then(|base| base.language().cloned()),
|
||||
diff.base_text().and_then(|base| base.language().cloned()),
|
||||
Some(language)
|
||||
)
|
||||
});
|
||||
|
@ -5807,15 +5810,21 @@ async fn test_uncommitted_diff_for_buffer(cx: &mut gpui::TestAppContext) {
|
|||
uncommitted_diff.update(cx, |uncommitted_diff, cx| {
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
assert_hunks(
|
||||
uncommitted_diff.diff_hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot),
|
||||
uncommitted_diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot, cx),
|
||||
&snapshot,
|
||||
&uncommitted_diff.base_text_string().unwrap(),
|
||||
&[
|
||||
(0..1, "", "// print goodbye\n"),
|
||||
(
|
||||
0..1,
|
||||
"",
|
||||
"// print goodbye\n",
|
||||
DiffHunkStatus::Added(DiffHunkSecondaryStatus::HasSecondaryHunk),
|
||||
),
|
||||
(
|
||||
2..3,
|
||||
" println!(\"hello world\");\n",
|
||||
" println!(\"goodbye world\");\n",
|
||||
DiffHunkStatus::modified(),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
@ -5837,10 +5846,15 @@ async fn test_uncommitted_diff_for_buffer(cx: &mut gpui::TestAppContext) {
|
|||
uncommitted_diff.update(cx, |uncommitted_diff, cx| {
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
assert_hunks(
|
||||
uncommitted_diff.diff_hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot),
|
||||
uncommitted_diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot, cx),
|
||||
&snapshot,
|
||||
&uncommitted_diff.snapshot.base_text.as_ref().unwrap().text(),
|
||||
&[(2..3, "", " println!(\"goodbye world\");\n")],
|
||||
&uncommitted_diff.base_text().unwrap().text(),
|
||||
&[(
|
||||
2..3,
|
||||
"",
|
||||
" println!(\"goodbye world\");\n",
|
||||
DiffHunkStatus::added(),
|
||||
)],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -5898,13 +5912,14 @@ async fn test_single_file_diffs(cx: &mut gpui::TestAppContext) {
|
|||
uncommitted_diff.update(cx, |uncommitted_diff, cx| {
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
assert_hunks(
|
||||
uncommitted_diff.diff_hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot),
|
||||
uncommitted_diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &snapshot, cx),
|
||||
&snapshot,
|
||||
&uncommitted_diff.snapshot.base_text.as_ref().unwrap().text(),
|
||||
&uncommitted_diff.base_text_string().unwrap(),
|
||||
&[(
|
||||
1..2,
|
||||
" println!(\"hello from HEAD\");\n",
|
||||
" println!(\"hello from the working copy\");\n",
|
||||
DiffHunkStatus::modified(),
|
||||
)],
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1246,8 +1246,7 @@ async fn test_remote_git_diffs(cx: &mut TestAppContext, server_cx: &mut TestAppC
|
|||
diff.read_with(cx, |diff, cx| {
|
||||
assert_eq!(diff.base_text_string().unwrap(), text_1);
|
||||
assert_eq!(
|
||||
diff.unstaged_diff
|
||||
.as_ref()
|
||||
diff.secondary_diff()
|
||||
.unwrap()
|
||||
.read(cx)
|
||||
.base_text_string()
|
||||
|
@ -1266,8 +1265,7 @@ async fn test_remote_git_diffs(cx: &mut TestAppContext, server_cx: &mut TestAppC
|
|||
diff.read_with(cx, |diff, cx| {
|
||||
assert_eq!(diff.base_text_string().unwrap(), text_1);
|
||||
assert_eq!(
|
||||
diff.unstaged_diff
|
||||
.as_ref()
|
||||
diff.secondary_diff()
|
||||
.unwrap()
|
||||
.read(cx)
|
||||
.base_text_string()
|
||||
|
@ -1286,8 +1284,7 @@ async fn test_remote_git_diffs(cx: &mut TestAppContext, server_cx: &mut TestAppC
|
|||
diff.read_with(cx, |diff, cx| {
|
||||
assert_eq!(diff.base_text_string().unwrap(), text_2);
|
||||
assert_eq!(
|
||||
diff.unstaged_diff
|
||||
.as_ref()
|
||||
diff.secondary_diff()
|
||||
.unwrap()
|
||||
.read(cx)
|
||||
.base_text_string()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue