Merge branch 'main' into project_search2

This commit is contained in:
Piotr Osiewicz 2023-12-11 16:47:48 +01:00
commit ddbd5cf2cb
145 changed files with 16798 additions and 12900 deletions

View file

@ -13,6 +13,7 @@ mod link_go_to_definition;
mod mouse_context_menu;
pub mod movement;
mod persistence;
mod rust_analyzer_ext;
pub mod scroll;
pub mod selections_collection;
@ -39,8 +40,8 @@ use futures::FutureExt;
use fuzzy::{StringMatch, StringMatchCandidate};
use git::diff_hunk_to_display;
use gpui::{
actions, div, point, prelude::*, px, relative, rems, size, uniform_list, Action, AnyElement,
AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Context,
actions, div, impl_actions, point, prelude::*, px, relative, rems, size, uniform_list, Action,
AnyElement, AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Context,
DispatchPhase, Div, ElementId, EventEmitter, FocusHandle, FocusableView, FontFeatures,
FontStyle, FontWeight, HighlightStyle, Hsla, InputHandler, InteractiveText, KeyContext, Model,
MouseButton, ParentElement, Pixels, Render, RenderOnce, SharedString, Styled, StyledText,
@ -107,7 +108,7 @@ use ui::{
use ui::{prelude::*, IconSize};
use util::{post_inc, RangeExt, ResultExt, TryFutureExt};
use workspace::{
item::{ItemEvent, ItemHandle},
item::{Item, ItemEvent, ItemHandle},
searchable::SearchEvent,
ItemNavHistory, Pane, SplitDirection, ViewId, Workspace,
};
@ -185,82 +186,101 @@ pub fn render_parsed_markdown(
})
}
#[derive(PartialEq, Clone, Deserialize, Default, Action)]
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct SelectNext {
#[serde(default)]
pub replace_newest: bool,
}
#[derive(PartialEq, Clone, Deserialize, Default, Action)]
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct SelectPrevious {
#[serde(default)]
pub replace_newest: bool,
}
#[derive(PartialEq, Clone, Deserialize, Default, Action)]
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct SelectAllMatches {
#[serde(default)]
pub replace_newest: bool,
}
#[derive(PartialEq, Clone, Deserialize, Default, Action)]
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct SelectToBeginningOfLine {
#[serde(default)]
stop_at_soft_wraps: bool,
}
#[derive(PartialEq, Clone, Deserialize, Default, Action)]
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct MovePageUp {
#[serde(default)]
center_cursor: bool,
}
#[derive(PartialEq, Clone, Deserialize, Default, Action)]
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct MovePageDown {
#[serde(default)]
center_cursor: bool,
}
#[derive(PartialEq, Clone, Deserialize, Default, Action)]
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct SelectToEndOfLine {
#[serde(default)]
stop_at_soft_wraps: bool,
}
#[derive(PartialEq, Clone, Deserialize, Default, Action)]
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct ToggleCodeActions {
#[serde(default)]
pub deployed_from_indicator: bool,
}
#[derive(PartialEq, Clone, Deserialize, Default, Action)]
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct ConfirmCompletion {
#[serde(default)]
pub item_ix: Option<usize>,
}
#[derive(PartialEq, Clone, Deserialize, Default, Action)]
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct ConfirmCodeAction {
#[serde(default)]
pub item_ix: Option<usize>,
}
#[derive(PartialEq, Clone, Deserialize, Default, Action)]
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct ToggleComments {
#[serde(default)]
pub advance_downwards: bool,
}
#[derive(PartialEq, Clone, Deserialize, Default, Action)]
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct FoldAt {
pub buffer_row: u32,
}
#[derive(PartialEq, Clone, Deserialize, Default, Action)]
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct UnfoldAt {
pub buffer_row: u32,
}
impl_actions!(
editor,
[
SelectNext,
SelectPrevious,
SelectAllMatches,
SelectToBeginningOfLine,
MovePageUp,
MovePageDown,
SelectToEndOfLine,
ToggleCodeActions,
ConfirmCompletion,
ConfirmCodeAction,
ToggleComments,
FoldAt,
UnfoldAt
]
);
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum InlayId {
Suggestion(usize),
@ -277,121 +297,125 @@ impl InlayId {
}
actions!(
AddSelectionAbove,
AddSelectionBelow,
Backspace,
Cancel,
ConfirmRename,
ContextMenuFirst,
ContextMenuLast,
ContextMenuNext,
ContextMenuPrev,
ConvertToKebabCase,
ConvertToLowerCamelCase,
ConvertToLowerCase,
ConvertToSnakeCase,
ConvertToTitleCase,
ConvertToUpperCamelCase,
ConvertToUpperCase,
Copy,
CopyHighlightJson,
CopyPath,
CopyRelativePath,
Cut,
CutToEndOfLine,
Delete,
DeleteLine,
DeleteToBeginningOfLine,
DeleteToEndOfLine,
DeleteToNextSubwordEnd,
DeleteToNextWordEnd,
DeleteToPreviousSubwordStart,
DeleteToPreviousWordStart,
DuplicateLine,
FindAllReferences,
Fold,
FoldSelectedRanges,
Format,
GoToDefinition,
GoToDefinitionSplit,
GoToDiagnostic,
GoToHunk,
GoToPrevDiagnostic,
GoToPrevHunk,
GoToTypeDefinition,
GoToTypeDefinitionSplit,
HalfPageDown,
HalfPageUp,
Hover,
Indent,
JoinLines,
LineDown,
LineUp,
MoveDown,
MoveLeft,
MoveLineDown,
MoveLineUp,
MoveRight,
MoveToBeginning,
MoveToBeginningOfLine,
MoveToEnclosingBracket,
MoveToEnd,
MoveToEndOfLine,
MoveToEndOfParagraph,
MoveToNextSubwordEnd,
MoveToNextWordEnd,
MoveToPreviousSubwordStart,
MoveToPreviousWordStart,
MoveToStartOfParagraph,
MoveUp,
Newline,
NewlineAbove,
NewlineBelow,
NextScreen,
OpenExcerpts,
Outdent,
PageDown,
PageUp,
Paste,
Redo,
RedoSelection,
Rename,
RestartLanguageServer,
RevealInFinder,
ReverseLines,
ScrollCursorBottom,
ScrollCursorCenter,
ScrollCursorTop,
SelectAll,
SelectDown,
SelectLargerSyntaxNode,
SelectLeft,
SelectLine,
SelectRight,
SelectSmallerSyntaxNode,
SelectToBeginning,
SelectToEnd,
SelectToEndOfParagraph,
SelectToNextSubwordEnd,
SelectToNextWordEnd,
SelectToPreviousSubwordStart,
SelectToPreviousWordStart,
SelectToStartOfParagraph,
SelectUp,
ShowCharacterPalette,
ShowCompletions,
ShuffleLines,
SortLinesCaseInsensitive,
SortLinesCaseSensitive,
SplitSelectionIntoLines,
Tab,
TabPrev,
ToggleInlayHints,
ToggleSoftWrap,
Transpose,
Undo,
UndoSelection,
UnfoldLines,
editor,
[
AddSelectionAbove,
AddSelectionBelow,
Backspace,
Cancel,
ConfirmRename,
ContextMenuFirst,
ContextMenuLast,
ContextMenuNext,
ContextMenuPrev,
ConvertToKebabCase,
ConvertToLowerCamelCase,
ConvertToLowerCase,
ConvertToSnakeCase,
ConvertToTitleCase,
ConvertToUpperCamelCase,
ConvertToUpperCase,
Copy,
CopyHighlightJson,
CopyPath,
CopyRelativePath,
Cut,
CutToEndOfLine,
Delete,
DeleteLine,
DeleteToBeginningOfLine,
DeleteToEndOfLine,
DeleteToNextSubwordEnd,
DeleteToNextWordEnd,
DeleteToPreviousSubwordStart,
DeleteToPreviousWordStart,
DuplicateLine,
ExpandMacroRecursively,
FindAllReferences,
Fold,
FoldSelectedRanges,
Format,
GoToDefinition,
GoToDefinitionSplit,
GoToDiagnostic,
GoToHunk,
GoToPrevDiagnostic,
GoToPrevHunk,
GoToTypeDefinition,
GoToTypeDefinitionSplit,
HalfPageDown,
HalfPageUp,
Hover,
Indent,
JoinLines,
LineDown,
LineUp,
MoveDown,
MoveLeft,
MoveLineDown,
MoveLineUp,
MoveRight,
MoveToBeginning,
MoveToBeginningOfLine,
MoveToEnclosingBracket,
MoveToEnd,
MoveToEndOfLine,
MoveToEndOfParagraph,
MoveToNextSubwordEnd,
MoveToNextWordEnd,
MoveToPreviousSubwordStart,
MoveToPreviousWordStart,
MoveToStartOfParagraph,
MoveUp,
Newline,
NewlineAbove,
NewlineBelow,
NextScreen,
OpenExcerpts,
Outdent,
PageDown,
PageUp,
Paste,
Redo,
RedoSelection,
Rename,
RestartLanguageServer,
RevealInFinder,
ReverseLines,
ScrollCursorBottom,
ScrollCursorCenter,
ScrollCursorTop,
SelectAll,
SelectDown,
SelectLargerSyntaxNode,
SelectLeft,
SelectLine,
SelectRight,
SelectSmallerSyntaxNode,
SelectToBeginning,
SelectToEnd,
SelectToEndOfParagraph,
SelectToNextSubwordEnd,
SelectToNextWordEnd,
SelectToPreviousSubwordStart,
SelectToPreviousWordStart,
SelectToStartOfParagraph,
SelectUp,
ShowCharacterPalette,
ShowCompletions,
ShuffleLines,
SortLinesCaseInsensitive,
SortLinesCaseSensitive,
SplitSelectionIntoLines,
Tab,
TabPrev,
ToggleInlayHints,
ToggleSoftWrap,
Transpose,
Undo,
UndoSelection,
UnfoldLines,
]
);
enum DocumentHighlightRead {}
@ -9319,7 +9343,6 @@ impl Render for Editor {
scrollbar_width: px(12.),
syntax: cx.theme().syntax().clone(),
diagnostic_style: cx.theme().diagnostic_style(),
// TODO kb find `HighlightStyle` usages
// todo!("what about the rest of the highlight style parts?")
inlays_style: HighlightStyle {
color: Some(cx.theme().status().hint),

View file

@ -32,7 +32,7 @@ use gpui::{
Style, Styled, TextRun, TextStyle, View, ViewContext, WeakView, WindowContext, WrappedLine,
};
use itertools::Itertools;
use language::language_settings::ShowWhitespaceSetting;
use language::{language_settings::ShowWhitespaceSetting, Language};
use multi_buffer::Anchor;
use project::{
project_settings::{GitGutterSetting, ProjectSettings},
@ -135,11 +135,13 @@ impl EditorElement {
fn register_actions(&self, cx: &mut WindowContext) {
let view = &self.editor;
self.editor.update(cx, |editor, cx| {
view.update(cx, |editor, cx| {
for action in editor.editor_actions.iter() {
(action)(cx)
}
});
crate::rust_analyzer_ext::apply_related_actions(view, cx);
register_action(view, cx, Editor::move_left);
register_action(view, cx, Editor::move_right);
register_action(view, cx, Editor::move_down);
@ -385,17 +387,17 @@ impl EditorElement {
gutter_bounds: Bounds<Pixels>,
stacking_order: &StackingOrder,
cx: &mut ViewContext<Editor>,
) -> bool {
) {
let mut click_count = event.click_count;
let modifiers = event.modifiers;
if gutter_bounds.contains_point(&event.position) {
click_count = 3; // Simulate triple-click when clicking the gutter to select lines
} else if !text_bounds.contains_point(&event.position) {
return false;
return;
}
if !cx.was_top_layer(&event.position, stacking_order) {
return false;
return;
}
let point_for_position = position_map.point_for_position(text_bounds, event.position);
@ -427,7 +429,7 @@ impl EditorElement {
);
}
true
cx.stop_propagation();
}
fn mouse_right_down(
@ -436,9 +438,9 @@ impl EditorElement {
position_map: &PositionMap,
text_bounds: Bounds<Pixels>,
cx: &mut ViewContext<Editor>,
) -> bool {
) {
if !text_bounds.contains_point(&event.position) {
return false;
return;
}
let point_for_position = position_map.point_for_position(text_bounds, event.position);
mouse_context_menu::deploy_context_menu(
@ -447,7 +449,7 @@ impl EditorElement {
point_for_position.previous_valid,
cx,
);
true
cx.stop_propagation();
}
fn mouse_up(
@ -457,7 +459,7 @@ impl EditorElement {
text_bounds: Bounds<Pixels>,
stacking_order: &StackingOrder,
cx: &mut ViewContext<Editor>,
) -> bool {
) {
let end_selection = editor.has_pending_selection();
let pending_nonempty_selections = editor.has_pending_nonempty_selection();
@ -479,10 +481,10 @@ impl EditorElement {
go_to_fetched_definition(editor, point, split, cx);
}
return true;
cx.stop_propagation();
} else if end_selection {
cx.stop_propagation();
}
end_selection
}
fn mouse_moved(
@ -493,7 +495,7 @@ impl EditorElement {
gutter_bounds: Bounds<Pixels>,
stacking_order: &StackingOrder,
cx: &mut ViewContext<Editor>,
) -> bool {
) {
let modifiers = event.modifiers;
if editor.has_pending_selection() && event.pressed_button == Some(MouseButton::Left) {
let point_for_position = position_map.point_for_position(text_bounds, event.position);
@ -562,11 +564,13 @@ impl EditorElement {
}
}
true
cx.stop_propagation();
} else {
update_go_to_definition_link(editor, None, modifiers.command, modifiers.shift, cx);
hover_at(editor, None, cx);
gutter_hovered && was_top
if gutter_hovered && was_top {
cx.stop_propagation();
}
}
}
@ -576,9 +580,9 @@ impl EditorElement {
position_map: &PositionMap,
bounds: &InteractiveBounds,
cx: &mut ViewContext<Editor>,
) -> bool {
) {
if !bounds.visibly_contains(&event.position, cx) {
return false;
return;
}
let line_height = position_map.line_height;
@ -602,8 +606,7 @@ impl EditorElement {
let y = f32::from((scroll_position.y * line_height - delta.y) / line_height);
let scroll_position = point(x, y).clamp(&point(0., 0.), &position_map.scroll_max);
editor.scroll(scroll_position, axis, cx);
true
cx.stop_propagation();
}
fn paint_background(
@ -749,44 +752,47 @@ impl EditorElement {
}
}
for (ix, fold_indicator) in layout.fold_indicators.drain(..).enumerate() {
if let Some(mut fold_indicator) = fold_indicator {
let mut fold_indicator = fold_indicator.into_any_element();
cx.with_z_index(1, |cx| {
for (ix, fold_indicator) in layout.fold_indicators.drain(..).enumerate() {
if let Some(mut fold_indicator) = fold_indicator {
let mut fold_indicator = fold_indicator.into_any_element();
let available_space = size(
AvailableSpace::MinContent,
AvailableSpace::Definite(line_height * 0.55),
);
let fold_indicator_size = fold_indicator.measure(available_space, cx);
let position = point(
bounds.size.width - layout.gutter_padding,
ix as f32 * line_height - (scroll_top % line_height),
);
let centering_offset = point(
(layout.gutter_padding + layout.gutter_margin - fold_indicator_size.width)
/ 2.,
(line_height - fold_indicator_size.height) / 2.,
);
let origin = bounds.origin + position + centering_offset;
fold_indicator.draw(origin, available_space, cx);
}
}
if let Some(indicator) = layout.code_actions_indicator.take() {
let mut button = indicator.button.into_any_element();
let available_space = size(
AvailableSpace::MinContent,
AvailableSpace::Definite(line_height * 0.55),
AvailableSpace::Definite(line_height),
);
let fold_indicator_size = fold_indicator.measure(available_space, cx);
let indicator_size = button.measure(available_space, cx);
let position = point(
bounds.size.width - layout.gutter_padding,
ix as f32 * line_height - (scroll_top % line_height),
);
let centering_offset = point(
(layout.gutter_padding + layout.gutter_margin - fold_indicator_size.width) / 2.,
(line_height - fold_indicator_size.height) / 2.,
);
let origin = bounds.origin + position + centering_offset;
fold_indicator.draw(origin, available_space, cx);
let mut x = Pixels::ZERO;
let mut y = indicator.row as f32 * line_height - scroll_top;
// Center indicator.
x += ((layout.gutter_padding + layout.gutter_margin) - indicator_size.width) / 2.;
y += (line_height - indicator_size.height) / 2.;
button.draw(bounds.origin + point(x, y), available_space, cx);
}
}
if let Some(indicator) = layout.code_actions_indicator.take() {
let mut button = indicator.button.into_any_element();
let available_space = size(
AvailableSpace::MinContent,
AvailableSpace::Definite(line_height),
);
let indicator_size = button.measure(available_space, cx);
let mut x = Pixels::ZERO;
let mut y = indicator.row as f32 * line_height - scroll_top;
// Center indicator.
x += ((layout.gutter_padding + layout.gutter_margin) - indicator_size.width) / 2.;
y += (line_height - indicator_size.height) / 2.;
button.draw(bounds.origin + point(x, y), available_space, cx);
}
});
}
fn paint_diff_hunks(bounds: Bounds<Pixels>, layout: &LayoutState, cx: &mut WindowContext) {
@ -824,8 +830,8 @@ impl EditorElement {
};
let color = match status {
DiffHunkStatus::Added => gpui::green(), // todo!("use the appropriate color")
DiffHunkStatus::Modified => gpui::yellow(), // todo!("use the appropriate color")
DiffHunkStatus::Added => cx.theme().status().created,
DiffHunkStatus::Modified => cx.theme().status().modified,
//TODO: This rendering is entirely a horrible hack
DiffHunkStatus::Removed => {
@ -842,7 +848,7 @@ impl EditorElement {
cx.paint_quad(
highlight_bounds,
Corners::all(1. * line_height),
gpui::red(), // todo!("use the right color")
cx.theme().status().deleted,
Edges::default(),
transparent_black(),
);
@ -1230,203 +1236,216 @@ impl EditorElement {
bounds.upper_right().x - self.style.scrollbar_width
}
// fn paint_scrollbar(
// &mut self,
// bounds: Bounds<Pixels>,
// layout: &mut LayoutState,
// editor: &Editor,
// cx: &mut ViewContext<Editor>,
// ) {
// enum ScrollbarMouseHandlers {}
// if layout.mode != EditorMode::Full {
// return;
// }
fn paint_scrollbar(
&mut self,
bounds: Bounds<Pixels>,
layout: &mut LayoutState,
cx: &mut WindowContext,
) {
if layout.mode != EditorMode::Full {
return;
}
// let style = &self.style.theme.scrollbar;
let top = bounds.origin.y;
let bottom = bounds.lower_left().y;
let right = bounds.lower_right().x;
let left = self.scrollbar_left(&bounds);
let row_range = layout.scrollbar_row_range.clone();
let max_row = layout.max_row as f32 + (row_range.end - row_range.start);
// let top = bounds.min_y;
// let bottom = bounds.max_y;
// let right = bounds.max_x;
// let left = self.scrollbar_left(&bounds);
// let row_range = &layout.scrollbar_row_range;
// let max_row = layout.max_row as f32 + (row_range.end - row_range.start);
let mut height = bounds.size.height;
let mut first_row_y_offset = px(0.0);
// let mut height = bounds.height();
// let mut first_row_y_offset = 0.0;
// Impose a minimum height on the scrollbar thumb
let row_height = height / max_row;
let min_thumb_height = layout.position_map.line_height;
let thumb_height = (row_range.end - row_range.start) * row_height;
if thumb_height < min_thumb_height {
first_row_y_offset = (min_thumb_height - thumb_height) / 2.0;
height -= min_thumb_height - thumb_height;
}
// // Impose a minimum height on the scrollbar thumb
// let row_height = height / max_row;
// let min_thumb_height =
// style.min_height_factor * cx.font_cache.line_height(self.style.text.font_size);
// let thumb_height = (row_range.end - row_range.start) * row_height;
// if thumb_height < min_thumb_height {
// first_row_y_offset = (min_thumb_height - thumb_height) / 2.0;
// height -= min_thumb_height - thumb_height;
// }
let y_for_row = |row: f32| -> Pixels { top + first_row_y_offset + row * row_height };
// let y_for_row = |row: f32| -> f32 { top + first_row_y_offset + row * row_height };
let thumb_top = y_for_row(row_range.start) - first_row_y_offset;
let thumb_bottom = y_for_row(row_range.end) + first_row_y_offset;
let track_bounds = Bounds::from_corners(point(left, top), point(right, bottom));
let thumb_bounds = Bounds::from_corners(point(left, thumb_top), point(right, thumb_bottom));
// let thumb_top = y_for_row(row_range.start) - first_row_y_offset;
// let thumb_bottom = y_for_row(row_range.end) + first_row_y_offset;
// let track_bounds = Bounds::<Pixels>::from_points(point(left, top), point(right, bottom));
// let thumb_bounds = Bounds::<Pixels>::from_points(point(left, thumb_top), point(right, thumb_bottom));
if layout.show_scrollbars {
cx.paint_quad(
track_bounds,
Corners::default(),
gpui::blue(), // todo!("style.track.background_color")
Edges::default(), // todo!("style.track.border")
transparent_black(), // todo!("style.track.border")
);
let scrollbar_settings = EditorSettings::get_global(cx).scrollbar;
if layout.is_singleton && scrollbar_settings.selections {
let start_anchor = Anchor::min();
let end_anchor = Anchor::max();
let background_ranges = self
.editor
.read(cx)
.background_highlight_row_ranges::<crate::items::BufferSearchHighlights>(
start_anchor..end_anchor,
&layout.position_map.snapshot,
50000,
);
for range in background_ranges {
let start_y = y_for_row(range.start().row() as f32);
let mut end_y = y_for_row(range.end().row() as f32);
if end_y - start_y < px(1.) {
end_y = start_y + px(1.);
}
let bounds = Bounds::from_corners(point(left, start_y), point(right, end_y));
cx.paint_quad(
bounds,
Corners::default(),
gpui::yellow(), // todo!("theme.editor.scrollbar")
Edges {
top: Pixels::ZERO,
right: px(1.),
bottom: Pixels::ZERO,
left: px(1.),
},
gpui::green(), // todo!("style.thumb.border.color")
);
}
}
// if layout.show_scrollbars {
// cx.paint_quad(Quad {
// bounds: track_bounds,
// border: style.track.border.into(),
// background: style.track.background_color,
// ..Default::default()
// });
// let scrollbar_settings = settings::get::<EditorSettings>(cx).scrollbar;
// let theme = theme::current(cx);
// let scrollbar_theme = &theme.editor.scrollbar;
// if layout.is_singleton && scrollbar_settings.selections {
// let start_anchor = Anchor::min();
// let end_anchor = Anchor::max;
// let color = scrollbar_theme.selections;
// let border = Border {
// width: 1.,
// color: style.thumb.border.color,
// overlay: false,
// top: false,
// right: true,
// bottom: false,
// left: true,
// };
// let mut push_region = |start: DisplayPoint, end: DisplayPoint| {
// let start_y = y_for_row(start.row() as f32);
// let mut end_y = y_for_row(end.row() as f32);
// if end_y - start_y < 1. {
// end_y = start_y + 1.;
// }
// let bounds = Bounds::<Pixels>::from_points(point(left, start_y), point(right, end_y));
if layout.is_singleton && scrollbar_settings.git_diff {
for hunk in layout
.position_map
.snapshot
.buffer_snapshot
.git_diff_hunks_in_range(0..(max_row.floor() as u32))
{
let start_display = Point::new(hunk.buffer_range.start, 0)
.to_display_point(&layout.position_map.snapshot.display_snapshot);
let end_display = Point::new(hunk.buffer_range.end, 0)
.to_display_point(&layout.position_map.snapshot.display_snapshot);
let start_y = y_for_row(start_display.row() as f32);
let mut end_y = if hunk.buffer_range.start == hunk.buffer_range.end {
y_for_row((end_display.row() + 1) as f32)
} else {
y_for_row((end_display.row()) as f32)
};
// cx.paint_quad(Quad {
// bounds,
// background: Some(color),
// border: border.into(),
// corner_radii: style.thumb.corner_radii.into(),
// })
// };
// let background_ranges = editor
// .background_highlight_row_ranges::<crate::items::BufferSearchHighlights>(
// start_anchor..end_anchor,
// &layout.position_map.snapshot,
// 50000,
// );
// for row in background_ranges {
// let start = row.start();
// let end = row.end();
// push_region(*start, *end);
// }
// }
if end_y - start_y < px(1.) {
end_y = start_y + px(1.);
}
let bounds = Bounds::from_corners(point(left, start_y), point(right, end_y));
// if layout.is_singleton && scrollbar_settings.git_diff {
// let diff_style = scrollbar_theme.git.clone();
// for hunk in layout
// .position_map
// .snapshot
// .buffer_snapshot
// .git_diff_hunks_in_range(0..(max_row.floor() as u32))
// {
// let start_display = Point::new(hunk.buffer_range.start, 0)
// .to_display_point(&layout.position_map.snapshot.display_snapshot);
// let end_display = Point::new(hunk.buffer_range.end, 0)
// .to_display_point(&layout.position_map.snapshot.display_snapshot);
// let start_y = y_for_row(start_display.row() as f32);
// let mut end_y = if hunk.buffer_range.start == hunk.buffer_range.end {
// y_for_row((end_display.row() + 1) as f32)
// } else {
// y_for_row((end_display.row()) as f32)
// };
let color = match hunk.status() {
DiffHunkStatus::Added => gpui::green(), // todo!("use the right color")
DiffHunkStatus::Modified => gpui::yellow(), // todo!("use the right color")
DiffHunkStatus::Removed => gpui::red(), // todo!("use the right color")
};
cx.paint_quad(
bounds,
Corners::default(),
color,
Edges {
top: Pixels::ZERO,
right: px(1.),
bottom: Pixels::ZERO,
left: px(1.),
},
gpui::green(), // todo!("style.thumb.border.color")
);
}
}
// if end_y - start_y < 1. {
// end_y = start_y + 1.;
// }
// let bounds = Bounds::<Pixels>::from_points(point(left, start_y), point(right, end_y));
cx.paint_quad(
thumb_bounds,
Corners::default(),
gpui::black(), // todo!("style.thumb.background_color")
Edges {
top: Pixels::ZERO,
right: px(1.),
bottom: Pixels::ZERO,
left: px(1.),
},
gpui::green(), // todo!("style.thumb.border.color")
);
}
// let color = match hunk.status() {
// DiffHunkStatus::Added => diff_style.inserted,
// DiffHunkStatus::Modified => diff_style.modified,
// DiffHunkStatus::Removed => diff_style.deleted,
// };
let mouse_position = cx.mouse_position();
if track_bounds.contains_point(&mouse_position) {
cx.set_cursor_style(CursorStyle::Arrow);
}
// let border = Border {
// width: 1.,
// color: style.thumb.border.color,
// overlay: false,
// top: false,
// right: true,
// bottom: false,
// left: true,
// };
cx.on_mouse_event({
let editor = self.editor.clone();
move |event: &MouseMoveEvent, phase, cx| {
if phase == DispatchPhase::Capture {
return;
}
// cx.paint_quad(Quad {
// bounds,
// background: Some(color),
// border: border.into(),
// corner_radii: style.thumb.corner_radii.into(),
// })
// }
// }
editor.update(cx, |editor, cx| {
if event.pressed_button == Some(MouseButton::Left)
&& editor.scroll_manager.is_dragging_scrollbar()
{
let y = mouse_position.y;
let new_y = event.position.y;
if thumb_top < y && y < thumb_bottom {
let mut position = editor.scroll_position(cx);
position.y += (new_y - y) * (max_row as f32) / height;
if position.y < 0.0 {
position.y = 0.0;
}
editor.set_scroll_position(position, cx);
}
cx.stop_propagation();
} else {
editor.scroll_manager.set_is_dragging_scrollbar(false, cx);
if track_bounds.contains_point(&event.position) {
editor.scroll_manager.show_scrollbar(cx);
}
}
})
}
});
// cx.paint_quad(Quad {
// bounds: thumb_bounds,
// border: style.thumb.border.into(),
// background: style.thumb.background_color,
// corner_radii: style.thumb.corner_radii.into(),
// });
// }
if self.editor.read(cx).scroll_manager.is_dragging_scrollbar() {
cx.on_mouse_event({
let editor = self.editor.clone();
move |event: &MouseUpEvent, phase, cx| {
editor.update(cx, |editor, cx| {
editor.scroll_manager.set_is_dragging_scrollbar(false, cx);
cx.stop_propagation();
});
}
});
} else {
cx.on_mouse_event({
let editor = self.editor.clone();
move |event: &MouseDownEvent, phase, cx| {
editor.update(cx, |editor, cx| {
if track_bounds.contains_point(&event.position) {
editor.scroll_manager.set_is_dragging_scrollbar(true, cx);
// cx.scene().push_cursor_region(CursorRegion {
// bounds: track_bounds,
// style: CursorStyle::Arrow,
// });
// let region_id = cx.view_id();
// cx.scene().push_mouse_region(
// MouseRegion::new::<ScrollbarMouseHandlers>(region_id, region_id, track_bounds)
// .on_move(move |event, editor: &mut Editor, cx| {
// if event.pressed_button.is_none() {
// editor.scroll_manager.show_scrollbar(cx);
// }
// })
// .on_down(MouseButton::Left, {
// let row_range = row_range.clone();
// move |event, editor: &mut Editor, cx| {
// let y = event.position.y;
// if y < thumb_top || thumb_bottom < y {
// let center_row = ((y - top) * max_row as f32 / height).round() as u32;
// let top_row = center_row
// .saturating_sub((row_range.end - row_range.start) as u32 / 2);
// let mut position = editor.scroll_position(cx);
// position.set_y(top_row as f32);
// editor.set_scroll_position(position, cx);
// } else {
// editor.scroll_manager.show_scrollbar(cx);
// }
// }
// })
// .on_drag(MouseButton::Left, {
// move |event, editor: &mut Editor, cx| {
// if event.end {
// return;
// }
let y = event.position.y;
if y < thumb_top || thumb_bottom < y {
let center_row =
((y - top) * max_row as f32 / height).round() as u32;
let top_row = center_row
.saturating_sub((row_range.end - row_range.start) as u32 / 2);
let mut position = editor.scroll_position(cx);
position.y = top_row as f32;
editor.set_scroll_position(position, cx);
} else {
editor.scroll_manager.show_scrollbar(cx);
}
// let y = event.prev_mouse_position.y;
// let new_y = event.position.y;
// if thumb_top < y && y < thumb_bottom {
// let mut position = editor.scroll_position(cx);
// position.set_y(position.y + (new_y - y) * (max_row as f32) / height);
// if position.y < 0.0 {
// position.set_y(0.);
// }
// editor.set_scroll_position(position, cx);
// }
// }
// }),
// );
// }
cx.stop_propagation();
}
});
}
});
}
}
#[allow(clippy::too_many_arguments)]
fn paint_highlighted_range(
@ -2452,12 +2471,9 @@ impl EditorElement {
return;
}
let handled = editor.update(cx, |editor, cx| {
editor.update(cx, |editor, cx| {
Self::scroll(editor, event, &position_map, &interactive_bounds, cx)
});
if handled {
cx.stop_propagation();
}
}
});
@ -2471,7 +2487,7 @@ impl EditorElement {
return;
}
let handled = match event.button {
match event.button {
MouseButton::Left => editor.update(cx, |editor, cx| {
Self::mouse_left_down(
editor,
@ -2486,12 +2502,8 @@ impl EditorElement {
MouseButton::Right => editor.update(cx, |editor, cx| {
Self::mouse_right_down(editor, event, &position_map, text_bounds, cx)
}),
_ => false,
_ => {}
};
if handled {
cx.stop_propagation()
}
}
});
@ -2501,7 +2513,7 @@ impl EditorElement {
let stacking_order = cx.stacking_order().clone();
move |event: &MouseUpEvent, phase, cx| {
let handled = editor.update(cx, |editor, cx| {
editor.update(cx, |editor, cx| {
Self::mouse_up(
editor,
event,
@ -2511,10 +2523,6 @@ impl EditorElement {
cx,
)
});
if handled {
cx.stop_propagation()
}
}
});
cx.on_mouse_event({
@ -2527,7 +2535,7 @@ impl EditorElement {
return;
}
let stop_propogating = editor.update(cx, |editor, cx| {
editor.update(cx, |editor, cx| {
Self::mouse_moved(
editor,
event,
@ -2538,10 +2546,6 @@ impl EditorElement {
cx,
)
});
if stop_propogating {
cx.stop_propagation()
}
}
});
}
@ -2840,9 +2844,11 @@ impl Element for EditorElement {
cx.with_z_index(1, |cx| {
cx.with_element_id(Some("editor_blocks"), |cx| {
self.paint_blocks(bounds, &mut layout, cx);
})
});
})
}
cx.with_z_index(2, |cx| self.paint_scrollbar(bounds, &mut layout, cx));
});
});
})
@ -2944,7 +2950,7 @@ impl PositionMap {
) -> PointForPosition {
let scroll_position = self.snapshot.scroll_position();
let position = position - text_bounds.origin;
let y = position.y.max(px(0.)).min(self.size.width);
let y = position.y.max(px(0.)).min(self.size.height);
let x = position.x + (scroll_position.x * self.em_width);
let row = (f32::from(y / self.line_height) + scroll_position.y) as u32;

View file

@ -26,7 +26,7 @@ pub const MIN_POPOVER_CHARACTER_WIDTH: f32 = 20.;
pub const MIN_POPOVER_LINE_HEIGHT: Pixels = px(4.);
pub const HOVER_POPOVER_GAP: Pixels = px(10.);
actions!(Hover);
actions!(editor, [Hover]);
/// Bindable action which uses the most recent selection head to trigger a hover
pub fn hover(editor: &mut Editor, _: &Hover, cx: &mut ViewContext<Editor>) {

View file

@ -0,0 +1,119 @@
use std::sync::Arc;
use anyhow::Context as _;
use gpui::{Context, Model, View, ViewContext, VisualContext, WindowContext};
use language::Language;
use multi_buffer::MultiBuffer;
use project::lsp_ext_command::ExpandMacro;
use text::ToPointUtf16;
use crate::{element::register_action, Editor, ExpandMacroRecursively};
pub fn apply_related_actions(editor: &View<Editor>, cx: &mut WindowContext) {
let is_rust_related = editor.update(cx, |editor, cx| {
editor
.buffer()
.read(cx)
.all_buffers()
.iter()
.any(|b| match b.read(cx).language() {
Some(l) => is_rust_language(l),
None => false,
})
});
if is_rust_related {
register_action(editor, cx, expand_macro_recursively);
}
}
pub fn expand_macro_recursively(
editor: &mut Editor,
_: &ExpandMacroRecursively,
cx: &mut ViewContext<'_, Editor>,
) {
if editor.selections.count() == 0 {
return;
}
let Some(project) = &editor.project else {
return;
};
let Some(workspace) = editor.workspace() else {
return;
};
let multibuffer = editor.buffer().read(cx);
let Some((trigger_anchor, rust_language, server_to_query, buffer)) = editor
.selections
.disjoint_anchors()
.into_iter()
.filter(|selection| selection.start == selection.end)
.filter_map(|selection| Some((selection.start.buffer_id?, selection.start)))
.filter_map(|(buffer_id, trigger_anchor)| {
let buffer = multibuffer.buffer(buffer_id)?;
let rust_language = buffer.read(cx).language_at(trigger_anchor.text_anchor)?;
if !is_rust_language(&rust_language) {
return None;
}
Some((trigger_anchor, rust_language, buffer))
})
.find_map(|(trigger_anchor, rust_language, buffer)| {
project
.read(cx)
.language_servers_for_buffer(buffer.read(cx), cx)
.into_iter()
.find_map(|(adapter, server)| {
if adapter.name.0.as_ref() == "rust-analyzer" {
Some((
trigger_anchor,
Arc::clone(&rust_language),
server.server_id(),
buffer.clone(),
))
} else {
None
}
})
})
else {
return;
};
let project = project.clone();
let buffer_snapshot = buffer.read(cx).snapshot();
let position = trigger_anchor.text_anchor.to_point_utf16(&buffer_snapshot);
let expand_macro_task = project.update(cx, |project, cx| {
project.request_lsp(
buffer,
project::LanguageServerToQuery::Other(server_to_query),
ExpandMacro { position },
cx,
)
});
cx.spawn(|editor, mut cx| async move {
let macro_expansion = expand_macro_task.await.context("expand macro")?;
if macro_expansion.is_empty() {
log::info!("Empty macro expansion for position {position:?}");
return Ok(());
}
let buffer = project.update(&mut cx, |project, cx| {
project.create_buffer(&macro_expansion.expansion, Some(rust_language), cx)
})??;
workspace.update(&mut cx, |workspace, cx| {
let buffer = cx.build_model(|cx| {
MultiBuffer::singleton(buffer, cx).with_title(macro_expansion.name)
});
workspace.add_item(
Box::new(cx.build_view(|cx| Editor::for_multibuffer(buffer, Some(project), cx))),
cx,
);
})
})
.detach_and_log_err(cx);
}
fn is_rust_language(language: &Language) -> bool {
language.name().as_ref() == "Rust"
}

View file

@ -136,6 +136,7 @@ pub struct ScrollManager {
last_autoscroll: Option<(gpui::Point<f32>, f32, f32, AutoscrollStrategy)>,
show_scrollbars: bool,
hide_scrollbar_task: Option<Task<()>>,
dragging_scrollbar: bool,
visible_line_count: Option<f32>,
}
@ -148,6 +149,7 @@ impl ScrollManager {
autoscroll_request: None,
show_scrollbars: true,
hide_scrollbar_task: None,
dragging_scrollbar: false,
last_autoscroll: None,
visible_line_count: None,
}
@ -278,6 +280,17 @@ impl ScrollManager {
self.autoscroll_request.is_some()
}
pub fn is_dragging_scrollbar(&self) -> bool {
self.dragging_scrollbar
}
pub fn set_is_dragging_scrollbar(&mut self, dragging: bool, cx: &mut ViewContext<Editor>) {
if dragging != self.dragging_scrollbar {
self.dragging_scrollbar = dragging;
cx.notify();
}
}
pub fn clamp_scroll_left(&mut self, max: f32) -> bool {
if max < self.anchor.offset.x {
self.anchor.offset.x = max;