Merge branch 'main' into picker
This commit is contained in:
commit
fe28d8faea
31 changed files with 5218 additions and 4767 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -9028,6 +9028,7 @@ dependencies = [
|
||||||
"fs2",
|
"fs2",
|
||||||
"gpui2",
|
"gpui2",
|
||||||
"indexmap 1.9.3",
|
"indexmap 1.9.3",
|
||||||
|
"itertools 0.11.0",
|
||||||
"parking_lot 0.11.2",
|
"parking_lot 0.11.2",
|
||||||
"refineable",
|
"refineable",
|
||||||
"schemars",
|
"schemars",
|
||||||
|
|
|
@ -80,7 +80,6 @@ pub fn init(client: &Arc<Client>, cx: &mut AppContext) {
|
||||||
init_settings(cx);
|
init_settings(cx);
|
||||||
|
|
||||||
let client = Arc::downgrade(client);
|
let client = Arc::downgrade(client);
|
||||||
cx.register_action_type::<SignIn>();
|
|
||||||
cx.on_action({
|
cx.on_action({
|
||||||
let client = client.clone();
|
let client = client.clone();
|
||||||
move |_: &SignIn, cx| {
|
move |_: &SignIn, cx| {
|
||||||
|
@ -93,7 +92,6 @@ pub fn init(client: &Arc<Client>, cx: &mut AppContext) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.register_action_type::<SignOut>();
|
|
||||||
cx.on_action({
|
cx.on_action({
|
||||||
let client = client.clone();
|
let client = client.clone();
|
||||||
move |_: &SignOut, cx| {
|
move |_: &SignOut, cx| {
|
||||||
|
@ -106,7 +104,6 @@ pub fn init(client: &Arc<Client>, cx: &mut AppContext) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.register_action_type::<Reconnect>();
|
|
||||||
cx.on_action({
|
cx.on_action({
|
||||||
let client = client.clone();
|
let client = client.clone();
|
||||||
move |_: &Reconnect, cx| {
|
move |_: &Reconnect, cx| {
|
||||||
|
|
|
@ -7,8 +7,8 @@ use async_tar::Archive;
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
use futures::{channel::oneshot, future::Shared, Future, FutureExt, TryFutureExt};
|
use futures::{channel::oneshot, future::Shared, Future, FutureExt, TryFutureExt};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AppContext, AsyncAppContext, Context, Entity, EntityId, EventEmitter, Model, ModelContext,
|
actions, AppContext, AsyncAppContext, Context, Entity, EntityId, EventEmitter, Model,
|
||||||
Task, WeakModel,
|
ModelContext, Task, WeakModel,
|
||||||
};
|
};
|
||||||
use language::{
|
use language::{
|
||||||
language_settings::{all_language_settings, language_settings},
|
language_settings::{all_language_settings, language_settings},
|
||||||
|
@ -34,19 +34,11 @@ use util::{
|
||||||
|
|
||||||
// todo!()
|
// todo!()
|
||||||
// const COPILOT_AUTH_NAMESPACE: &'static str = "copilot_auth";
|
// const COPILOT_AUTH_NAMESPACE: &'static str = "copilot_auth";
|
||||||
// actions!(copilot_auth, [SignIn, SignOut]);
|
actions!(SignIn, SignOut);
|
||||||
|
|
||||||
// todo!()
|
// todo!()
|
||||||
// const COPILOT_NAMESPACE: &'static str = "copilot";
|
// const COPILOT_NAMESPACE: &'static str = "copilot";
|
||||||
// actions!(
|
actions!(Suggest, NextSuggestion, PreviousSuggestion, Reinstall);
|
||||||
// copilot,
|
|
||||||
// [Suggest, NextSuggestion, PreviousSuggestion, Reinstall]
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
pub struct Suggest;
|
|
||||||
pub struct NextSuggestion;
|
|
||||||
pub struct PreviousSuggestion;
|
|
||||||
pub struct Reinstall;
|
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
new_server_id: LanguageServerId,
|
new_server_id: LanguageServerId,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,16 +2,25 @@ use crate::{
|
||||||
display_map::{BlockStyle, DisplaySnapshot, FoldStatus, HighlightedChunk, ToDisplayPoint},
|
display_map::{BlockStyle, DisplaySnapshot, FoldStatus, HighlightedChunk, ToDisplayPoint},
|
||||||
editor_settings::ShowScrollbar,
|
editor_settings::ShowScrollbar,
|
||||||
git::{diff_hunk_to_display, DisplayDiffHunk},
|
git::{diff_hunk_to_display, DisplayDiffHunk},
|
||||||
|
hover_popover::hover_at,
|
||||||
|
link_go_to_definition::{
|
||||||
|
go_to_fetched_definition, go_to_fetched_type_definition, update_go_to_definition_link,
|
||||||
|
update_inlay_link_and_hover_points, GoToDefinitionTrigger,
|
||||||
|
},
|
||||||
|
scroll::scroll_amount::ScrollAmount,
|
||||||
CursorShape, DisplayPoint, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle,
|
CursorShape, DisplayPoint, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle,
|
||||||
MoveDown, Point, Selection, SoftWrap, ToPoint, MAX_LINE_LEN,
|
HalfPageDown, HalfPageUp, LineDown, LineUp, MoveDown, PageDown, PageUp, Point, SelectPhase,
|
||||||
|
Selection, SoftWrap, ToPoint, MAX_LINE_LEN,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use collections::{BTreeMap, HashMap};
|
use collections::{BTreeMap, HashMap};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
black, hsla, point, px, relative, size, transparent_black, Action, AnyElement, BorrowWindow,
|
black, hsla, point, px, relative, size, transparent_black, Action, AnyElement,
|
||||||
Bounds, ContentMask, Corners, DispatchContext, DispatchPhase, Edges, Element, ElementId,
|
BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners, DispatchContext, DispatchPhase,
|
||||||
Entity, Hsla, KeyDownEvent, KeyListener, KeyMatch, Line, Pixels, ScrollWheelEvent, ShapedGlyph,
|
Edges, Element, ElementId, Entity, GlobalElementId, Hsla, KeyDownEvent, KeyListener, KeyMatch,
|
||||||
Size, StatefulInteractivity, Style, TextRun, TextStyle, TextSystem, ViewContext, WindowContext,
|
Line, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
|
||||||
|
ScrollWheelEvent, ShapedGlyph, Size, Style, TextRun, TextStyle, TextSystem, ViewContext,
|
||||||
|
WindowContext,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use language::language_settings::ShowWhitespaceSetting;
|
use language::language_settings::ShowWhitespaceSetting;
|
||||||
|
@ -30,6 +39,7 @@ use std::{
|
||||||
};
|
};
|
||||||
use sum_tree::Bias;
|
use sum_tree::Bias;
|
||||||
use theme::{ActiveTheme, PlayerColor};
|
use theme::{ActiveTheme, PlayerColor};
|
||||||
|
use util::ResultExt;
|
||||||
use workspace::item::Item;
|
use workspace::item::Item;
|
||||||
|
|
||||||
enum FoldMarkers {}
|
enum FoldMarkers {}
|
||||||
|
@ -103,194 +113,54 @@ impl EditorElement {
|
||||||
Self { style }
|
Self { style }
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn attach_mouse_handlers(
|
fn mouse_down(
|
||||||
// position_map: &Arc<PositionMap>,
|
editor: &mut Editor,
|
||||||
// has_popovers: bool,
|
event: &MouseDownEvent,
|
||||||
// visible_bounds: Bounds<Pixels>,
|
position_map: &PositionMap,
|
||||||
// text_bounds: Bounds<Pixels>,
|
text_bounds: Bounds<Pixels>,
|
||||||
// gutter_bounds: Bounds<Pixels>,
|
gutter_bounds: Bounds<Pixels>,
|
||||||
// bounds: Bounds<Pixels>,
|
cx: &mut ViewContext<Editor>,
|
||||||
// cx: &mut ViewContext<Editor>,
|
) -> bool {
|
||||||
// ) {
|
let mut click_count = event.click_count;
|
||||||
// enum EditorElementMouseHandlers {}
|
let modifiers = event.modifiers;
|
||||||
// let view_id = cx.view_id();
|
|
||||||
// cx.scene().push_mouse_region(
|
|
||||||
// MouseRegion::new::<EditorElementMouseHandlers>(view_id, view_id, visible_bounds)
|
|
||||||
// .on_down(MouseButton::Left, {
|
|
||||||
// let position_map = position_map.clone();
|
|
||||||
// move |event, editor, cx| {
|
|
||||||
// if !Self::mouse_down(
|
|
||||||
// editor,
|
|
||||||
// event.platform_event,
|
|
||||||
// position_map.as_ref(),
|
|
||||||
// text_bounds,
|
|
||||||
// gutter_bounds,
|
|
||||||
// cx,
|
|
||||||
// ) {
|
|
||||||
// cx.propagate_event();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .on_down(MouseButton::Right, {
|
|
||||||
// let position_map = position_map.clone();
|
|
||||||
// move |event, editor, cx| {
|
|
||||||
// if !Self::mouse_right_down(
|
|
||||||
// editor,
|
|
||||||
// event.position,
|
|
||||||
// position_map.as_ref(),
|
|
||||||
// text_bounds,
|
|
||||||
// cx,
|
|
||||||
// ) {
|
|
||||||
// cx.propagate_event();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .on_up(MouseButton::Left, {
|
|
||||||
// let position_map = position_map.clone();
|
|
||||||
// move |event, editor, cx| {
|
|
||||||
// if !Self::mouse_up(
|
|
||||||
// editor,
|
|
||||||
// event.position,
|
|
||||||
// event.cmd,
|
|
||||||
// event.shift,
|
|
||||||
// event.alt,
|
|
||||||
// position_map.as_ref(),
|
|
||||||
// text_bounds,
|
|
||||||
// cx,
|
|
||||||
// ) {
|
|
||||||
// cx.propagate_event()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .on_drag(MouseButton::Left, {
|
|
||||||
// let position_map = position_map.clone();
|
|
||||||
// move |event, editor, cx| {
|
|
||||||
// if event.end {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if !Self::mouse_dragged(
|
if gutter_bounds.contains_point(&event.position) {
|
||||||
// editor,
|
click_count = 3; // Simulate triple-click when clicking the gutter to select lines
|
||||||
// event.platform_event,
|
} else if !text_bounds.contains_point(&event.position) {
|
||||||
// position_map.as_ref(),
|
return false;
|
||||||
// text_bounds,
|
}
|
||||||
// cx,
|
|
||||||
// ) {
|
|
||||||
// cx.propagate_event()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .on_move({
|
|
||||||
// let position_map = position_map.clone();
|
|
||||||
// move |event, editor, cx| {
|
|
||||||
// if !Self::mouse_moved(
|
|
||||||
// editor,
|
|
||||||
// event.platform_event,
|
|
||||||
// &position_map,
|
|
||||||
// text_bounds,
|
|
||||||
// cx,
|
|
||||||
// ) {
|
|
||||||
// cx.propagate_event()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .on_move_out(move |_, editor: &mut Editor, cx| {
|
|
||||||
// if has_popovers {
|
|
||||||
// hide_hover(editor, cx);
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// .on_scroll({
|
|
||||||
// let position_map = position_map.clone();
|
|
||||||
// move |event, editor, cx| {
|
|
||||||
// if !Self::scroll(
|
|
||||||
// editor,
|
|
||||||
// event.position,
|
|
||||||
// *event.delta.raw(),
|
|
||||||
// event.delta.precise(),
|
|
||||||
// &position_map,
|
|
||||||
// bounds,
|
|
||||||
// cx,
|
|
||||||
// ) {
|
|
||||||
// cx.propagate_event()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// enum GutterHandlers {}
|
let point_for_position = position_map.point_for_position(text_bounds, event.position);
|
||||||
// let view_id = cx.view_id();
|
let position = point_for_position.previous_valid;
|
||||||
// let region_id = cx.view_id() + 1;
|
if modifiers.shift && modifiers.alt {
|
||||||
// cx.scene().push_mouse_region(
|
editor.select(
|
||||||
// MouseRegion::new::<GutterHandlers>(view_id, region_id, gutter_bounds).on_hover(
|
SelectPhase::BeginColumnar {
|
||||||
// |hover, editor: &mut Editor, cx| {
|
position,
|
||||||
// editor.gutter_hover(
|
goal_column: point_for_position.exact_unclipped.column(),
|
||||||
// &GutterHover {
|
},
|
||||||
// hovered: hover.started,
|
cx,
|
||||||
// },
|
);
|
||||||
// cx,
|
} else if modifiers.shift && !modifiers.control && !modifiers.alt && !modifiers.command {
|
||||||
// );
|
editor.select(
|
||||||
// },
|
SelectPhase::Extend {
|
||||||
// ),
|
position,
|
||||||
// )
|
click_count,
|
||||||
// }
|
},
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
editor.select(
|
||||||
|
SelectPhase::Begin {
|
||||||
|
position,
|
||||||
|
add: modifiers.alt,
|
||||||
|
click_count,
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// fn mouse_down(
|
true
|
||||||
// editor: &mut Editor,
|
}
|
||||||
// MouseButtonEvent {
|
|
||||||
// position,
|
|
||||||
// modifiers:
|
|
||||||
// Modifiers {
|
|
||||||
// shift,
|
|
||||||
// ctrl,
|
|
||||||
// alt,
|
|
||||||
// cmd,
|
|
||||||
// ..
|
|
||||||
// },
|
|
||||||
// mut click_count,
|
|
||||||
// ..
|
|
||||||
// }: MouseButtonEvent,
|
|
||||||
// position_map: &PositionMap,
|
|
||||||
// text_bounds: Bounds<Pixels>,
|
|
||||||
// gutter_bounds: Bounds<Pixels>,
|
|
||||||
// cx: &mut EventContext<Editor>,
|
|
||||||
// ) -> bool {
|
|
||||||
// if gutter_bounds.contains_point(position) {
|
|
||||||
// click_count = 3; // Simulate triple-click when clicking the gutter to select lines
|
|
||||||
// } else if !text_bounds.contains_point(position) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let point_for_position = position_map.point_for_position(text_bounds, position);
|
|
||||||
// let position = point_for_position.previous_valid;
|
|
||||||
// if shift && alt {
|
|
||||||
// editor.select(
|
|
||||||
// SelectPhase::BeginColumnar {
|
|
||||||
// position,
|
|
||||||
// goal_column: point_for_position.exact_unclipped.column(),
|
|
||||||
// },
|
|
||||||
// cx,
|
|
||||||
// );
|
|
||||||
// } else if shift && !ctrl && !alt && !cmd {
|
|
||||||
// editor.select(
|
|
||||||
// SelectPhase::Extend {
|
|
||||||
// position,
|
|
||||||
// click_count,
|
|
||||||
// },
|
|
||||||
// cx,
|
|
||||||
// );
|
|
||||||
// } else {
|
|
||||||
// editor.select(
|
|
||||||
// SelectPhase::Begin {
|
|
||||||
// position,
|
|
||||||
// add: alt,
|
|
||||||
// click_count,
|
|
||||||
// },
|
|
||||||
// cx,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// true
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn mouse_right_down(
|
// fn mouse_right_down(
|
||||||
// editor: &mut Editor,
|
// editor: &mut Editor,
|
||||||
|
@ -312,157 +182,120 @@ impl EditorElement {
|
||||||
// true
|
// true
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// fn mouse_up(
|
fn mouse_up(
|
||||||
// editor: &mut Editor,
|
editor: &mut Editor,
|
||||||
// position: gpui::Point<Pixels>,
|
event: &MouseUpEvent,
|
||||||
// cmd: bool,
|
position_map: &PositionMap,
|
||||||
// shift: bool,
|
text_bounds: Bounds<Pixels>,
|
||||||
// alt: bool,
|
cx: &mut ViewContext<Editor>,
|
||||||
// position_map: &PositionMap,
|
) -> bool {
|
||||||
// text_bounds: Bounds<Pixels>,
|
let end_selection = editor.has_pending_selection();
|
||||||
// cx: &mut EventContext<Editor>,
|
let pending_nonempty_selections = editor.has_pending_nonempty_selection();
|
||||||
// ) -> bool {
|
|
||||||
// let end_selection = editor.has_pending_selection();
|
|
||||||
// let pending_nonempty_selections = editor.has_pending_nonempty_selection();
|
|
||||||
|
|
||||||
// if end_selection {
|
if end_selection {
|
||||||
// editor.select(SelectPhase::End, cx);
|
editor.select(SelectPhase::End, cx);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if !pending_nonempty_selections && cmd && text_bounds.contains_point(position) {
|
if !pending_nonempty_selections
|
||||||
// let point = position_map.point_for_position(text_bounds, position);
|
&& event.modifiers.command
|
||||||
// let could_be_inlay = point.as_valid().is_none();
|
&& text_bounds.contains_point(&event.position)
|
||||||
// if shift || could_be_inlay {
|
{
|
||||||
// go_to_fetched_type_definition(editor, point, alt, cx);
|
let point = position_map.point_for_position(text_bounds, event.position);
|
||||||
// } else {
|
let could_be_inlay = point.as_valid().is_none();
|
||||||
// go_to_fetched_definition(editor, point, alt, cx);
|
let split = event.modifiers.alt;
|
||||||
// }
|
if event.modifiers.shift || could_be_inlay {
|
||||||
|
go_to_fetched_type_definition(editor, point, split, cx);
|
||||||
|
} else {
|
||||||
|
go_to_fetched_definition(editor, point, split, cx);
|
||||||
|
}
|
||||||
|
|
||||||
// return true;
|
return true;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// end_selection
|
end_selection
|
||||||
// }
|
}
|
||||||
|
|
||||||
// fn mouse_dragged(
|
fn mouse_moved(
|
||||||
// editor: &mut Editor,
|
editor: &mut Editor,
|
||||||
// MouseMovedEvent {
|
event: &MouseMoveEvent,
|
||||||
// modifiers: Modifiers { cmd, shift, .. },
|
position_map: &PositionMap,
|
||||||
// position,
|
text_bounds: Bounds<Pixels>,
|
||||||
// ..
|
gutter_bounds: Bounds<Pixels>,
|
||||||
// }: MouseMovedEvent,
|
cx: &mut ViewContext<Editor>,
|
||||||
// position_map: &PositionMap,
|
) -> bool {
|
||||||
// text_bounds: Bounds<Pixels>,
|
let modifiers = event.modifiers;
|
||||||
// cx: &mut EventContext<Editor>,
|
if editor.has_pending_selection() && event.pressed_button == Some(MouseButton::Left) {
|
||||||
// ) -> bool {
|
let point_for_position = position_map.point_for_position(text_bounds, event.position);
|
||||||
// // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
|
let mut scroll_delta = gpui::Point::<f32>::zero();
|
||||||
// // Don't trigger hover popover if mouse is hovering over context menu
|
let vertical_margin = position_map.line_height.min(text_bounds.size.height / 3.0);
|
||||||
// let point = if text_bounds.contains_point(position) {
|
let top = text_bounds.origin.y + vertical_margin;
|
||||||
// position_map
|
let bottom = text_bounds.lower_left().y - vertical_margin;
|
||||||
// .point_for_position(text_bounds, position)
|
if event.position.y < top {
|
||||||
// .as_valid()
|
scroll_delta.y = -scale_vertical_mouse_autoscroll_delta(top - event.position.y);
|
||||||
// } else {
|
}
|
||||||
// None
|
if event.position.y > bottom {
|
||||||
// };
|
scroll_delta.y = scale_vertical_mouse_autoscroll_delta(event.position.y - bottom);
|
||||||
|
}
|
||||||
|
|
||||||
// update_go_to_definition_link(
|
let horizontal_margin = position_map.line_height.min(text_bounds.size.width / 3.0);
|
||||||
// editor,
|
let left = text_bounds.origin.x + horizontal_margin;
|
||||||
// point.map(GoToDefinitionTrigger::Text),
|
let right = text_bounds.upper_right().x - horizontal_margin;
|
||||||
// cmd,
|
if event.position.x < left {
|
||||||
// shift,
|
scroll_delta.x = -scale_horizontal_mouse_autoscroll_delta(left - event.position.x);
|
||||||
// cx,
|
}
|
||||||
// );
|
if event.position.x > right {
|
||||||
|
scroll_delta.x = scale_horizontal_mouse_autoscroll_delta(event.position.x - right);
|
||||||
|
}
|
||||||
|
|
||||||
// if editor.has_pending_selection() {
|
editor.select(
|
||||||
// let mut scroll_delta = gpui::Point::<Pixels>::zero();
|
SelectPhase::Update {
|
||||||
|
position: point_for_position.previous_valid,
|
||||||
|
goal_column: point_for_position.exact_unclipped.column(),
|
||||||
|
scroll_position: (position_map.snapshot.scroll_position() + scroll_delta)
|
||||||
|
.clamp(&gpui::Point::zero(), &position_map.scroll_max),
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// let vertical_margin = position_map.line_height.min(text_bounds.height() / 3.0);
|
let text_hovered = text_bounds.contains_point(&event.position);
|
||||||
// let top = text_bounds.origin.y + vertical_margin;
|
let gutter_hovered = gutter_bounds.contains_point(&event.position);
|
||||||
// let bottom = text_bounds.lower_left().y - vertical_margin;
|
editor.set_gutter_hovered(gutter_hovered, cx);
|
||||||
// if position.y < top {
|
|
||||||
// scroll_delta.set_y(-scale_vertical_mouse_autoscroll_delta(top - position.y))
|
|
||||||
// }
|
|
||||||
// if position.y > bottom {
|
|
||||||
// scroll_delta.set_y(scale_vertical_mouse_autoscroll_delta(position.y - bottom))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let horizontal_margin = position_map.line_height.min(text_bounds.width() / 3.0);
|
// Don't trigger hover popover if mouse is hovering over context menu
|
||||||
// let left = text_bounds.origin.x + horizontal_margin;
|
if text_hovered {
|
||||||
// let right = text_bounds.upper_right().x - horizontal_margin;
|
let point_for_position = position_map.point_for_position(text_bounds, event.position);
|
||||||
// if position.x < left {
|
|
||||||
// scroll_delta.set_x(-scale_horizontal_mouse_autoscroll_delta(
|
|
||||||
// left - position.x,
|
|
||||||
// ))
|
|
||||||
// }
|
|
||||||
// if position.x > right {
|
|
||||||
// scroll_delta.set_x(scale_horizontal_mouse_autoscroll_delta(
|
|
||||||
// position.x - right,
|
|
||||||
// ))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let point_for_position = position_map.point_for_position(text_bounds, position);
|
match point_for_position.as_valid() {
|
||||||
|
Some(point) => {
|
||||||
|
update_go_to_definition_link(
|
||||||
|
editor,
|
||||||
|
Some(GoToDefinitionTrigger::Text(point)),
|
||||||
|
modifiers.command,
|
||||||
|
modifiers.shift,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
hover_at(editor, Some(point), cx);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
update_inlay_link_and_hover_points(
|
||||||
|
&position_map.snapshot,
|
||||||
|
point_for_position,
|
||||||
|
editor,
|
||||||
|
modifiers.command,
|
||||||
|
modifiers.shift,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// editor.select(
|
true
|
||||||
// SelectPhase::Update {
|
} else {
|
||||||
// position: point_for_position.previous_valid,
|
update_go_to_definition_link(editor, None, modifiers.command, modifiers.shift, cx);
|
||||||
// goal_column: point_for_position.exact_unclipped.column(),
|
hover_at(editor, None, cx);
|
||||||
// scroll_position: (position_map.snapshot.scroll_position() + scroll_delta)
|
gutter_hovered
|
||||||
// .clamp(gpui::Point::<Pixels>::zero(), position_map.scroll_max),
|
}
|
||||||
// },
|
}
|
||||||
// cx,
|
|
||||||
// );
|
|
||||||
// hover_at(editor, point, cx);
|
|
||||||
// true
|
|
||||||
// } else {
|
|
||||||
// hover_at(editor, point, cx);
|
|
||||||
// false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn mouse_moved(
|
|
||||||
// editor: &mut Editor,
|
|
||||||
// MouseMovedEvent {
|
|
||||||
// modifiers: Modifiers { shift, cmd, .. },
|
|
||||||
// position,
|
|
||||||
// ..
|
|
||||||
// }: MouseMovedEvent,
|
|
||||||
// position_map: &PositionMap,
|
|
||||||
// text_bounds: Bounds<Pixels>,
|
|
||||||
// cx: &mut ViewContext<Editor>,
|
|
||||||
// ) -> bool {
|
|
||||||
// // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
|
|
||||||
// // Don't trigger hover popover if mouse is hovering over context menu
|
|
||||||
// if text_bounds.contains_point(position) {
|
|
||||||
// let point_for_position = position_map.point_for_position(text_bounds, position);
|
|
||||||
// match point_for_position.as_valid() {
|
|
||||||
// Some(point) => {
|
|
||||||
// update_go_to_definition_link(
|
|
||||||
// editor,
|
|
||||||
// Some(GoToDefinitionTrigger::Text(point)),
|
|
||||||
// cmd,
|
|
||||||
// shift,
|
|
||||||
// cx,
|
|
||||||
// );
|
|
||||||
// hover_at(editor, Some(point), cx);
|
|
||||||
// }
|
|
||||||
// None => {
|
|
||||||
// update_inlay_link_and_hover_points(
|
|
||||||
// &position_map.snapshot,
|
|
||||||
// point_for_position,
|
|
||||||
// editor,
|
|
||||||
// cmd,
|
|
||||||
// shift,
|
|
||||||
// cx,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// update_go_to_definition_link(editor, None, cmd, shift, cx);
|
|
||||||
// hover_at(editor, None, cx);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// true
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn scroll(
|
fn scroll(
|
||||||
editor: &mut Editor,
|
editor: &mut Editor,
|
||||||
|
@ -2336,6 +2169,79 @@ impl EditorElement {
|
||||||
// blocks,
|
// blocks,
|
||||||
// )
|
// )
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
fn paint_mouse_listeners(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
gutter_bounds: Bounds<Pixels>,
|
||||||
|
text_bounds: Bounds<Pixels>,
|
||||||
|
position_map: &Arc<PositionMap>,
|
||||||
|
cx: &mut ViewContext<Editor>,
|
||||||
|
) {
|
||||||
|
cx.on_mouse_event({
|
||||||
|
let position_map = position_map.clone();
|
||||||
|
move |editor, event: &ScrollWheelEvent, phase, cx| {
|
||||||
|
if phase != DispatchPhase::Bubble {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if Self::scroll(editor, event, &position_map, bounds, cx) {
|
||||||
|
cx.stop_propagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cx.on_mouse_event({
|
||||||
|
let position_map = position_map.clone();
|
||||||
|
move |editor, event: &MouseDownEvent, phase, cx| {
|
||||||
|
if phase != DispatchPhase::Bubble {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if Self::mouse_down(editor, event, &position_map, text_bounds, gutter_bounds, cx) {
|
||||||
|
cx.stop_propagation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cx.on_mouse_event({
|
||||||
|
let position_map = position_map.clone();
|
||||||
|
move |editor, event: &MouseUpEvent, phase, cx| {
|
||||||
|
if phase != DispatchPhase::Bubble {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if Self::mouse_up(editor, event, &position_map, text_bounds, cx) {
|
||||||
|
cx.stop_propagation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// todo!()
|
||||||
|
// on_down(MouseButton::Right, {
|
||||||
|
// let position_map = position_map.clone();
|
||||||
|
// move |event, editor, cx| {
|
||||||
|
// if !Self::mouse_right_down(
|
||||||
|
// editor,
|
||||||
|
// event.position,
|
||||||
|
// position_map.as_ref(),
|
||||||
|
// text_bounds,
|
||||||
|
// cx,
|
||||||
|
// ) {
|
||||||
|
// cx.propagate_event();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
cx.on_mouse_event({
|
||||||
|
let position_map = position_map.clone();
|
||||||
|
move |editor, event: &MouseMoveEvent, phase, cx| {
|
||||||
|
if phase != DispatchPhase::Bubble {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if Self::mouse_moved(editor, event, &position_map, text_bounds, gutter_bounds, cx) {
|
||||||
|
cx.stop_propagation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -2555,30 +2461,9 @@ impl Element<Editor> for EditorElement {
|
||||||
let dispatch_context = editor.dispatch_context(cx);
|
let dispatch_context = editor.dispatch_context(cx);
|
||||||
cx.with_element_id(cx.view().entity_id(), |global_id, cx| {
|
cx.with_element_id(cx.view().entity_id(), |global_id, cx| {
|
||||||
cx.with_key_dispatch_context(dispatch_context, |cx| {
|
cx.with_key_dispatch_context(dispatch_context, |cx| {
|
||||||
cx.with_key_listeners(
|
cx.with_key_listeners(build_key_listeners(global_id), |cx| {
|
||||||
[
|
cx.with_focus(editor.focus_handle.clone(), |_| {})
|
||||||
build_action_listener(Editor::move_left),
|
});
|
||||||
build_action_listener(Editor::move_right),
|
|
||||||
build_action_listener(Editor::move_down),
|
|
||||||
build_action_listener(Editor::move_up),
|
|
||||||
build_key_listener(
|
|
||||||
move |editor, key_down: &KeyDownEvent, dispatch_context, phase, cx| {
|
|
||||||
if phase == DispatchPhase::Bubble {
|
|
||||||
if let KeyMatch::Some(action) = cx.match_keystroke(
|
|
||||||
&global_id,
|
|
||||||
&key_down.keystroke,
|
|
||||||
dispatch_context,
|
|
||||||
) {
|
|
||||||
return Some(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
|cx| cx.with_focus(editor.focus_handle.clone(), |_| {}),
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2608,25 +2493,6 @@ impl Element<Editor> for EditorElement {
|
||||||
cx: &mut gpui::ViewContext<Editor>,
|
cx: &mut gpui::ViewContext<Editor>,
|
||||||
) {
|
) {
|
||||||
let layout = self.compute_layout(editor, cx, bounds);
|
let layout = self.compute_layout(editor, cx, bounds);
|
||||||
|
|
||||||
cx.on_mouse_event({
|
|
||||||
let position_map = layout.position_map.clone();
|
|
||||||
move |editor, event: &ScrollWheelEvent, phase, cx| {
|
|
||||||
if phase != DispatchPhase::Bubble {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if Self::scroll(editor, event, &position_map, bounds, cx) {
|
|
||||||
cx.stop_propagation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if editor.focus_handle.is_focused(cx) {
|
|
||||||
cx.handle_text_input();
|
|
||||||
}
|
|
||||||
|
|
||||||
cx.with_content_mask(ContentMask { bounds }, |cx| {
|
|
||||||
let gutter_bounds = Bounds {
|
let gutter_bounds = Bounds {
|
||||||
origin: bounds.origin,
|
origin: bounds.origin,
|
||||||
size: layout.gutter_size,
|
size: layout.gutter_size,
|
||||||
|
@ -2636,6 +2502,18 @@ impl Element<Editor> for EditorElement {
|
||||||
size: layout.text_size,
|
size: layout.text_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if editor.focus_handle.is_focused(cx) {
|
||||||
|
cx.handle_text_input();
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.with_content_mask(ContentMask { bounds }, |cx| {
|
||||||
|
self.paint_mouse_listeners(
|
||||||
|
bounds,
|
||||||
|
gutter_bounds,
|
||||||
|
text_bounds,
|
||||||
|
&layout.position_map,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
self.paint_background(gutter_bounds, text_bounds, &layout, cx);
|
self.paint_background(gutter_bounds, text_bounds, &layout, cx);
|
||||||
if layout.gutter_size.width > Pixels::ZERO {
|
if layout.gutter_size.width > Pixels::ZERO {
|
||||||
self.paint_gutter(gutter_bounds, &layout, editor, cx);
|
self.paint_gutter(gutter_bounds, &layout, editor, cx);
|
||||||
|
@ -3664,12 +3542,12 @@ impl HighlightedRange {
|
||||||
// bounds.into_iter()
|
// bounds.into_iter()
|
||||||
// }
|
// }
|
||||||
|
|
||||||
pub fn scale_vertical_mouse_autoscroll_delta(delta: f32) -> f32 {
|
pub fn scale_vertical_mouse_autoscroll_delta(delta: Pixels) -> f32 {
|
||||||
delta.powf(1.5) / 100.0
|
(delta.pow(1.5) / 100.0).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scale_horizontal_mouse_autoscroll_delta(delta: f32) -> f32 {
|
fn scale_horizontal_mouse_autoscroll_delta(delta: Pixels) -> f32 {
|
||||||
delta.powf(1.2) / 300.0
|
(delta.pow(1.2) / 300.0).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cfg(test)]
|
// #[cfg(test)]
|
||||||
|
@ -4115,6 +3993,178 @@ fn scale_horizontal_mouse_autoscroll_delta(delta: f32) -> f32 {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
fn build_key_listeners(
|
||||||
|
global_element_id: GlobalElementId,
|
||||||
|
) -> impl IntoIterator<Item = (TypeId, KeyListener<Editor>)> {
|
||||||
|
[
|
||||||
|
build_action_listener(Editor::move_left),
|
||||||
|
build_action_listener(Editor::move_right),
|
||||||
|
build_action_listener(Editor::move_down),
|
||||||
|
build_action_listener(Editor::move_up),
|
||||||
|
// build_action_listener(Editor::new_file), todo!()
|
||||||
|
// build_action_listener(Editor::new_file_in_direction), todo!()
|
||||||
|
build_action_listener(Editor::cancel),
|
||||||
|
build_action_listener(Editor::newline),
|
||||||
|
build_action_listener(Editor::newline_above),
|
||||||
|
build_action_listener(Editor::newline_below),
|
||||||
|
build_action_listener(Editor::backspace),
|
||||||
|
build_action_listener(Editor::delete),
|
||||||
|
build_action_listener(Editor::tab),
|
||||||
|
build_action_listener(Editor::tab_prev),
|
||||||
|
build_action_listener(Editor::indent),
|
||||||
|
build_action_listener(Editor::outdent),
|
||||||
|
build_action_listener(Editor::delete_line),
|
||||||
|
build_action_listener(Editor::join_lines),
|
||||||
|
build_action_listener(Editor::sort_lines_case_sensitive),
|
||||||
|
build_action_listener(Editor::sort_lines_case_insensitive),
|
||||||
|
build_action_listener(Editor::reverse_lines),
|
||||||
|
build_action_listener(Editor::shuffle_lines),
|
||||||
|
build_action_listener(Editor::convert_to_upper_case),
|
||||||
|
build_action_listener(Editor::convert_to_lower_case),
|
||||||
|
build_action_listener(Editor::convert_to_title_case),
|
||||||
|
build_action_listener(Editor::convert_to_snake_case),
|
||||||
|
build_action_listener(Editor::convert_to_kebab_case),
|
||||||
|
build_action_listener(Editor::convert_to_upper_camel_case),
|
||||||
|
build_action_listener(Editor::convert_to_lower_camel_case),
|
||||||
|
build_action_listener(Editor::delete_to_previous_word_start),
|
||||||
|
build_action_listener(Editor::delete_to_previous_subword_start),
|
||||||
|
build_action_listener(Editor::delete_to_next_word_end),
|
||||||
|
build_action_listener(Editor::delete_to_next_subword_end),
|
||||||
|
build_action_listener(Editor::delete_to_beginning_of_line),
|
||||||
|
build_action_listener(Editor::delete_to_end_of_line),
|
||||||
|
build_action_listener(Editor::cut_to_end_of_line),
|
||||||
|
build_action_listener(Editor::duplicate_line),
|
||||||
|
build_action_listener(Editor::move_line_up),
|
||||||
|
build_action_listener(Editor::move_line_down),
|
||||||
|
build_action_listener(Editor::transpose),
|
||||||
|
build_action_listener(Editor::cut),
|
||||||
|
build_action_listener(Editor::copy),
|
||||||
|
build_action_listener(Editor::paste),
|
||||||
|
build_action_listener(Editor::undo),
|
||||||
|
build_action_listener(Editor::redo),
|
||||||
|
build_action_listener(Editor::move_page_up),
|
||||||
|
build_action_listener(Editor::move_page_down),
|
||||||
|
build_action_listener(Editor::next_screen),
|
||||||
|
build_action_listener(Editor::scroll_cursor_top),
|
||||||
|
build_action_listener(Editor::scroll_cursor_center),
|
||||||
|
build_action_listener(Editor::scroll_cursor_bottom),
|
||||||
|
build_action_listener(|editor, _: &LineDown, cx| {
|
||||||
|
editor.scroll_screen(&ScrollAmount::Line(1.), cx)
|
||||||
|
}),
|
||||||
|
build_action_listener(|editor, _: &LineUp, cx| {
|
||||||
|
editor.scroll_screen(&ScrollAmount::Line(-1.), cx)
|
||||||
|
}),
|
||||||
|
build_action_listener(|editor, _: &HalfPageDown, cx| {
|
||||||
|
editor.scroll_screen(&ScrollAmount::Page(0.5), cx)
|
||||||
|
}),
|
||||||
|
build_action_listener(|editor, _: &HalfPageUp, cx| {
|
||||||
|
editor.scroll_screen(&ScrollAmount::Page(-0.5), cx)
|
||||||
|
}),
|
||||||
|
build_action_listener(|editor, _: &PageDown, cx| {
|
||||||
|
editor.scroll_screen(&ScrollAmount::Page(1.), cx)
|
||||||
|
}),
|
||||||
|
build_action_listener(|editor, _: &PageUp, cx| {
|
||||||
|
editor.scroll_screen(&ScrollAmount::Page(-1.), cx)
|
||||||
|
}),
|
||||||
|
build_action_listener(Editor::move_to_previous_word_start),
|
||||||
|
build_action_listener(Editor::move_to_previous_subword_start),
|
||||||
|
build_action_listener(Editor::move_to_next_word_end),
|
||||||
|
build_action_listener(Editor::move_to_next_subword_end),
|
||||||
|
build_action_listener(Editor::move_to_beginning_of_line),
|
||||||
|
build_action_listener(Editor::move_to_end_of_line),
|
||||||
|
build_action_listener(Editor::move_to_start_of_paragraph),
|
||||||
|
build_action_listener(Editor::move_to_end_of_paragraph),
|
||||||
|
build_action_listener(Editor::move_to_beginning),
|
||||||
|
build_action_listener(Editor::move_to_end),
|
||||||
|
build_action_listener(Editor::select_up),
|
||||||
|
build_action_listener(Editor::select_down),
|
||||||
|
build_action_listener(Editor::select_left),
|
||||||
|
build_action_listener(Editor::select_right),
|
||||||
|
build_action_listener(Editor::select_to_previous_word_start),
|
||||||
|
build_action_listener(Editor::select_to_previous_subword_start),
|
||||||
|
build_action_listener(Editor::select_to_next_word_end),
|
||||||
|
build_action_listener(Editor::select_to_next_subword_end),
|
||||||
|
build_action_listener(Editor::select_to_beginning_of_line),
|
||||||
|
build_action_listener(Editor::select_to_end_of_line),
|
||||||
|
build_action_listener(Editor::select_to_start_of_paragraph),
|
||||||
|
build_action_listener(Editor::select_to_end_of_paragraph),
|
||||||
|
build_action_listener(Editor::select_to_beginning),
|
||||||
|
build_action_listener(Editor::select_to_end),
|
||||||
|
build_action_listener(Editor::select_all),
|
||||||
|
build_action_listener(|editor, action, cx| {
|
||||||
|
editor.select_all_matches(action, cx).log_err();
|
||||||
|
}),
|
||||||
|
build_action_listener(Editor::select_line),
|
||||||
|
build_action_listener(Editor::split_selection_into_lines),
|
||||||
|
build_action_listener(Editor::add_selection_above),
|
||||||
|
build_action_listener(Editor::add_selection_below),
|
||||||
|
build_action_listener(|editor, action, cx| {
|
||||||
|
editor.select_next(action, cx).log_err();
|
||||||
|
}),
|
||||||
|
build_action_listener(|editor, action, cx| {
|
||||||
|
editor.select_previous(action, cx).log_err();
|
||||||
|
}),
|
||||||
|
build_action_listener(Editor::toggle_comments),
|
||||||
|
build_action_listener(Editor::select_larger_syntax_node),
|
||||||
|
build_action_listener(Editor::select_smaller_syntax_node),
|
||||||
|
build_action_listener(Editor::move_to_enclosing_bracket),
|
||||||
|
build_action_listener(Editor::undo_selection),
|
||||||
|
build_action_listener(Editor::redo_selection),
|
||||||
|
build_action_listener(Editor::go_to_diagnostic),
|
||||||
|
build_action_listener(Editor::go_to_prev_diagnostic),
|
||||||
|
build_action_listener(Editor::go_to_hunk),
|
||||||
|
build_action_listener(Editor::go_to_prev_hunk),
|
||||||
|
build_action_listener(Editor::go_to_definition),
|
||||||
|
build_action_listener(Editor::go_to_definition_split),
|
||||||
|
build_action_listener(Editor::go_to_type_definition),
|
||||||
|
build_action_listener(Editor::go_to_type_definition_split),
|
||||||
|
build_action_listener(Editor::fold),
|
||||||
|
build_action_listener(Editor::fold_at),
|
||||||
|
build_action_listener(Editor::unfold_lines),
|
||||||
|
build_action_listener(Editor::unfold_at),
|
||||||
|
build_action_listener(Editor::fold_selected_ranges),
|
||||||
|
build_action_listener(Editor::show_completions),
|
||||||
|
// build_action_listener(Editor::toggle_code_actions), todo!()
|
||||||
|
// build_action_listener(Editor::open_excerpts), todo!()
|
||||||
|
build_action_listener(Editor::toggle_soft_wrap),
|
||||||
|
build_action_listener(Editor::toggle_inlay_hints),
|
||||||
|
build_action_listener(Editor::reveal_in_finder),
|
||||||
|
build_action_listener(Editor::copy_path),
|
||||||
|
build_action_listener(Editor::copy_relative_path),
|
||||||
|
build_action_listener(Editor::copy_highlight_json),
|
||||||
|
build_action_listener(|editor, action, cx| {
|
||||||
|
editor
|
||||||
|
.format(action, cx)
|
||||||
|
.map(|task| task.detach_and_log_err(cx));
|
||||||
|
}),
|
||||||
|
build_action_listener(Editor::restart_language_server),
|
||||||
|
build_action_listener(Editor::show_character_palette),
|
||||||
|
// build_action_listener(Editor::confirm_completion), todo!()
|
||||||
|
// build_action_listener(Editor::confirm_code_action), todo!()
|
||||||
|
// build_action_listener(Editor::rename), todo!()
|
||||||
|
// build_action_listener(Editor::confirm_rename), todo!()
|
||||||
|
// build_action_listener(Editor::find_all_references), todo!()
|
||||||
|
build_action_listener(Editor::next_copilot_suggestion),
|
||||||
|
build_action_listener(Editor::previous_copilot_suggestion),
|
||||||
|
build_action_listener(Editor::copilot_suggest),
|
||||||
|
build_key_listener(
|
||||||
|
move |editor, key_down: &KeyDownEvent, dispatch_context, phase, cx| {
|
||||||
|
if phase == DispatchPhase::Bubble {
|
||||||
|
if let KeyMatch::Some(action) = cx.match_keystroke(
|
||||||
|
&global_element_id,
|
||||||
|
&key_down.keystroke,
|
||||||
|
dispatch_context,
|
||||||
|
) {
|
||||||
|
return Some(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
fn build_key_listener<T: 'static>(
|
fn build_key_listener<T: 'static>(
|
||||||
listener: impl Fn(
|
listener: impl Fn(
|
||||||
&mut Editor,
|
&mut Editor,
|
||||||
|
|
|
@ -144,8 +144,7 @@ pub fn hide_hover(editor: &mut Editor, cx: &mut ViewContext<Editor>) -> bool {
|
||||||
editor.hover_state.info_task = None;
|
editor.hover_state.info_task = None;
|
||||||
editor.hover_state.triggered_from = None;
|
editor.hover_state.triggered_from = None;
|
||||||
|
|
||||||
// todo!()
|
editor.clear_background_highlights::<HoverState>(cx);
|
||||||
// editor.clear_background_highlights::<HoverState>(cx);
|
|
||||||
|
|
||||||
if did_hide {
|
if did_hide {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
@ -325,23 +324,22 @@ fn show_hover(
|
||||||
};
|
};
|
||||||
|
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
todo!();
|
if let Some(symbol_range) = hover_popover
|
||||||
// if let Some(symbol_range) = hover_popover
|
.as_ref()
|
||||||
// .as_ref()
|
.and_then(|hover_popover| hover_popover.symbol_range.as_text_range())
|
||||||
// .and_then(|hover_popover| hover_popover.symbol_range.as_text_range())
|
{
|
||||||
// {
|
// Highlight the selected symbol using a background highlight
|
||||||
// // Highlight the selected symbol using a background highlight
|
this.highlight_background::<HoverState>(
|
||||||
// this.highlight_background::<HoverState>(
|
vec![symbol_range],
|
||||||
// vec![symbol_range],
|
|theme| theme.element_hover, // todo! update theme
|
||||||
// |theme| theme.editor.hover_popover.highlight,
|
cx,
|
||||||
// cx,
|
);
|
||||||
// );
|
} else {
|
||||||
// } else {
|
this.clear_background_highlights::<HoverState>(cx);
|
||||||
// this.clear_background_highlights::<HoverState>(cx);
|
}
|
||||||
// }
|
|
||||||
//
|
this.hover_state.info_popover = hover_popover;
|
||||||
// this.hover_state.info_popover = hover_popover;
|
cx.notify();
|
||||||
// cx.notify();
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok::<_, anyhow::Error>(())
|
Ok::<_, anyhow::Error>(())
|
||||||
|
|
|
@ -171,173 +171,170 @@ pub fn update_inlay_link_and_hover_points(
|
||||||
shift_held: bool,
|
shift_held: bool,
|
||||||
cx: &mut ViewContext<'_, Editor>,
|
cx: &mut ViewContext<'_, Editor>,
|
||||||
) {
|
) {
|
||||||
todo!("old implementation below")
|
let hovered_offset = if point_for_position.column_overshoot_after_line_end == 0 {
|
||||||
}
|
Some(snapshot.display_point_to_inlay_offset(point_for_position.exact_unclipped, Bias::Left))
|
||||||
// ) {
|
} else {
|
||||||
// let hovered_offset = if point_for_position.column_overshoot_after_line_end == 0 {
|
None
|
||||||
// Some(snapshot.display_point_to_inlay_offset(point_for_position.exact_unclipped, Bias::Left))
|
};
|
||||||
// } else {
|
let mut go_to_definition_updated = false;
|
||||||
// None
|
let mut hover_updated = false;
|
||||||
// };
|
if let Some(hovered_offset) = hovered_offset {
|
||||||
// let mut go_to_definition_updated = false;
|
let buffer_snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||||
// let mut hover_updated = false;
|
let previous_valid_anchor = buffer_snapshot.anchor_at(
|
||||||
// if let Some(hovered_offset) = hovered_offset {
|
point_for_position.previous_valid.to_point(snapshot),
|
||||||
// let buffer_snapshot = editor.buffer().read(cx).snapshot(cx);
|
Bias::Left,
|
||||||
// let previous_valid_anchor = buffer_snapshot.anchor_at(
|
);
|
||||||
// point_for_position.previous_valid.to_point(snapshot),
|
let next_valid_anchor = buffer_snapshot.anchor_at(
|
||||||
// Bias::Left,
|
point_for_position.next_valid.to_point(snapshot),
|
||||||
// );
|
Bias::Right,
|
||||||
// let next_valid_anchor = buffer_snapshot.anchor_at(
|
);
|
||||||
// point_for_position.next_valid.to_point(snapshot),
|
if let Some(hovered_hint) = editor
|
||||||
// Bias::Right,
|
.visible_inlay_hints(cx)
|
||||||
// );
|
.into_iter()
|
||||||
// if let Some(hovered_hint) = editor
|
.skip_while(|hint| {
|
||||||
// .visible_inlay_hints(cx)
|
hint.position
|
||||||
// .into_iter()
|
.cmp(&previous_valid_anchor, &buffer_snapshot)
|
||||||
// .skip_while(|hint| {
|
.is_lt()
|
||||||
// hint.position
|
})
|
||||||
// .cmp(&previous_valid_anchor, &buffer_snapshot)
|
.take_while(|hint| {
|
||||||
// .is_lt()
|
hint.position
|
||||||
// })
|
.cmp(&next_valid_anchor, &buffer_snapshot)
|
||||||
// .take_while(|hint| {
|
.is_le()
|
||||||
// hint.position
|
})
|
||||||
// .cmp(&next_valid_anchor, &buffer_snapshot)
|
.max_by_key(|hint| hint.id)
|
||||||
// .is_le()
|
{
|
||||||
// })
|
let inlay_hint_cache = editor.inlay_hint_cache();
|
||||||
// .max_by_key(|hint| hint.id)
|
let excerpt_id = previous_valid_anchor.excerpt_id;
|
||||||
// {
|
if let Some(cached_hint) = inlay_hint_cache.hint_by_id(excerpt_id, hovered_hint.id) {
|
||||||
// let inlay_hint_cache = editor.inlay_hint_cache();
|
match cached_hint.resolve_state {
|
||||||
// let excerpt_id = previous_valid_anchor.excerpt_id;
|
ResolveState::CanResolve(_, _) => {
|
||||||
// if let Some(cached_hint) = inlay_hint_cache.hint_by_id(excerpt_id, hovered_hint.id) {
|
if let Some(buffer_id) = previous_valid_anchor.buffer_id {
|
||||||
// match cached_hint.resolve_state {
|
inlay_hint_cache.spawn_hint_resolve(
|
||||||
// ResolveState::CanResolve(_, _) => {
|
buffer_id,
|
||||||
// if let Some(buffer_id) = previous_valid_anchor.buffer_id {
|
excerpt_id,
|
||||||
// inlay_hint_cache.spawn_hint_resolve(
|
hovered_hint.id,
|
||||||
// buffer_id,
|
cx,
|
||||||
// excerpt_id,
|
);
|
||||||
// hovered_hint.id,
|
}
|
||||||
// cx,
|
}
|
||||||
// );
|
ResolveState::Resolved => {
|
||||||
// }
|
let mut extra_shift_left = 0;
|
||||||
// }
|
let mut extra_shift_right = 0;
|
||||||
// ResolveState::Resolved => {
|
if cached_hint.padding_left {
|
||||||
// let mut extra_shift_left = 0;
|
extra_shift_left += 1;
|
||||||
// let mut extra_shift_right = 0;
|
extra_shift_right += 1;
|
||||||
// if cached_hint.padding_left {
|
}
|
||||||
// extra_shift_left += 1;
|
if cached_hint.padding_right {
|
||||||
// extra_shift_right += 1;
|
extra_shift_right += 1;
|
||||||
// }
|
}
|
||||||
// if cached_hint.padding_right {
|
match cached_hint.label {
|
||||||
// extra_shift_right += 1;
|
project::InlayHintLabel::String(_) => {
|
||||||
// }
|
if let Some(tooltip) = cached_hint.tooltip {
|
||||||
// match cached_hint.label {
|
hover_popover::hover_at_inlay(
|
||||||
// project::InlayHintLabel::String(_) => {
|
editor,
|
||||||
// if let Some(tooltip) = cached_hint.tooltip {
|
InlayHover {
|
||||||
// hover_popover::hover_at_inlay(
|
excerpt: excerpt_id,
|
||||||
// editor,
|
tooltip: match tooltip {
|
||||||
// InlayHover {
|
InlayHintTooltip::String(text) => HoverBlock {
|
||||||
// excerpt: excerpt_id,
|
text,
|
||||||
// tooltip: match tooltip {
|
kind: HoverBlockKind::PlainText,
|
||||||
// InlayHintTooltip::String(text) => HoverBlock {
|
},
|
||||||
// text,
|
InlayHintTooltip::MarkupContent(content) => {
|
||||||
// kind: HoverBlockKind::PlainText,
|
HoverBlock {
|
||||||
// },
|
text: content.value,
|
||||||
// InlayHintTooltip::MarkupContent(content) => {
|
kind: content.kind,
|
||||||
// HoverBlock {
|
}
|
||||||
// text: content.value,
|
}
|
||||||
// kind: content.kind,
|
},
|
||||||
// }
|
range: InlayHighlight {
|
||||||
// }
|
inlay: hovered_hint.id,
|
||||||
// },
|
inlay_position: hovered_hint.position,
|
||||||
// range: InlayHighlight {
|
range: extra_shift_left
|
||||||
// inlay: hovered_hint.id,
|
..hovered_hint.text.len() + extra_shift_right,
|
||||||
// inlay_position: hovered_hint.position,
|
},
|
||||||
// range: extra_shift_left
|
},
|
||||||
// ..hovered_hint.text.len() + extra_shift_right,
|
cx,
|
||||||
// },
|
);
|
||||||
// },
|
hover_updated = true;
|
||||||
// cx,
|
}
|
||||||
// );
|
}
|
||||||
// hover_updated = true;
|
project::InlayHintLabel::LabelParts(label_parts) => {
|
||||||
// }
|
let hint_start =
|
||||||
// }
|
snapshot.anchor_to_inlay_offset(hovered_hint.position);
|
||||||
// project::InlayHintLabel::LabelParts(label_parts) => {
|
if let Some((hovered_hint_part, part_range)) =
|
||||||
// let hint_start =
|
hover_popover::find_hovered_hint_part(
|
||||||
// snapshot.anchor_to_inlay_offset(hovered_hint.position);
|
label_parts,
|
||||||
// if let Some((hovered_hint_part, part_range)) =
|
hint_start,
|
||||||
// hover_popover::find_hovered_hint_part(
|
hovered_offset,
|
||||||
// label_parts,
|
)
|
||||||
// hint_start,
|
{
|
||||||
// hovered_offset,
|
let highlight_start =
|
||||||
// )
|
(part_range.start - hint_start).0 + extra_shift_left;
|
||||||
// {
|
let highlight_end =
|
||||||
// let highlight_start =
|
(part_range.end - hint_start).0 + extra_shift_right;
|
||||||
// (part_range.start - hint_start).0 + extra_shift_left;
|
let highlight = InlayHighlight {
|
||||||
// let highlight_end =
|
inlay: hovered_hint.id,
|
||||||
// (part_range.end - hint_start).0 + extra_shift_right;
|
inlay_position: hovered_hint.position,
|
||||||
// let highlight = InlayHighlight {
|
range: highlight_start..highlight_end,
|
||||||
// inlay: hovered_hint.id,
|
};
|
||||||
// inlay_position: hovered_hint.position,
|
if let Some(tooltip) = hovered_hint_part.tooltip {
|
||||||
// range: highlight_start..highlight_end,
|
hover_popover::hover_at_inlay(
|
||||||
// };
|
editor,
|
||||||
// if let Some(tooltip) = hovered_hint_part.tooltip {
|
InlayHover {
|
||||||
// hover_popover::hover_at_inlay(
|
excerpt: excerpt_id,
|
||||||
// editor,
|
tooltip: match tooltip {
|
||||||
// InlayHover {
|
InlayHintLabelPartTooltip::String(text) => {
|
||||||
// excerpt: excerpt_id,
|
HoverBlock {
|
||||||
// tooltip: match tooltip {
|
text,
|
||||||
// InlayHintLabelPartTooltip::String(text) => {
|
kind: HoverBlockKind::PlainText,
|
||||||
// HoverBlock {
|
}
|
||||||
// text,
|
}
|
||||||
// kind: HoverBlockKind::PlainText,
|
InlayHintLabelPartTooltip::MarkupContent(
|
||||||
// }
|
content,
|
||||||
// }
|
) => HoverBlock {
|
||||||
// InlayHintLabelPartTooltip::MarkupContent(
|
text: content.value,
|
||||||
// content,
|
kind: content.kind,
|
||||||
// ) => HoverBlock {
|
},
|
||||||
// text: content.value,
|
},
|
||||||
// kind: content.kind,
|
range: highlight.clone(),
|
||||||
// },
|
},
|
||||||
// },
|
cx,
|
||||||
// range: highlight.clone(),
|
);
|
||||||
// },
|
hover_updated = true;
|
||||||
// cx,
|
}
|
||||||
// );
|
if let Some((language_server_id, location)) =
|
||||||
// hover_updated = true;
|
hovered_hint_part.location
|
||||||
// }
|
{
|
||||||
// if let Some((language_server_id, location)) =
|
go_to_definition_updated = true;
|
||||||
// hovered_hint_part.location
|
update_go_to_definition_link(
|
||||||
// {
|
editor,
|
||||||
// go_to_definition_updated = true;
|
Some(GoToDefinitionTrigger::InlayHint(
|
||||||
// update_go_to_definition_link(
|
highlight,
|
||||||
// editor,
|
location,
|
||||||
// Some(GoToDefinitionTrigger::InlayHint(
|
language_server_id,
|
||||||
// highlight,
|
)),
|
||||||
// location,
|
cmd_held,
|
||||||
// language_server_id,
|
shift_held,
|
||||||
// )),
|
cx,
|
||||||
// cmd_held,
|
);
|
||||||
// shift_held,
|
}
|
||||||
// cx,
|
}
|
||||||
// );
|
}
|
||||||
// }
|
};
|
||||||
// }
|
}
|
||||||
// }
|
ResolveState::Resolving => {}
|
||||||
// };
|
}
|
||||||
// }
|
}
|
||||||
// ResolveState::Resolving => {}
|
}
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if !go_to_definition_updated {
|
if !go_to_definition_updated {
|
||||||
// update_go_to_definition_link(editor, None, cmd_held, shift_held, cx);
|
update_go_to_definition_link(editor, None, cmd_held, shift_held, cx);
|
||||||
// }
|
}
|
||||||
// if !hover_updated {
|
if !hover_updated {
|
||||||
// hover_popover::hover_at(editor, None, cx);
|
hover_popover::hover_at(editor, None, cx);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum LinkDefinitionKind {
|
pub enum LinkDefinitionKind {
|
||||||
|
|
|
@ -288,16 +288,15 @@ impl ScrollManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo!()
|
|
||||||
impl Editor {
|
impl Editor {
|
||||||
// pub fn vertical_scroll_margin(&mut self) -> usize {
|
pub fn vertical_scroll_margin(&mut self) -> usize {
|
||||||
// self.scroll_manager.vertical_scroll_margin as usize
|
self.scroll_manager.vertical_scroll_margin as usize
|
||||||
// }
|
}
|
||||||
|
|
||||||
// pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut ViewContext<Self>) {
|
pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut ViewContext<Self>) {
|
||||||
// self.scroll_manager.vertical_scroll_margin = margin_rows as f32;
|
self.scroll_manager.vertical_scroll_margin = margin_rows as f32;
|
||||||
// cx.notify();
|
cx.notify();
|
||||||
// }
|
}
|
||||||
|
|
||||||
pub fn visible_line_count(&self) -> Option<f32> {
|
pub fn visible_line_count(&self) -> Option<f32> {
|
||||||
self.scroll_manager.visible_line_count
|
self.scroll_manager.visible_line_count
|
||||||
|
@ -349,11 +348,9 @@ impl Editor {
|
||||||
self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
|
self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> gpui::Point<Pixels> {
|
pub fn scroll_position(&self, cx: &mut ViewContext<Self>) -> gpui::Point<f32> {
|
||||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
// todo!() Should `self.scroll_manager.anchor.scroll_position()` return `Pixels`?
|
self.scroll_manager.anchor.scroll_position(&display_map)
|
||||||
// self.scroll_manager.anchor.scroll_position(&display_map)
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_scroll_anchor(&mut self, scroll_anchor: ScrollAnchor, cx: &mut ViewContext<Self>) {
|
pub fn set_scroll_anchor(&mut self, scroll_anchor: ScrollAnchor, cx: &mut ViewContext<Self>) {
|
||||||
|
@ -382,50 +379,50 @@ impl Editor {
|
||||||
.set_anchor(scroll_anchor, top_row, false, false, workspace_id, cx);
|
.set_anchor(scroll_anchor, top_row, false, false, workspace_id, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn scroll_screen(&mut self, amount: &ScrollAmount, cx: &mut ViewContext<Self>) {
|
pub fn scroll_screen(&mut self, amount: &ScrollAmount, cx: &mut ViewContext<Self>) {
|
||||||
// if matches!(self.mode, EditorMode::SingleLine) {
|
if matches!(self.mode, EditorMode::SingleLine) {
|
||||||
// cx.propagate_action();
|
cx.propagate();
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if self.take_rename(true, cx).is_some() {
|
if self.take_rename(true, cx).is_some() {
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// let cur_position = self.scroll_position(cx);
|
let cur_position = self.scroll_position(cx);
|
||||||
// let new_pos = cur_position + point(0., amount.lines(self));
|
let new_pos = cur_position + point(0., amount.lines(self));
|
||||||
// self.set_scroll_position(new_pos, cx);
|
self.set_scroll_position(new_pos, cx);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// /// Returns an ordering. The newest selection is:
|
/// Returns an ordering. The newest selection is:
|
||||||
// /// Ordering::Equal => on screen
|
/// Ordering::Equal => on screen
|
||||||
// /// Ordering::Less => above the screen
|
/// Ordering::Less => above the screen
|
||||||
// /// Ordering::Greater => below the screen
|
/// Ordering::Greater => below the screen
|
||||||
// pub fn newest_selection_on_screen(&self, cx: &mut AppContext) -> Ordering {
|
pub fn newest_selection_on_screen(&self, cx: &mut AppContext) -> Ordering {
|
||||||
// let snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
let snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
// let newest_head = self
|
let newest_head = self
|
||||||
// .selections
|
.selections
|
||||||
// .newest_anchor()
|
.newest_anchor()
|
||||||
// .head()
|
.head()
|
||||||
// .to_display_point(&snapshot);
|
.to_display_point(&snapshot);
|
||||||
// let screen_top = self
|
let screen_top = self
|
||||||
// .scroll_manager
|
.scroll_manager
|
||||||
// .anchor
|
.anchor
|
||||||
// .anchor
|
.anchor
|
||||||
// .to_display_point(&snapshot);
|
.to_display_point(&snapshot);
|
||||||
|
|
||||||
// if screen_top > newest_head {
|
if screen_top > newest_head {
|
||||||
// return Ordering::Less;
|
return Ordering::Less;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if let Some(visible_lines) = self.visible_line_count() {
|
if let Some(visible_lines) = self.visible_line_count() {
|
||||||
// if newest_head.row() < screen_top.row() + visible_lines as u32 {
|
if newest_head.row() < screen_top.row() + visible_lines as u32 {
|
||||||
// return Ordering::Equal;
|
return Ordering::Equal;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Ordering::Greater
|
Ordering::Greater
|
||||||
// }
|
}
|
||||||
|
|
||||||
pub fn read_scroll_position_from_db(
|
pub fn read_scroll_position_from_db(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
@ -1,66 +1,27 @@
|
||||||
use super::Axis;
|
use super::Axis;
|
||||||
use crate::Editor;
|
use crate::{
|
||||||
use gpui::{AppContext, Point, ViewContext};
|
Autoscroll, Bias, Editor, EditorMode, NextScreen, ScrollAnchor, ScrollCursorBottom,
|
||||||
|
ScrollCursorCenter, ScrollCursorTop,
|
||||||
// actions!(
|
};
|
||||||
// editor,
|
use gpui::{actions, AppContext, Point, ViewContext};
|
||||||
// [
|
|
||||||
// LineDown,
|
|
||||||
// LineUp,
|
|
||||||
// HalfPageDown,
|
|
||||||
// HalfPageUp,
|
|
||||||
// PageDown,
|
|
||||||
// PageUp,
|
|
||||||
// NextScreen,
|
|
||||||
// ScrollCursorTop,
|
|
||||||
// ScrollCursorCenter,
|
|
||||||
// ScrollCursorBottom,
|
|
||||||
// ]
|
|
||||||
// );
|
|
||||||
|
|
||||||
pub fn init(cx: &mut AppContext) {
|
|
||||||
// todo!()
|
|
||||||
// cx.add_action(Editor::next_screen);
|
|
||||||
// cx.add_action(Editor::scroll_cursor_top);
|
|
||||||
// cx.add_action(Editor::scroll_cursor_center);
|
|
||||||
// cx.add_action(Editor::scroll_cursor_bottom);
|
|
||||||
// cx.add_action(|this: &mut Editor, _: &LineDown, cx| {
|
|
||||||
// this.scroll_screen(&ScrollAmount::Line(1.), cx)
|
|
||||||
// });
|
|
||||||
// cx.add_action(|this: &mut Editor, _: &LineUp, cx| {
|
|
||||||
// this.scroll_screen(&ScrollAmount::Line(-1.), cx)
|
|
||||||
// });
|
|
||||||
// cx.add_action(|this: &mut Editor, _: &HalfPageDown, cx| {
|
|
||||||
// this.scroll_screen(&ScrollAmount::Page(0.5), cx)
|
|
||||||
// });
|
|
||||||
// cx.add_action(|this: &mut Editor, _: &HalfPageUp, cx| {
|
|
||||||
// this.scroll_screen(&ScrollAmount::Page(-0.5), cx)
|
|
||||||
// });
|
|
||||||
// cx.add_action(|this: &mut Editor, _: &PageDown, cx| {
|
|
||||||
// this.scroll_screen(&ScrollAmount::Page(1.), cx)
|
|
||||||
// });
|
|
||||||
// cx.add_action(|this: &mut Editor, _: &PageUp, cx| {
|
|
||||||
// this.scroll_screen(&ScrollAmount::Page(-1.), cx)
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Editor {
|
impl Editor {
|
||||||
// pub fn next_screen(&mut self, _: &NextScreen, cx: &mut ViewContext<Editor>) -> Option<()> {
|
pub fn next_screen(&mut self, _: &NextScreen, cx: &mut ViewContext<Editor>) {
|
||||||
// if self.take_rename(true, cx).is_some() {
|
if self.take_rename(true, cx).is_some() {
|
||||||
// return None;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
// todo!()
|
||||||
// if self.mouse_context_menu.read(cx).visible() {
|
// if self.mouse_context_menu.read(cx).visible() {
|
||||||
// return None;
|
// return None;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// if matches!(self.mode, EditorMode::SingleLine) {
|
if matches!(self.mode, EditorMode::SingleLine) {
|
||||||
// cx.propagate_action();
|
cx.propagate();
|
||||||
// return None;
|
return;
|
||||||
// }
|
}
|
||||||
// self.request_autoscroll(Autoscroll::Next, cx);
|
self.request_autoscroll(Autoscroll::Next, cx);
|
||||||
// Some(())
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn scroll(
|
pub fn scroll(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -72,79 +33,71 @@ impl Editor {
|
||||||
self.set_scroll_position(scroll_position, cx);
|
self.set_scroll_position(scroll_position, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn scroll_cursor_top(editor: &mut Editor, _: &ScrollCursorTop, cx: &mut ViewContext<Editor>) {
|
pub fn scroll_cursor_top(&mut self, _: &ScrollCursorTop, cx: &mut ViewContext<Editor>) {
|
||||||
// let snapshot = editor.snapshot(cx).display_snapshot;
|
let snapshot = self.snapshot(cx).display_snapshot;
|
||||||
// let scroll_margin_rows = editor.vertical_scroll_margin() as u32;
|
let scroll_margin_rows = self.vertical_scroll_margin() as u32;
|
||||||
|
|
||||||
// let mut new_screen_top = editor.selections.newest_display(cx).head();
|
let mut new_screen_top = self.selections.newest_display(cx).head();
|
||||||
// *new_screen_top.row_mut() = new_screen_top.row().saturating_sub(scroll_margin_rows);
|
*new_screen_top.row_mut() = new_screen_top.row().saturating_sub(scroll_margin_rows);
|
||||||
// *new_screen_top.column_mut() = 0;
|
*new_screen_top.column_mut() = 0;
|
||||||
// let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
||||||
// let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
||||||
|
|
||||||
// editor.set_scroll_anchor(
|
self.set_scroll_anchor(
|
||||||
// ScrollAnchor {
|
ScrollAnchor {
|
||||||
// anchor: new_anchor,
|
anchor: new_anchor,
|
||||||
// offset: Default::default(),
|
offset: Default::default(),
|
||||||
// },
|
},
|
||||||
// cx,
|
cx,
|
||||||
// )
|
)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// fn scroll_cursor_center(
|
pub fn scroll_cursor_center(&mut self, _: &ScrollCursorCenter, cx: &mut ViewContext<Editor>) {
|
||||||
// editor: &mut Editor,
|
let snapshot = self.snapshot(cx).display_snapshot;
|
||||||
// _: &ScrollCursorCenter,
|
let visible_rows = if let Some(visible_rows) = self.visible_line_count() {
|
||||||
// cx: &mut ViewContext<Editor>,
|
visible_rows as u32
|
||||||
// ) {
|
} else {
|
||||||
// let snapshot = editor.snapshot(cx).display_snapshot;
|
return;
|
||||||
// let visible_rows = if let Some(visible_rows) = editor.visible_line_count() {
|
};
|
||||||
// visible_rows as u32
|
|
||||||
// } else {
|
|
||||||
// return;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let mut new_screen_top = editor.selections.newest_display(cx).head();
|
let mut new_screen_top = self.selections.newest_display(cx).head();
|
||||||
// *new_screen_top.row_mut() = new_screen_top.row().saturating_sub(visible_rows / 2);
|
*new_screen_top.row_mut() = new_screen_top.row().saturating_sub(visible_rows / 2);
|
||||||
// *new_screen_top.column_mut() = 0;
|
*new_screen_top.column_mut() = 0;
|
||||||
// let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
||||||
// let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
||||||
|
|
||||||
// editor.set_scroll_anchor(
|
self.set_scroll_anchor(
|
||||||
// ScrollAnchor {
|
ScrollAnchor {
|
||||||
// anchor: new_anchor,
|
anchor: new_anchor,
|
||||||
// offset: Default::default(),
|
offset: Default::default(),
|
||||||
// },
|
},
|
||||||
// cx,
|
cx,
|
||||||
// )
|
)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// fn scroll_cursor_bottom(
|
pub fn scroll_cursor_bottom(&mut self, _: &ScrollCursorBottom, cx: &mut ViewContext<Editor>) {
|
||||||
// editor: &mut Editor,
|
let snapshot = self.snapshot(cx).display_snapshot;
|
||||||
// _: &ScrollCursorBottom,
|
let scroll_margin_rows = self.vertical_scroll_margin() as u32;
|
||||||
// cx: &mut ViewContext<Editor>,
|
let visible_rows = if let Some(visible_rows) = self.visible_line_count() {
|
||||||
// ) {
|
visible_rows as u32
|
||||||
// let snapshot = editor.snapshot(cx).display_snapshot;
|
} else {
|
||||||
// let scroll_margin_rows = editor.vertical_scroll_margin() as u32;
|
return;
|
||||||
// let visible_rows = if let Some(visible_rows) = editor.visible_line_count() {
|
};
|
||||||
// visible_rows as u32
|
|
||||||
// } else {
|
|
||||||
// return;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let mut new_screen_top = editor.selections.newest_display(cx).head();
|
let mut new_screen_top = self.selections.newest_display(cx).head();
|
||||||
// *new_screen_top.row_mut() = new_screen_top
|
*new_screen_top.row_mut() = new_screen_top
|
||||||
// .row()
|
.row()
|
||||||
// .saturating_sub(visible_rows.saturating_sub(scroll_margin_rows));
|
.saturating_sub(visible_rows.saturating_sub(scroll_margin_rows));
|
||||||
// *new_screen_top.column_mut() = 0;
|
*new_screen_top.column_mut() = 0;
|
||||||
// let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
let new_screen_top = new_screen_top.to_offset(&snapshot, Bias::Left);
|
||||||
// let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
let new_anchor = snapshot.buffer_snapshot.anchor_before(new_screen_top);
|
||||||
|
|
||||||
// editor.set_scroll_anchor(
|
self.set_scroll_anchor(
|
||||||
// ScrollAnchor {
|
ScrollAnchor {
|
||||||
// anchor: new_anchor,
|
anchor: new_anchor,
|
||||||
// offset: Default::default(),
|
offset: Default::default(),
|
||||||
// },
|
},
|
||||||
// cx,
|
cx,
|
||||||
// )
|
)
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,39 +302,39 @@ impl SelectionsCollection {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn build_columnar_selection(
|
pub fn build_columnar_selection(
|
||||||
// &mut self,
|
&mut self,
|
||||||
// display_map: &DisplaySnapshot,
|
display_map: &DisplaySnapshot,
|
||||||
// row: u32,
|
row: u32,
|
||||||
// positions: &Range<Pixels>,
|
positions: &Range<Pixels>,
|
||||||
// reversed: bool,
|
reversed: bool,
|
||||||
// text_layout_details: &TextLayoutDetails,
|
text_layout_details: &TextLayoutDetails,
|
||||||
// ) -> Option<Selection<Point>> {
|
) -> Option<Selection<Point>> {
|
||||||
// let is_empty = positions.start == positions.end;
|
let is_empty = positions.start == positions.end;
|
||||||
// let line_len = display_map.line_len(row);
|
let line_len = display_map.line_len(row);
|
||||||
|
|
||||||
// let layed_out_line = display_map.lay_out_line_for_row(row, &text_layout_details);
|
let layed_out_line = display_map.lay_out_line_for_row(row, &text_layout_details);
|
||||||
|
|
||||||
// let start_col = layed_out_line.closest_index_for_x(positions.start) as u32;
|
let start_col = layed_out_line.closest_index_for_x(positions.start) as u32;
|
||||||
// if start_col < line_len || (is_empty && positions.start == layed_out_line.width()) {
|
if start_col < line_len || (is_empty && positions.start == layed_out_line.width) {
|
||||||
// let start = DisplayPoint::new(row, start_col);
|
let start = DisplayPoint::new(row, start_col);
|
||||||
// let end_col = layed_out_line.closest_index_for_x(positions.end) as u32;
|
let end_col = layed_out_line.closest_index_for_x(positions.end) as u32;
|
||||||
// let end = DisplayPoint::new(row, end_col);
|
let end = DisplayPoint::new(row, end_col);
|
||||||
|
|
||||||
// Some(Selection {
|
Some(Selection {
|
||||||
// id: post_inc(&mut self.next_selection_id),
|
id: post_inc(&mut self.next_selection_id),
|
||||||
// start: start.to_point(display_map),
|
start: start.to_point(display_map),
|
||||||
// end: end.to_point(display_map),
|
end: end.to_point(display_map),
|
||||||
// reversed,
|
reversed,
|
||||||
// goal: SelectionGoal::HorizontalRange {
|
goal: SelectionGoal::HorizontalRange {
|
||||||
// start: positions.start,
|
start: positions.start.into(),
|
||||||
// end: positions.end,
|
end: positions.end.into(),
|
||||||
// },
|
},
|
||||||
// })
|
})
|
||||||
// } else {
|
} else {
|
||||||
// None
|
None
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
pub(crate) fn change_with<R>(
|
pub(crate) fn change_with<R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
@ -4,7 +4,6 @@ use workspace::ModalRegistry;
|
||||||
actions!(Toggle);
|
actions!(Toggle);
|
||||||
|
|
||||||
pub fn init(cx: &mut AppContext) {
|
pub fn init(cx: &mut AppContext) {
|
||||||
cx.register_action_type::<Toggle>();
|
|
||||||
cx.global_mut::<ModalRegistry>()
|
cx.global_mut::<ModalRegistry>()
|
||||||
.register_modal(Toggle, |_, cx| {
|
.register_modal(Toggle, |_, cx| {
|
||||||
// if let Some(editor) = workspace
|
// if let Some(editor) = workspace
|
||||||
|
|
|
@ -1,9 +1,54 @@
|
||||||
use crate::SharedString;
|
use crate::SharedString;
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::any::{type_name, Any};
|
use std::any::{type_name, Any};
|
||||||
|
|
||||||
|
/// Actions are used to implement keyboard-driven UI.
|
||||||
|
/// When you declare an action, you can bind keys to the action in the keymap and
|
||||||
|
/// listeners for that action in the element tree.
|
||||||
|
///
|
||||||
|
/// To declare a list of simple actions, you can use the actions! macro, which defines a simple unit struct
|
||||||
|
/// action for each listed action name.
|
||||||
|
/// ```rust
|
||||||
|
/// actions!(MoveUp, MoveDown, MoveLeft, MoveRight, Newline);
|
||||||
|
/// ```
|
||||||
|
/// More complex data types can also be actions. If you annotate your type with the `#[action]` proc macro,
|
||||||
|
/// it will automatically
|
||||||
|
/// ```
|
||||||
|
/// #[action]
|
||||||
|
/// pub struct SelectNext {
|
||||||
|
/// pub replace_newest: bool,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Any type A that satisfies the following bounds is automatically an action:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// A: for<'a> Deserialize<'a> + PartialEq + Clone + Default + std::fmt::Debug + 'static,
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The `#[action]` annotation will derive these implementations for your struct automatically. If you
|
||||||
|
/// want to control them manually, you can use the lower-level `#[register_action]` macro, which only
|
||||||
|
/// generates the code needed to register your action before `main`. Then you'll need to implement all
|
||||||
|
/// the traits manually.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #[gpui::register_action]
|
||||||
|
/// #[derive(gpui::serde::Deserialize, std::cmp::PartialEq, std::clone::Clone, std::fmt::Debug)]
|
||||||
|
/// pub struct Paste {
|
||||||
|
/// pub content: SharedString,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl std::default::Default for Paste {
|
||||||
|
/// fn default() -> Self {
|
||||||
|
/// Self {
|
||||||
|
/// content: SharedString::from("🍝"),
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub trait Action: std::fmt::Debug + 'static {
|
pub trait Action: std::fmt::Debug + 'static {
|
||||||
fn qualified_name() -> SharedString
|
fn qualified_name() -> SharedString
|
||||||
where
|
where
|
||||||
|
@ -17,32 +62,7 @@ pub trait Action: std::fmt::Debug + 'static {
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
}
|
}
|
||||||
|
|
||||||
// actions defines structs that can be used as actions.
|
// Types become actions by satisfying a list of trait bounds.
|
||||||
#[macro_export]
|
|
||||||
macro_rules! actions {
|
|
||||||
() => {};
|
|
||||||
|
|
||||||
( $name:ident ) => {
|
|
||||||
#[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug, ::std::cmp::PartialEq, $crate::serde::Deserialize)]
|
|
||||||
pub struct $name;
|
|
||||||
};
|
|
||||||
|
|
||||||
( $name:ident { $($token:tt)* } ) => {
|
|
||||||
#[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug, ::std::cmp::PartialEq, $crate::serde::Deserialize)]
|
|
||||||
pub struct $name { $($token)* }
|
|
||||||
};
|
|
||||||
|
|
||||||
( $name:ident, $($rest:tt)* ) => {
|
|
||||||
actions!($name);
|
|
||||||
actions!($($rest)*);
|
|
||||||
};
|
|
||||||
|
|
||||||
( $name:ident { $($token:tt)* }, $($rest:tt)* ) => {
|
|
||||||
actions!($name { $($token)* });
|
|
||||||
actions!($($rest)*);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A> Action for A
|
impl<A> Action for A
|
||||||
where
|
where
|
||||||
A: for<'a> Deserialize<'a> + PartialEq + Clone + Default + std::fmt::Debug + 'static,
|
A: for<'a> Deserialize<'a> + PartialEq + Clone + Default + std::fmt::Debug + 'static,
|
||||||
|
@ -80,6 +100,61 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ActionBuilder = fn(json: Option<serde_json::Value>) -> anyhow::Result<Box<dyn Action>>;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref ACTION_REGISTRY: RwLock<ActionRegistry> = RwLock::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct ActionRegistry {
|
||||||
|
builders_by_name: HashMap<SharedString, ActionBuilder>,
|
||||||
|
all_names: Vec<SharedString>, // So we can return a static slice.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register an action type to allow it to be referenced in keymaps.
|
||||||
|
pub fn register_action<A: Action>() {
|
||||||
|
let name = A::qualified_name();
|
||||||
|
let mut lock = ACTION_REGISTRY.write();
|
||||||
|
lock.builders_by_name.insert(name.clone(), A::build);
|
||||||
|
lock.all_names.push(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct an action based on its name and optional JSON parameters sourced from the keymap.
|
||||||
|
pub fn build_action(name: &str, params: Option<serde_json::Value>) -> Result<Box<dyn Action>> {
|
||||||
|
let lock = ACTION_REGISTRY.read();
|
||||||
|
let build_action = lock
|
||||||
|
.builders_by_name
|
||||||
|
.get(name)
|
||||||
|
.ok_or_else(|| anyhow!("no action type registered for {}", name))?;
|
||||||
|
(build_action)(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn all_action_names() -> MappedRwLockReadGuard<'static, [SharedString]> {
|
||||||
|
let lock = ACTION_REGISTRY.read();
|
||||||
|
RwLockReadGuard::map(lock, |registry: &ActionRegistry| {
|
||||||
|
registry.all_names.as_slice()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Defines unit structs that can be used as actions.
|
||||||
|
/// To use more complex data types as actions, annotate your type with the #[action] macro.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! actions {
|
||||||
|
() => {};
|
||||||
|
|
||||||
|
( $name:ident ) => {
|
||||||
|
#[gpui::register_action]
|
||||||
|
#[derive(::std::clone::Clone, ::std::default::Default, ::std::fmt::Debug, ::std::cmp::PartialEq, $crate::serde::Deserialize)]
|
||||||
|
pub struct $name;
|
||||||
|
};
|
||||||
|
|
||||||
|
( $name:ident, $($rest:tt)* ) => {
|
||||||
|
actions!($name);
|
||||||
|
actions!($($rest)*);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||||
pub struct DispatchContext {
|
pub struct DispatchContext {
|
||||||
set: HashSet<SharedString>,
|
set: HashSet<SharedString>,
|
||||||
|
@ -317,22 +392,23 @@ fn skip_whitespace(source: &str) -> &str {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate as gpui;
|
||||||
use DispatchContextPredicate::*;
|
use DispatchContextPredicate::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_actions_definition() {
|
fn test_actions_definition() {
|
||||||
{
|
{
|
||||||
actions!(A, B { field: i32 }, C, D, E, F {}, G);
|
actions!(A, B, C, D, E, F, G);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
actions!(
|
actions!(
|
||||||
A,
|
A,
|
||||||
B { field: i32 },
|
B,
|
||||||
C,
|
C,
|
||||||
D,
|
D,
|
||||||
E,
|
E,
|
||||||
F {},
|
F,
|
||||||
G, // Don't wrap, test the trailing comma
|
G, // Don't wrap, test the trailing comma
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@ use crate::{
|
||||||
current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AnyWindowHandle,
|
current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AnyWindowHandle,
|
||||||
AppMetadata, AssetSource, BackgroundExecutor, ClipboardItem, Context, DispatchPhase, DisplayId,
|
AppMetadata, AssetSource, BackgroundExecutor, ClipboardItem, Context, DispatchPhase, DisplayId,
|
||||||
Entity, FocusEvent, FocusHandle, FocusId, ForegroundExecutor, KeyBinding, Keymap, LayoutId,
|
Entity, FocusEvent, FocusHandle, FocusId, ForegroundExecutor, KeyBinding, Keymap, LayoutId,
|
||||||
PathPromptOptions, Pixels, Platform, PlatformDisplay, Point, Render, SharedString,
|
PathPromptOptions, Pixels, Platform, PlatformDisplay, Point, Render, SubscriberSet,
|
||||||
SubscriberSet, Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem,
|
Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, Window,
|
||||||
View, Window, WindowContext, WindowHandle, WindowId,
|
WindowContext, WindowHandle, WindowId,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use collections::{HashMap, HashSet, VecDeque};
|
use collections::{HashMap, HashSet, VecDeque};
|
||||||
|
@ -140,7 +140,6 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActionBuilder = fn(json: Option<serde_json::Value>) -> anyhow::Result<Box<dyn Action>>;
|
|
||||||
pub(crate) type FrameCallback = Box<dyn FnOnce(&mut AppContext)>;
|
pub(crate) type FrameCallback = Box<dyn FnOnce(&mut AppContext)>;
|
||||||
type Handler = Box<dyn FnMut(&mut AppContext) -> bool + 'static>;
|
type Handler = Box<dyn FnMut(&mut AppContext) -> bool + 'static>;
|
||||||
type Listener = Box<dyn FnMut(&dyn Any, &mut AppContext) -> bool + 'static>;
|
type Listener = Box<dyn FnMut(&dyn Any, &mut AppContext) -> bool + 'static>;
|
||||||
|
@ -176,7 +175,6 @@ pub struct AppContext {
|
||||||
pub(crate) keymap: Arc<Mutex<Keymap>>,
|
pub(crate) keymap: Arc<Mutex<Keymap>>,
|
||||||
pub(crate) global_action_listeners:
|
pub(crate) global_action_listeners:
|
||||||
HashMap<TypeId, Vec<Box<dyn Fn(&dyn Action, DispatchPhase, &mut Self)>>>,
|
HashMap<TypeId, Vec<Box<dyn Fn(&dyn Action, DispatchPhase, &mut Self)>>>,
|
||||||
action_builders: HashMap<SharedString, ActionBuilder>,
|
|
||||||
pending_effects: VecDeque<Effect>,
|
pending_effects: VecDeque<Effect>,
|
||||||
pub(crate) pending_notifications: HashSet<EntityId>,
|
pub(crate) pending_notifications: HashSet<EntityId>,
|
||||||
pub(crate) pending_global_notifications: HashSet<TypeId>,
|
pub(crate) pending_global_notifications: HashSet<TypeId>,
|
||||||
|
@ -234,7 +232,6 @@ impl AppContext {
|
||||||
windows: SlotMap::with_key(),
|
windows: SlotMap::with_key(),
|
||||||
keymap: Arc::new(Mutex::new(Keymap::default())),
|
keymap: Arc::new(Mutex::new(Keymap::default())),
|
||||||
global_action_listeners: HashMap::default(),
|
global_action_listeners: HashMap::default(),
|
||||||
action_builders: HashMap::default(),
|
|
||||||
pending_effects: VecDeque::new(),
|
pending_effects: VecDeque::new(),
|
||||||
pending_notifications: HashSet::default(),
|
pending_notifications: HashSet::default(),
|
||||||
pending_global_notifications: HashSet::default(),
|
pending_global_notifications: HashSet::default(),
|
||||||
|
@ -695,10 +692,6 @@ impl AppContext {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_action_names<'a>(&'a self) -> impl Iterator<Item = SharedString> + 'a {
|
|
||||||
self.action_builders.keys().cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Move the global of the given type to the stack.
|
/// Move the global of the given type to the stack.
|
||||||
pub(crate) fn lease_global<G: 'static>(&mut self) -> GlobalLease<G> {
|
pub(crate) fn lease_global<G: 'static>(&mut self) -> GlobalLease<G> {
|
||||||
GlobalLease::new(
|
GlobalLease::new(
|
||||||
|
@ -761,24 +754,6 @@ impl AppContext {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register an action type to allow it to be referenced in keymaps.
|
|
||||||
pub fn register_action_type<A: Action>(&mut self) {
|
|
||||||
self.action_builders.insert(A::qualified_name(), A::build);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct an action based on its name and parameters.
|
|
||||||
pub fn build_action(
|
|
||||||
&mut self,
|
|
||||||
name: &str,
|
|
||||||
params: Option<serde_json::Value>,
|
|
||||||
) -> Result<Box<dyn Action>> {
|
|
||||||
let build = self
|
|
||||||
.action_builders
|
|
||||||
.get(name)
|
|
||||||
.ok_or_else(|| anyhow!("no action type registered for {}", name))?;
|
|
||||||
(build)(params)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Event handlers propagate events by default. Call this method to stop dispatching to
|
/// Event handlers propagate events by default. Call this method to stop dispatching to
|
||||||
/// event handlers with a lower z-index (mouse) or higher in the tree (keyboard). This is
|
/// event handlers with a lower z-index (mouse) or higher in the tree (keyboard). This is
|
||||||
/// the opposite of [propagate]. It's also possible to cancel a call to [propagate] by
|
/// the opposite of [propagate]. It's also possible to cancel a call to [propagate] by
|
||||||
|
|
|
@ -68,7 +68,8 @@ impl<T> Future for Task<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
type AnyLocalFuture<R> = Pin<Box<dyn 'static + Future<Output = R>>>;
|
||||||
|
type AnyFuture<R> = Pin<Box<dyn 'static + Send + Future<Output = R>>>;
|
||||||
impl BackgroundExecutor {
|
impl BackgroundExecutor {
|
||||||
pub fn new(dispatcher: Arc<dyn PlatformDispatcher>) -> Self {
|
pub fn new(dispatcher: Arc<dyn PlatformDispatcher>) -> Self {
|
||||||
Self { dispatcher }
|
Self { dispatcher }
|
||||||
|
@ -81,11 +82,17 @@ impl BackgroundExecutor {
|
||||||
R: Send + 'static,
|
R: Send + 'static,
|
||||||
{
|
{
|
||||||
let dispatcher = self.dispatcher.clone();
|
let dispatcher = self.dispatcher.clone();
|
||||||
|
fn inner<R: Send + 'static>(
|
||||||
|
dispatcher: Arc<dyn PlatformDispatcher>,
|
||||||
|
future: AnyFuture<R>,
|
||||||
|
) -> Task<R> {
|
||||||
let (runnable, task) =
|
let (runnable, task) =
|
||||||
async_task::spawn(future, move |runnable| dispatcher.dispatch(runnable));
|
async_task::spawn(future, move |runnable| dispatcher.dispatch(runnable));
|
||||||
runnable.schedule();
|
runnable.schedule();
|
||||||
Task::Spawned(task)
|
Task::Spawned(task)
|
||||||
}
|
}
|
||||||
|
inner::<R>(dispatcher, Box::pin(future))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
pub fn block_test<R>(&self, future: impl Future<Output = R>) -> R {
|
pub fn block_test<R>(&self, future: impl Future<Output = R>) -> R {
|
||||||
|
@ -243,12 +250,18 @@ impl ForegroundExecutor {
|
||||||
R: 'static,
|
R: 'static,
|
||||||
{
|
{
|
||||||
let dispatcher = self.dispatcher.clone();
|
let dispatcher = self.dispatcher.clone();
|
||||||
|
fn inner<R: 'static>(
|
||||||
|
dispatcher: Arc<dyn PlatformDispatcher>,
|
||||||
|
future: AnyLocalFuture<R>,
|
||||||
|
) -> Task<R> {
|
||||||
let (runnable, task) = async_task::spawn_local(future, move |runnable| {
|
let (runnable, task) = async_task::spawn_local(future, move |runnable| {
|
||||||
dispatcher.dispatch_on_main_thread(runnable)
|
dispatcher.dispatch_on_main_thread(runnable)
|
||||||
});
|
});
|
||||||
runnable.schedule();
|
runnable.schedule();
|
||||||
Task::Spawned(task)
|
Task::Spawned(task)
|
||||||
}
|
}
|
||||||
|
inner::<R>(dispatcher, Box::pin(future))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Scope<'a> {
|
pub struct Scope<'a> {
|
||||||
|
|
|
@ -37,6 +37,7 @@ pub use anyhow::Result;
|
||||||
pub use app::*;
|
pub use app::*;
|
||||||
pub use assets::*;
|
pub use assets::*;
|
||||||
pub use color::*;
|
pub use color::*;
|
||||||
|
pub use ctor::ctor;
|
||||||
pub use element::*;
|
pub use element::*;
|
||||||
pub use elements::*;
|
pub use elements::*;
|
||||||
pub use executor::*;
|
pub use executor::*;
|
||||||
|
|
|
@ -87,7 +87,7 @@ impl MetalRenderer {
|
||||||
MTLResourceOptions::StorageModeManaged,
|
MTLResourceOptions::StorageModeManaged,
|
||||||
);
|
);
|
||||||
|
|
||||||
let paths_rasterization_pipeline_state = build_pipeline_state(
|
let paths_rasterization_pipeline_state = build_path_rasterization_pipeline_state(
|
||||||
&device,
|
&device,
|
||||||
&library,
|
&library,
|
||||||
"paths_rasterization",
|
"paths_rasterization",
|
||||||
|
@ -823,7 +823,40 @@ fn build_pipeline_state(
|
||||||
color_attachment.set_source_alpha_blend_factor(metal::MTLBlendFactor::One);
|
color_attachment.set_source_alpha_blend_factor(metal::MTLBlendFactor::One);
|
||||||
color_attachment.set_destination_rgb_blend_factor(metal::MTLBlendFactor::OneMinusSourceAlpha);
|
color_attachment.set_destination_rgb_blend_factor(metal::MTLBlendFactor::OneMinusSourceAlpha);
|
||||||
color_attachment.set_destination_alpha_blend_factor(metal::MTLBlendFactor::One);
|
color_attachment.set_destination_alpha_blend_factor(metal::MTLBlendFactor::One);
|
||||||
descriptor.set_depth_attachment_pixel_format(MTLPixelFormat::Invalid);
|
|
||||||
|
device
|
||||||
|
.new_render_pipeline_state(&descriptor)
|
||||||
|
.expect("could not create render pipeline state")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_path_rasterization_pipeline_state(
|
||||||
|
device: &metal::DeviceRef,
|
||||||
|
library: &metal::LibraryRef,
|
||||||
|
label: &str,
|
||||||
|
vertex_fn_name: &str,
|
||||||
|
fragment_fn_name: &str,
|
||||||
|
pixel_format: metal::MTLPixelFormat,
|
||||||
|
) -> metal::RenderPipelineState {
|
||||||
|
let vertex_fn = library
|
||||||
|
.get_function(vertex_fn_name, None)
|
||||||
|
.expect("error locating vertex function");
|
||||||
|
let fragment_fn = library
|
||||||
|
.get_function(fragment_fn_name, None)
|
||||||
|
.expect("error locating fragment function");
|
||||||
|
|
||||||
|
let descriptor = metal::RenderPipelineDescriptor::new();
|
||||||
|
descriptor.set_label(label);
|
||||||
|
descriptor.set_vertex_function(Some(vertex_fn.as_ref()));
|
||||||
|
descriptor.set_fragment_function(Some(fragment_fn.as_ref()));
|
||||||
|
let color_attachment = descriptor.color_attachments().object_at(0).unwrap();
|
||||||
|
color_attachment.set_pixel_format(pixel_format);
|
||||||
|
color_attachment.set_blending_enabled(true);
|
||||||
|
color_attachment.set_rgb_blend_operation(metal::MTLBlendOperation::Add);
|
||||||
|
color_attachment.set_alpha_blend_operation(metal::MTLBlendOperation::Add);
|
||||||
|
color_attachment.set_source_rgb_blend_factor(metal::MTLBlendFactor::One);
|
||||||
|
color_attachment.set_source_alpha_blend_factor(metal::MTLBlendFactor::One);
|
||||||
|
color_attachment.set_destination_rgb_blend_factor(metal::MTLBlendFactor::One);
|
||||||
|
color_attachment.set_destination_alpha_blend_factor(metal::MTLBlendFactor::One);
|
||||||
|
|
||||||
device
|
device
|
||||||
.new_render_pipeline_state(&descriptor)
|
.new_render_pipeline_state(&descriptor)
|
||||||
|
|
|
@ -614,6 +614,10 @@ impl<'a> WindowContext<'a> {
|
||||||
.find(|display| display.id() == self.window.display_id)
|
.find(|display| display.id() == self.window.display_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn show_character_palette(&self) {
|
||||||
|
self.window.platform_window.show_character_palette();
|
||||||
|
}
|
||||||
|
|
||||||
/// The scale factor of the display associated with the window. For example, it could
|
/// The scale factor of the display associated with the window. For example, it could
|
||||||
/// return 2.0 for a "retina" display, indicating that each logical pixel should actually
|
/// return 2.0 for a "retina" display, indicating that each logical pixel should actually
|
||||||
/// be rendered as two pixels on screen.
|
/// be rendered as two pixels on screen.
|
||||||
|
|
55
crates/gpui2_macros/src/action.rs
Normal file
55
crates/gpui2_macros/src/action.rs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// Input:
|
||||||
|
//
|
||||||
|
// #[action]
|
||||||
|
// struct Foo {
|
||||||
|
// bar: String,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
//
|
||||||
|
// #[gpui::register_action]
|
||||||
|
// #[derive(gpui::serde::Deserialize, std::cmp::PartialEq, std::clone::Clone, std::default::Default, std::fmt::Debug)]
|
||||||
|
// struct Foo {
|
||||||
|
// bar: String,
|
||||||
|
// }
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{parse_macro_input, DeriveInput};
|
||||||
|
|
||||||
|
pub fn action(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
let input = parse_macro_input!(item as DeriveInput);
|
||||||
|
let name = &input.ident;
|
||||||
|
let attrs = input
|
||||||
|
.attrs
|
||||||
|
.into_iter()
|
||||||
|
.filter(|attr| !attr.path.is_ident("action"))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let attributes = quote! {
|
||||||
|
#[gpui::register_action]
|
||||||
|
#[derive(gpui::serde::Deserialize, std::cmp::PartialEq, std::clone::Clone, std::default::Default, std::fmt::Debug)]
|
||||||
|
#(#attrs)*
|
||||||
|
};
|
||||||
|
let visibility = input.vis;
|
||||||
|
|
||||||
|
let output = match input.data {
|
||||||
|
syn::Data::Struct(ref struct_data) => {
|
||||||
|
let fields = &struct_data.fields;
|
||||||
|
quote! {
|
||||||
|
#attributes
|
||||||
|
#visibility struct #name #fields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syn::Data::Enum(ref enum_data) => {
|
||||||
|
let variants = &enum_data.variants;
|
||||||
|
quote! {
|
||||||
|
#attributes
|
||||||
|
#visibility enum #name { #variants }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("Expected a struct or an enum."),
|
||||||
|
};
|
||||||
|
|
||||||
|
TokenStream::from(output)
|
||||||
|
}
|
|
@ -1,14 +1,26 @@
|
||||||
use proc_macro::TokenStream;
|
mod action;
|
||||||
|
|
||||||
mod derive_component;
|
mod derive_component;
|
||||||
|
mod register_action;
|
||||||
mod style_helpers;
|
mod style_helpers;
|
||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn style_helpers(args: TokenStream) -> TokenStream {
|
pub fn style_helpers(args: TokenStream) -> TokenStream {
|
||||||
style_helpers::style_helpers(args)
|
style_helpers::style_helpers(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn action(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
action::action(attr, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn register_action(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
register_action::register_action(attr, item)
|
||||||
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(Component, attributes(component))]
|
#[proc_macro_derive(Component, attributes(component))]
|
||||||
pub fn derive_component(input: TokenStream) -> TokenStream {
|
pub fn derive_component(input: TokenStream) -> TokenStream {
|
||||||
derive_component::derive_component(input)
|
derive_component::derive_component(input)
|
||||||
|
|
33
crates/gpui2_macros/src/register_action.rs
Normal file
33
crates/gpui2_macros/src/register_action.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// Input:
|
||||||
|
//
|
||||||
|
// struct FooBar {}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
//
|
||||||
|
// struct FooBar {}
|
||||||
|
//
|
||||||
|
// #[allow(non_snake_case)]
|
||||||
|
// #[gpui2::ctor]
|
||||||
|
// fn register_foobar_builder() {
|
||||||
|
// gpui2::register_action_builder::<Foo>()
|
||||||
|
// }
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
use syn::{parse_macro_input, DeriveInput};
|
||||||
|
|
||||||
|
pub fn register_action(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
let input = parse_macro_input!(item as DeriveInput);
|
||||||
|
let type_name = &input.ident;
|
||||||
|
let ctor_fn_name = format_ident!("register_{}_builder", type_name.to_string().to_lowercase());
|
||||||
|
|
||||||
|
let expanded = quote! {
|
||||||
|
#input
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[gpui::ctor]
|
||||||
|
fn #ctor_fn_name() {
|
||||||
|
gpui::register_action::<#type_name>()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TokenStream::from(expanded)
|
||||||
|
}
|
|
@ -73,9 +73,9 @@ impl KeymapFile {
|
||||||
"Expected first item in array to be a string."
|
"Expected first item in array to be a string."
|
||||||
)));
|
)));
|
||||||
};
|
};
|
||||||
cx.build_action(&name, Some(data))
|
gpui::build_action(&name, Some(data))
|
||||||
}
|
}
|
||||||
Value::String(name) => cx.build_action(&name, None),
|
Value::String(name) => gpui::build_action(&name, None),
|
||||||
Value::Null => Ok(no_action()),
|
Value::Null => Ok(no_action()),
|
||||||
_ => {
|
_ => {
|
||||||
return Some(Err(anyhow!("Expected two-element array, got {action:?}")))
|
return Some(Err(anyhow!("Expected two-element array, got {action:?}")))
|
||||||
|
|
|
@ -15,8 +15,6 @@ impl FocusStory {
|
||||||
KeyBinding::new("cmd-a", ActionB, Some("child-1")),
|
KeyBinding::new("cmd-a", ActionB, Some("child-1")),
|
||||||
KeyBinding::new("cmd-c", ActionC, None),
|
KeyBinding::new("cmd-c", ActionC, None),
|
||||||
]);
|
]);
|
||||||
cx.register_action_type::<ActionA>();
|
|
||||||
cx.register_action_type::<ActionB>();
|
|
||||||
|
|
||||||
cx.build_view(move |cx| Self {})
|
cx.build_view(move |cx| Self {})
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ pub enum ComponentStory {
|
||||||
Palette,
|
Palette,
|
||||||
Panel,
|
Panel,
|
||||||
ProjectPanel,
|
ProjectPanel,
|
||||||
|
Players,
|
||||||
RecentProjects,
|
RecentProjects,
|
||||||
Scroll,
|
Scroll,
|
||||||
Tab,
|
Tab,
|
||||||
|
@ -80,6 +81,7 @@ impl ComponentStory {
|
||||||
Self::MultiBuffer => cx.build_view(|_| ui::MultiBufferStory).into(),
|
Self::MultiBuffer => cx.build_view(|_| ui::MultiBufferStory).into(),
|
||||||
Self::NotificationsPanel => cx.build_view(|cx| ui::NotificationsPanelStory).into(),
|
Self::NotificationsPanel => cx.build_view(|cx| ui::NotificationsPanelStory).into(),
|
||||||
Self::Palette => cx.build_view(|cx| ui::PaletteStory).into(),
|
Self::Palette => cx.build_view(|cx| ui::PaletteStory).into(),
|
||||||
|
Self::Players => cx.build_view(|_| theme2::PlayerStory).into(),
|
||||||
Self::Panel => cx.build_view(|cx| ui::PanelStory).into(),
|
Self::Panel => cx.build_view(|cx| ui::PanelStory).into(),
|
||||||
Self::ProjectPanel => cx.build_view(|_| ui::ProjectPanelStory).into(),
|
Self::ProjectPanel => cx.build_view(|_| ui::ProjectPanelStory).into(),
|
||||||
Self::RecentProjects => cx.build_view(|_| ui::RecentProjectsStory).into(),
|
Self::RecentProjects => cx.build_view(|_| ui::RecentProjectsStory).into(),
|
||||||
|
|
|
@ -5,6 +5,8 @@ edition = "2021"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
default = ["stories"]
|
||||||
|
stories = ["dep:itertools"]
|
||||||
test-support = [
|
test-support = [
|
||||||
"gpui/test-support",
|
"gpui/test-support",
|
||||||
"fs/test-support",
|
"fs/test-support",
|
||||||
|
@ -30,6 +32,7 @@ settings = { package = "settings2", path = "../settings2" }
|
||||||
toml.workspace = true
|
toml.workspace = true
|
||||||
uuid.workspace = true
|
uuid.workspace = true
|
||||||
util = { path = "../util" }
|
util = { path = "../util" }
|
||||||
|
itertools = { version = "0.11.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
|
gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||||
use gpui::Hsla;
|
use gpui::Hsla;
|
||||||
use refineable::Refineable;
|
use refineable::Refineable;
|
||||||
|
|
||||||
use crate::SyntaxTheme;
|
use crate::{PlayerColors, SyntaxTheme};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SystemColors {
|
pub struct SystemColors {
|
||||||
|
@ -13,33 +13,6 @@ pub struct SystemColors {
|
||||||
pub mac_os_traffic_light_green: Hsla,
|
pub mac_os_traffic_light_green: Hsla,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct PlayerColor {
|
|
||||||
pub cursor: Hsla,
|
|
||||||
pub background: Hsla,
|
|
||||||
pub selection: Hsla,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct PlayerColors(pub Vec<PlayerColor>);
|
|
||||||
|
|
||||||
impl PlayerColors {
|
|
||||||
pub fn local(&self) -> PlayerColor {
|
|
||||||
// todo!("use a valid color");
|
|
||||||
*self.0.first().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn absent(&self) -> PlayerColor {
|
|
||||||
// todo!("use a valid color");
|
|
||||||
*self.0.last().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn color_for_participant(&self, participant_index: u32) -> PlayerColor {
|
|
||||||
let len = self.0.len() - 1;
|
|
||||||
self.0[(participant_index as usize % len) + 1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Refineable, Clone, Debug)]
|
#[derive(Refineable, Clone, Debug)]
|
||||||
#[refineable(debug)]
|
#[refineable(debug)]
|
||||||
pub struct StatusColors {
|
pub struct StatusColors {
|
||||||
|
|
|
@ -3,12 +3,106 @@ use std::num::ParseIntError;
|
||||||
use gpui::{hsla, Hsla, Rgba};
|
use gpui::{hsla, Hsla, Rgba};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
colors::{GitStatusColors, PlayerColor, PlayerColors, StatusColors, SystemColors, ThemeColors},
|
colors::{GitStatusColors, StatusColors, SystemColors, ThemeColors},
|
||||||
scale::{ColorScaleSet, ColorScales},
|
scale::{ColorScaleSet, ColorScales},
|
||||||
syntax::SyntaxTheme,
|
syntax::SyntaxTheme,
|
||||||
ColorScale,
|
ColorScale, PlayerColor, PlayerColors,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
impl Default for PlayerColors {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(vec![
|
||||||
|
PlayerColor {
|
||||||
|
cursor: blue().dark().step_9(),
|
||||||
|
background: blue().dark().step_5(),
|
||||||
|
selection: blue().dark().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: orange().dark().step_9(),
|
||||||
|
background: orange().dark().step_5(),
|
||||||
|
selection: orange().dark().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: pink().dark().step_9(),
|
||||||
|
background: pink().dark().step_5(),
|
||||||
|
selection: pink().dark().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: lime().dark().step_9(),
|
||||||
|
background: lime().dark().step_5(),
|
||||||
|
selection: lime().dark().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: purple().dark().step_9(),
|
||||||
|
background: purple().dark().step_5(),
|
||||||
|
selection: purple().dark().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: amber().dark().step_9(),
|
||||||
|
background: amber().dark().step_5(),
|
||||||
|
selection: amber().dark().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: jade().dark().step_9(),
|
||||||
|
background: jade().dark().step_5(),
|
||||||
|
selection: jade().dark().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: red().dark().step_9(),
|
||||||
|
background: red().dark().step_5(),
|
||||||
|
selection: red().dark().step_3(),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlayerColors {
|
||||||
|
pub fn default_light() -> Self {
|
||||||
|
Self(vec![
|
||||||
|
PlayerColor {
|
||||||
|
cursor: blue().light().step_9(),
|
||||||
|
background: blue().light().step_4(),
|
||||||
|
selection: blue().light().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: orange().light().step_9(),
|
||||||
|
background: orange().light().step_4(),
|
||||||
|
selection: orange().light().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: pink().light().step_9(),
|
||||||
|
background: pink().light().step_4(),
|
||||||
|
selection: pink().light().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: lime().light().step_9(),
|
||||||
|
background: lime().light().step_4(),
|
||||||
|
selection: lime().light().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: purple().light().step_9(),
|
||||||
|
background: purple().light().step_4(),
|
||||||
|
selection: purple().light().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: amber().light().step_9(),
|
||||||
|
background: amber().light().step_4(),
|
||||||
|
selection: amber().light().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: jade().light().step_9(),
|
||||||
|
background: jade().light().step_4(),
|
||||||
|
selection: jade().light().step_3(),
|
||||||
|
},
|
||||||
|
PlayerColor {
|
||||||
|
cursor: red().light().step_9(),
|
||||||
|
background: red().light().step_4(),
|
||||||
|
selection: red().light().step_3(),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn neutral() -> ColorScaleSet {
|
fn neutral() -> ColorScaleSet {
|
||||||
slate()
|
slate()
|
||||||
}
|
}
|
||||||
|
@ -27,17 +121,17 @@ impl Default for SystemColors {
|
||||||
impl Default for StatusColors {
|
impl Default for StatusColors {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
conflict: red().dark().step_11(),
|
conflict: red().dark().step_9(),
|
||||||
created: grass().dark().step_11(),
|
created: grass().dark().step_9(),
|
||||||
deleted: red().dark().step_11(),
|
deleted: red().dark().step_9(),
|
||||||
error: red().dark().step_11(),
|
error: red().dark().step_9(),
|
||||||
hidden: neutral().dark().step_11(),
|
hidden: neutral().dark().step_9(),
|
||||||
ignored: neutral().dark().step_11(),
|
ignored: neutral().dark().step_9(),
|
||||||
info: blue().dark().step_11(),
|
info: blue().dark().step_9(),
|
||||||
modified: yellow().dark().step_11(),
|
modified: yellow().dark().step_9(),
|
||||||
renamed: blue().dark().step_11(),
|
renamed: blue().dark().step_9(),
|
||||||
success: grass().dark().step_11(),
|
success: grass().dark().step_9(),
|
||||||
warning: yellow().dark().step_11(),
|
warning: yellow().dark().step_9(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,43 +139,16 @@ impl Default for StatusColors {
|
||||||
impl Default for GitStatusColors {
|
impl Default for GitStatusColors {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
conflict: orange().dark().step_11(),
|
conflict: orange().dark().step_9(),
|
||||||
created: grass().dark().step_11(),
|
created: grass().dark().step_9(),
|
||||||
deleted: red().dark().step_11(),
|
deleted: red().dark().step_9(),
|
||||||
ignored: neutral().dark().step_11(),
|
ignored: neutral().dark().step_9(),
|
||||||
modified: yellow().dark().step_11(),
|
modified: yellow().dark().step_9(),
|
||||||
renamed: blue().dark().step_11(),
|
renamed: blue().dark().step_9(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PlayerColors {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(vec![
|
|
||||||
PlayerColor {
|
|
||||||
cursor: hsla(0.0, 0.0, 0.0, 1.0),
|
|
||||||
background: hsla(0.0, 0.0, 0.0, 1.0),
|
|
||||||
selection: hsla(0.0, 0.0, 0.0, 1.0),
|
|
||||||
},
|
|
||||||
PlayerColor {
|
|
||||||
cursor: hsla(0.0, 0.0, 0.0, 1.0),
|
|
||||||
background: hsla(0.0, 0.0, 0.0, 1.0),
|
|
||||||
selection: hsla(0.0, 0.0, 0.0, 1.0),
|
|
||||||
},
|
|
||||||
PlayerColor {
|
|
||||||
cursor: hsla(0.0, 0.0, 0.0, 1.0),
|
|
||||||
background: hsla(0.0, 0.0, 0.0, 1.0),
|
|
||||||
selection: hsla(0.0, 0.0, 0.0, 1.0),
|
|
||||||
},
|
|
||||||
PlayerColor {
|
|
||||||
cursor: hsla(0.0, 0.0, 0.0, 1.0),
|
|
||||||
background: hsla(0.0, 0.0, 0.0, 1.0),
|
|
||||||
selection: hsla(0.0, 0.0, 0.0, 1.0),
|
|
||||||
},
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SyntaxTheme {
|
impl SyntaxTheme {
|
||||||
pub fn default_light() -> Self {
|
pub fn default_light() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
colors::{GitStatusColors, PlayerColors, StatusColors, SystemColors, ThemeColors, ThemeStyles},
|
colors::{GitStatusColors, StatusColors, SystemColors, ThemeColors, ThemeStyles},
|
||||||
default_color_scales, Appearance, SyntaxTheme, Theme, ThemeFamily,
|
default_color_scales, Appearance, PlayerColors, SyntaxTheme, Theme, ThemeFamily,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn zed_pro_daylight() -> Theme {
|
fn zed_pro_daylight() -> Theme {
|
||||||
|
@ -15,7 +15,7 @@ fn zed_pro_daylight() -> Theme {
|
||||||
colors: ThemeColors::default_light(),
|
colors: ThemeColors::default_light(),
|
||||||
status: StatusColors::default(),
|
status: StatusColors::default(),
|
||||||
git: GitStatusColors::default(),
|
git: GitStatusColors::default(),
|
||||||
player: PlayerColors::default(),
|
player: PlayerColors::default_light(),
|
||||||
syntax: Arc::new(SyntaxTheme::default_light()),
|
syntax: Arc::new(SyntaxTheme::default_light()),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
170
crates/theme2/src/players.rs
Normal file
170
crates/theme2/src/players.rs
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
use gpui::Hsla;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct PlayerColor {
|
||||||
|
pub cursor: Hsla,
|
||||||
|
pub background: Hsla,
|
||||||
|
pub selection: Hsla,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A collection of colors that are used to color players in the editor.
|
||||||
|
///
|
||||||
|
/// The first color is always the local player's color, usually a blue.
|
||||||
|
///
|
||||||
|
/// The rest of the default colors crisscross back and forth on the
|
||||||
|
/// color wheel so that the colors are as distinct as possible.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PlayerColors(pub Vec<PlayerColor>);
|
||||||
|
|
||||||
|
impl PlayerColors {
|
||||||
|
pub fn local(&self) -> PlayerColor {
|
||||||
|
// todo!("use a valid color");
|
||||||
|
*self.0.first().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn absent(&self) -> PlayerColor {
|
||||||
|
// todo!("use a valid color");
|
||||||
|
*self.0.last().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn color_for_participant(&self, participant_index: u32) -> PlayerColor {
|
||||||
|
let len = self.0.len() - 1;
|
||||||
|
self.0[(participant_index as usize % len) + 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "stories")]
|
||||||
|
pub use stories::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "stories")]
|
||||||
|
mod stories {
|
||||||
|
use super::*;
|
||||||
|
use crate::{ActiveTheme, Story};
|
||||||
|
use gpui::{div, img, px, Div, ParentElement, Render, Styled, ViewContext};
|
||||||
|
|
||||||
|
pub struct PlayerStory;
|
||||||
|
|
||||||
|
impl Render for PlayerStory {
|
||||||
|
type Element = Div<Self>;
|
||||||
|
|
||||||
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||||
|
Story::container(cx).child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.gap_4()
|
||||||
|
.child(Story::title_for::<_, PlayerColors>(cx))
|
||||||
|
.child(Story::label(cx, "Player Colors"))
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.gap_1()
|
||||||
|
.child(
|
||||||
|
div().flex().gap_1().children(
|
||||||
|
cx.theme().players().0.clone().iter_mut().map(|player| {
|
||||||
|
div().w_8().h_8().rounded_md().bg(player.cursor)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(div().flex().gap_1().children(
|
||||||
|
cx.theme().players().0.clone().iter_mut().map(|player| {
|
||||||
|
div().w_8().h_8().rounded_md().bg(player.background)
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
.child(div().flex().gap_1().children(
|
||||||
|
cx.theme().players().0.clone().iter_mut().map(|player| {
|
||||||
|
div().w_8().h_8().rounded_md().bg(player.selection)
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.child(Story::label(cx, "Avatar Rings"))
|
||||||
|
.child(div().flex().gap_1().children(
|
||||||
|
cx.theme().players().0.clone().iter_mut().map(|player| {
|
||||||
|
div()
|
||||||
|
.my_1()
|
||||||
|
.rounded_full()
|
||||||
|
.border_2()
|
||||||
|
.border_color(player.cursor)
|
||||||
|
.child(
|
||||||
|
img()
|
||||||
|
.rounded_full()
|
||||||
|
.uri("https://avatars.githubusercontent.com/u/1714999?v=4")
|
||||||
|
.size_6()
|
||||||
|
.bg(gpui::red()),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
.child(Story::label(cx, "Player Backgrounds"))
|
||||||
|
.child(div().flex().gap_1().children(
|
||||||
|
cx.theme().players().0.clone().iter_mut().map(|player| {
|
||||||
|
div()
|
||||||
|
.my_1()
|
||||||
|
.rounded_xl()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.h_8()
|
||||||
|
.py_0p5()
|
||||||
|
.px_1p5()
|
||||||
|
.bg(player.background)
|
||||||
|
.child(
|
||||||
|
div().relative().neg_mx_1().rounded_full().z_index(3)
|
||||||
|
.border_2()
|
||||||
|
.border_color(player.background)
|
||||||
|
.size(px(28.))
|
||||||
|
.child(
|
||||||
|
img()
|
||||||
|
.rounded_full()
|
||||||
|
.uri("https://avatars.githubusercontent.com/u/1714999?v=4")
|
||||||
|
.size(px(24.))
|
||||||
|
.bg(gpui::red()),
|
||||||
|
),
|
||||||
|
).child(
|
||||||
|
div().relative().neg_mx_1().rounded_full().z_index(2)
|
||||||
|
.border_2()
|
||||||
|
.border_color(player.background)
|
||||||
|
.size(px(28.))
|
||||||
|
.child(
|
||||||
|
img()
|
||||||
|
.rounded_full()
|
||||||
|
.uri("https://avatars.githubusercontent.com/u/1714999?v=4")
|
||||||
|
.size(px(24.))
|
||||||
|
.bg(gpui::red()),
|
||||||
|
),
|
||||||
|
).child(
|
||||||
|
div().relative().neg_mx_1().rounded_full().z_index(1)
|
||||||
|
.border_2()
|
||||||
|
.border_color(player.background)
|
||||||
|
.size(px(28.))
|
||||||
|
.child(
|
||||||
|
img()
|
||||||
|
.rounded_full()
|
||||||
|
.uri("https://avatars.githubusercontent.com/u/1714999?v=4")
|
||||||
|
.size(px(24.))
|
||||||
|
.bg(gpui::red()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
.child(Story::label(cx, "Player Selections"))
|
||||||
|
.child(div().flex().flex_col().gap_px().children(
|
||||||
|
cx.theme().players().0.clone().iter_mut().map(|player| {
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.flex_none()
|
||||||
|
.rounded_sm()
|
||||||
|
.px_0p5()
|
||||||
|
.text_color(cx.theme().colors().text)
|
||||||
|
.bg(player.selection)
|
||||||
|
.child("The brown fox jumped over the lazy dog."),
|
||||||
|
)
|
||||||
|
.child(div().flex_1())
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
crates/theme2/src/story.rs
Normal file
38
crates/theme2/src/story.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
use gpui::{div, Component, Div, ParentElement, Styled, ViewContext};
|
||||||
|
|
||||||
|
use crate::ActiveTheme;
|
||||||
|
|
||||||
|
pub struct Story {}
|
||||||
|
|
||||||
|
impl Story {
|
||||||
|
pub fn container<V: 'static>(cx: &mut ViewContext<V>) -> Div<V> {
|
||||||
|
div()
|
||||||
|
.size_full()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.pt_2()
|
||||||
|
.px_4()
|
||||||
|
.font("Zed Mono")
|
||||||
|
.bg(cx.theme().colors().background)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn title<V: 'static>(cx: &mut ViewContext<V>, title: &str) -> impl Component<V> {
|
||||||
|
div()
|
||||||
|
.text_xl()
|
||||||
|
.text_color(cx.theme().colors().text)
|
||||||
|
.child(title.to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn title_for<V: 'static, T>(cx: &mut ViewContext<V>) -> impl Component<V> {
|
||||||
|
Self::title(cx, std::any::type_name::<T>())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn label<V: 'static>(cx: &mut ViewContext<V>, label: &str) -> impl Component<V> {
|
||||||
|
div()
|
||||||
|
.mt_4()
|
||||||
|
.mb_2()
|
||||||
|
.text_xs()
|
||||||
|
.text_color(cx.theme().colors().text)
|
||||||
|
.child(label.to_owned())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
mod colors;
|
mod colors;
|
||||||
mod default_colors;
|
mod default_colors;
|
||||||
mod default_theme;
|
mod default_theme;
|
||||||
|
mod players;
|
||||||
mod registry;
|
mod registry;
|
||||||
mod scale;
|
mod scale;
|
||||||
mod settings;
|
mod settings;
|
||||||
|
@ -14,6 +15,7 @@ use ::settings::Settings;
|
||||||
pub use colors::*;
|
pub use colors::*;
|
||||||
pub use default_colors::*;
|
pub use default_colors::*;
|
||||||
pub use default_theme::*;
|
pub use default_theme::*;
|
||||||
|
pub use players::*;
|
||||||
pub use registry::*;
|
pub use registry::*;
|
||||||
pub use scale::*;
|
pub use scale::*;
|
||||||
pub use settings::*;
|
pub use settings::*;
|
||||||
|
@ -120,3 +122,8 @@ pub struct DiagnosticStyle {
|
||||||
pub hint: Hsla,
|
pub hint: Hsla,
|
||||||
pub ignored: Hsla,
|
pub ignored: Hsla,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "stories")]
|
||||||
|
mod story;
|
||||||
|
#[cfg(feature = "stories")]
|
||||||
|
pub use story::*;
|
||||||
|
|
|
@ -107,7 +107,7 @@ impl LspAdapter for JsonLspAdapter {
|
||||||
&self,
|
&self,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> BoxFuture<'static, serde_json::Value> {
|
) -> BoxFuture<'static, serde_json::Value> {
|
||||||
let action_names = cx.all_action_names().collect::<Vec<_>>();
|
let action_names = gpui::all_action_names();
|
||||||
let staff_mode = cx.is_staff();
|
let staff_mode = cx.is_staff();
|
||||||
let language_names = &self.languages.language_names();
|
let language_names = &self.languages.language_names();
|
||||||
let settings_schema = cx.global::<SettingsStore>().json_schema(
|
let settings_schema = cx.global::<SettingsStore>().json_schema(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue