Styling for Apply/Discard buttons (#21017)

Change the "Apply" and "Discard" buttons to match @danilo-leal's design!
Here are some different states:

### Cursor in the first hunk

Now that the cursor is in a particular hunk, we show the "Apply" and
"Discard" names, and the keyboard shortcut. If I press the keyboard
shortcut, it will only apply to this hunk.

<img width="759" alt="Screenshot 2024-11-23 at 10 54 45 PM"
src="https://github.com/user-attachments/assets/68e0f109-9493-4ca2-a99c-dfcbb4d1ce0c">

### Cursor in the second hunk

Moving the cursor to a different hunk changes which buttons get the
keyboard shortcut treatment. Now the keyboard shortcut is shown next to
the hunk that will actually be affected if you press that shortcut.

<img width="749" alt="Screenshot 2024-11-23 at 10 56 27 PM"
src="https://github.com/user-attachments/assets/59c2ace3-6972-4a60-b806-f45e8c25eaae">


Release Notes:

- Restyled Apply/Discard buttons

---------

Co-authored-by: Max <max@zed.dev>
Co-authored-by: Danilo Leal <67129314+danilo-leal@users.noreply.github.com>
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Co-authored-by: Bennet Bo Fenner <53836821+bennetbo@users.noreply.github.com>
This commit is contained in:
Richard Feldman 2024-11-26 11:09:43 -05:00 committed by GitHub
parent 8f1ec3d11b
commit 884748038e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 411 additions and 293 deletions

View file

@ -99,7 +99,8 @@ use language::{
use language::{point_to_lsp, BufferRow, CharClassifier, Runnable, RunnableRange};
use linked_editing_ranges::refresh_linked_ranges;
pub use proposed_changes_editor::{
ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
ProposedChangeLocation, ProposedChangesEditor, ProposedChangesToolbar,
ProposedChangesToolbarControls,
};
use similar::{ChangeTag, TextDiff};
use std::iter::Peekable;
@ -160,7 +161,7 @@ use theme::{
};
use ui::{
h_flex, prelude::*, ButtonSize, ButtonStyle, Disclosure, IconButton, IconName, IconSize,
ListItem, Popover, PopoverMenuHandle, Tooltip,
ListItem, Popover, Tooltip,
};
use util::{defer, maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
use workspace::item::{ItemHandle, PreviewTabsSettings};
@ -590,7 +591,6 @@ pub struct Editor {
nav_history: Option<ItemNavHistory>,
context_menu: RwLock<Option<ContextMenu>>,
mouse_context_menu: Option<MouseContextMenu>,
hunk_controls_menu_handle: PopoverMenuHandle<ui::ContextMenu>,
completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
signature_help_state: SignatureHelpState,
auto_signature_help: Option<bool>,
@ -2112,7 +2112,6 @@ impl Editor {
nav_history: None,
context_menu: RwLock::new(None),
mouse_context_menu: None,
hunk_controls_menu_handle: PopoverMenuHandle::default(),
completion_tasks: Default::default(),
signature_help_state: SignatureHelpState::default(),
auto_signature_help: None,
@ -13558,20 +13557,24 @@ fn test_wrap_with_prefix() {
);
}
fn is_hunk_selected(hunk: &MultiBufferDiffHunk, selections: &[Selection<Point>]) -> bool {
let mut buffer_rows_for_selections = selections.iter().map(|selection| {
let start = MultiBufferRow(selection.start.row);
let end = MultiBufferRow(selection.end.row);
start..end
});
buffer_rows_for_selections.any(|range| does_selection_touch_hunk(&range, hunk))
}
fn hunks_for_selections(
multi_buffer_snapshot: &MultiBufferSnapshot,
selections: &[Selection<Anchor>],
) -> Vec<MultiBufferDiffHunk> {
let buffer_rows_for_selections = selections.iter().map(|selection| {
let head = selection.head();
let tail = selection.tail();
let start = MultiBufferRow(tail.to_point(multi_buffer_snapshot).row);
let end = MultiBufferRow(head.to_point(multi_buffer_snapshot).row);
if start > end {
end..start
} else {
start..end
}
let start = MultiBufferRow(selection.start.to_point(multi_buffer_snapshot).row);
let end = MultiBufferRow(selection.end.to_point(multi_buffer_snapshot).row);
start..end
});
hunks_for_rows(buffer_rows_for_selections, multi_buffer_snapshot)
@ -13588,19 +13591,8 @@ pub fn hunks_for_rows(
let query_rows =
selected_multi_buffer_rows.start..selected_multi_buffer_rows.end.next_row();
for hunk in multi_buffer_snapshot.git_diff_hunks_in_range(query_rows.clone()) {
// 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(&hunk) == DiffHunkStatus::Removed;
let related_to_selection = if allow_adjacent {
hunk.row_range.overlaps(&query_rows)
|| hunk.row_range.start == query_rows.end
|| hunk.row_range.end == query_rows.start
} else {
// `selected_multi_buffer_rows` are inclusive (e.g. [2..2] means 2nd row is selected)
// `hunk.row_range` is exclusive (e.g. [2..3] means 2nd row is selected)
hunk.row_range.overlaps(&selected_multi_buffer_rows)
|| selected_multi_buffer_rows.end == hunk.row_range.start
};
let related_to_selection =
does_selection_touch_hunk(&selected_multi_buffer_rows, &hunk);
if related_to_selection {
if !processed_buffer_rows
.entry(hunk.buffer_id)
@ -13617,6 +13609,26 @@ pub fn hunks_for_rows(
hunks
}
fn does_selection_touch_hunk(
selected_multi_buffer_rows: &Range<MultiBufferRow>,
hunk: &MultiBufferDiffHunk,
) -> bool {
let query_rows = selected_multi_buffer_rows.start..selected_multi_buffer_rows.end.next_row();
// 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(hunk) == DiffHunkStatus::Removed;
if allow_adjacent {
hunk.row_range.overlaps(&query_rows)
|| hunk.row_range.start == query_rows.end
|| hunk.row_range.end == query_rows.start
} else {
// `selected_multi_buffer_rows` are inclusive (e.g. [2..2] means 2nd row is selected)
// `hunk.row_range` is exclusive (e.g. [2..3] means 2nd row is selected)
hunk.row_range.overlaps(selected_multi_buffer_rows)
|| selected_multi_buffer_rows.end == hunk.row_range.start
}
}
pub trait CollaborationHub {
fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator>;
fn user_participant_indices<'a>(