Implement character index for point (#23989)
Fixes #22939 Fixes #23970 Supersedes https://github.com/zed-industries/zed/pull/23469 Release Notes: - Fixed a bug where Zed could crash with certain input sources on macOS --------- Co-authored-by: Louis Brunner <louis.brunner.fr@gmail.com> Co-authored-by: ben <ben@zed.dev>
This commit is contained in:
parent
7da60995cc
commit
cfe0932c0a
9 changed files with 221 additions and 129 deletions
|
@ -63,10 +63,10 @@ pub use editor_settings::{
|
||||||
CurrentLineHighlight, EditorSettings, ScrollBeyondLastLine, SearchSettings, ShowScrollbar,
|
CurrentLineHighlight, EditorSettings, ScrollBeyondLastLine, SearchSettings, ShowScrollbar,
|
||||||
};
|
};
|
||||||
pub use editor_settings_controls::*;
|
pub use editor_settings_controls::*;
|
||||||
use element::LineWithInvisibles;
|
|
||||||
pub use element::{
|
pub use element::{
|
||||||
CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
|
CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
|
||||||
};
|
};
|
||||||
|
use element::{LineWithInvisibles, PositionMap};
|
||||||
use futures::{future, FutureExt};
|
use futures::{future, FutureExt};
|
||||||
use fuzzy::StringMatchCandidate;
|
use fuzzy::StringMatchCandidate;
|
||||||
|
|
||||||
|
@ -715,6 +715,7 @@ pub struct Editor {
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
last_bounds: Option<Bounds<Pixels>>,
|
last_bounds: Option<Bounds<Pixels>>,
|
||||||
|
last_position_map: Option<Rc<PositionMap>>,
|
||||||
expect_bounds_change: Option<Bounds<Pixels>>,
|
expect_bounds_change: Option<Bounds<Pixels>>,
|
||||||
tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
|
tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
|
||||||
tasks_update_task: Option<Task<()>>,
|
tasks_update_task: Option<Task<()>>,
|
||||||
|
@ -1377,6 +1378,7 @@ impl Editor {
|
||||||
gutter_hovered: false,
|
gutter_hovered: false,
|
||||||
pixel_position_of_newest_cursor: None,
|
pixel_position_of_newest_cursor: None,
|
||||||
last_bounds: None,
|
last_bounds: None,
|
||||||
|
last_position_map: None,
|
||||||
expect_bounds_change: None,
|
expect_bounds_change: None,
|
||||||
gutter_dimensions: GutterDimensions::default(),
|
gutter_dimensions: GutterDimensions::default(),
|
||||||
style: None,
|
style: None,
|
||||||
|
@ -14386,7 +14388,7 @@ impl Editor {
|
||||||
.and_then(|item| item.to_any().downcast_ref::<T>())
|
.and_then(|item| item.to_any().downcast_ref::<T>())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn character_size(&self, window: &mut Window) -> gpui::Point<Pixels> {
|
fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
|
||||||
let text_layout_details = self.text_layout_details(window);
|
let text_layout_details = self.text_layout_details(window);
|
||||||
let style = &text_layout_details.editor_style;
|
let style = &text_layout_details.editor_style;
|
||||||
let font_id = window.text_system().resolve_font(&style.text.font());
|
let font_id = window.text_system().resolve_font(&style.text.font());
|
||||||
|
@ -14394,7 +14396,7 @@ impl Editor {
|
||||||
let line_height = style.text.line_height_in_pixels(window.rem_size());
|
let line_height = style.text.line_height_in_pixels(window.rem_size());
|
||||||
let em_width = window.text_system().em_width(font_id, font_size).unwrap();
|
let em_width = window.text_system().em_width(font_id, font_size).unwrap();
|
||||||
|
|
||||||
gpui::Point::new(em_width, line_height)
|
gpui::Size::new(em_width, line_height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15902,9 +15904,9 @@ impl EntityInputHandler for Editor {
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Option<gpui::Bounds<Pixels>> {
|
) -> Option<gpui::Bounds<Pixels>> {
|
||||||
let text_layout_details = self.text_layout_details(window);
|
let text_layout_details = self.text_layout_details(window);
|
||||||
let gpui::Point {
|
let gpui::Size {
|
||||||
x: em_width,
|
width: em_width,
|
||||||
y: line_height,
|
height: line_height,
|
||||||
} = self.character_size(window);
|
} = self.character_size(window);
|
||||||
|
|
||||||
let snapshot = self.snapshot(window, cx);
|
let snapshot = self.snapshot(window, cx);
|
||||||
|
@ -15922,6 +15924,24 @@ impl EntityInputHandler for Editor {
|
||||||
size: size(em_width, line_height),
|
size: size(em_width, line_height),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn character_index_for_point(
|
||||||
|
&mut self,
|
||||||
|
point: gpui::Point<Pixels>,
|
||||||
|
_window: &mut Window,
|
||||||
|
_cx: &mut Context<Self>,
|
||||||
|
) -> Option<usize> {
|
||||||
|
let position_map = self.last_position_map.as_ref()?;
|
||||||
|
if !position_map.text_hitbox.contains(&point) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let display_point = position_map.point_for_position(point).previous_valid;
|
||||||
|
let anchor = position_map
|
||||||
|
.snapshot
|
||||||
|
.display_point_to_anchor(display_point, Bias::Left);
|
||||||
|
let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
|
||||||
|
Some(utf16_offset.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait SelectionExt {
|
trait SelectionExt {
|
||||||
|
|
|
@ -503,7 +503,6 @@ impl EditorElement {
|
||||||
let position_map = layout.position_map.clone();
|
let position_map = layout.position_map.clone();
|
||||||
window.on_key_event({
|
window.on_key_event({
|
||||||
let editor = self.editor.clone();
|
let editor = self.editor.clone();
|
||||||
let text_hitbox = layout.text_hitbox.clone();
|
|
||||||
move |event: &ModifiersChangedEvent, phase, window, cx| {
|
move |event: &ModifiersChangedEvent, phase, window, cx| {
|
||||||
if phase != DispatchPhase::Bubble {
|
if phase != DispatchPhase::Bubble {
|
||||||
return;
|
return;
|
||||||
|
@ -512,7 +511,7 @@ impl EditorElement {
|
||||||
if editor.hover_state.focused(window, cx) {
|
if editor.hover_state.focused(window, cx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Self::modifiers_changed(editor, event, &position_map, &text_hitbox, window, cx)
|
Self::modifiers_changed(editor, event, &position_map, window, cx)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -522,19 +521,18 @@ impl EditorElement {
|
||||||
editor: &mut Editor,
|
editor: &mut Editor,
|
||||||
event: &ModifiersChangedEvent,
|
event: &ModifiersChangedEvent,
|
||||||
position_map: &PositionMap,
|
position_map: &PositionMap,
|
||||||
text_hitbox: &Hitbox,
|
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Editor>,
|
cx: &mut Context<Editor>,
|
||||||
) {
|
) {
|
||||||
editor.update_inline_completion_preview(&event.modifiers, window, cx);
|
editor.update_inline_completion_preview(&event.modifiers, window, cx);
|
||||||
|
|
||||||
let mouse_position = window.mouse_position();
|
let mouse_position = window.mouse_position();
|
||||||
if !text_hitbox.is_hovered(window) {
|
if !position_map.text_hitbox.is_hovered(window) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.update_hovered_link(
|
editor.update_hovered_link(
|
||||||
position_map.point_for_position(text_hitbox.bounds, mouse_position),
|
position_map.point_for_position(mouse_position),
|
||||||
&position_map.snapshot,
|
&position_map.snapshot,
|
||||||
event.modifiers,
|
event.modifiers,
|
||||||
window,
|
window,
|
||||||
|
@ -542,14 +540,11 @@ impl EditorElement {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
fn mouse_left_down(
|
fn mouse_left_down(
|
||||||
editor: &mut Editor,
|
editor: &mut Editor,
|
||||||
event: &MouseDownEvent,
|
event: &MouseDownEvent,
|
||||||
hovered_hunk: Option<Range<Anchor>>,
|
hovered_hunk: Option<Range<Anchor>>,
|
||||||
position_map: &PositionMap,
|
position_map: &PositionMap,
|
||||||
text_hitbox: &Hitbox,
|
|
||||||
gutter_hitbox: &Hitbox,
|
|
||||||
line_numbers: &HashMap<MultiBufferRow, LineNumberLayout>,
|
line_numbers: &HashMap<MultiBufferRow, LineNumberLayout>,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Editor>,
|
cx: &mut Context<Editor>,
|
||||||
|
@ -558,6 +553,8 @@ impl EditorElement {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let text_hitbox = &position_map.text_hitbox;
|
||||||
|
let gutter_hitbox = &position_map.gutter_hitbox;
|
||||||
let mut click_count = event.click_count;
|
let mut click_count = event.click_count;
|
||||||
let mut modifiers = event.modifiers;
|
let mut modifiers = event.modifiers;
|
||||||
|
|
||||||
|
@ -614,8 +611,7 @@ impl EditorElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let point_for_position =
|
let point_for_position = position_map.point_for_position(event.position);
|
||||||
position_map.point_for_position(text_hitbox.bounds, event.position);
|
|
||||||
let position = point_for_position.previous_valid;
|
let position = point_for_position.previous_valid;
|
||||||
if modifiers.shift && modifiers.alt {
|
if modifiers.shift && modifiers.alt {
|
||||||
editor.select(
|
editor.select(
|
||||||
|
@ -690,15 +686,13 @@ impl EditorElement {
|
||||||
editor: &mut Editor,
|
editor: &mut Editor,
|
||||||
event: &MouseDownEvent,
|
event: &MouseDownEvent,
|
||||||
position_map: &PositionMap,
|
position_map: &PositionMap,
|
||||||
text_hitbox: &Hitbox,
|
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Editor>,
|
cx: &mut Context<Editor>,
|
||||||
) {
|
) {
|
||||||
if !text_hitbox.is_hovered(window) {
|
if !position_map.text_hitbox.is_hovered(window) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let point_for_position =
|
let point_for_position = position_map.point_for_position(event.position);
|
||||||
position_map.point_for_position(text_hitbox.bounds, event.position);
|
|
||||||
mouse_context_menu::deploy_context_menu(
|
mouse_context_menu::deploy_context_menu(
|
||||||
editor,
|
editor,
|
||||||
Some(event.position),
|
Some(event.position),
|
||||||
|
@ -713,16 +707,14 @@ impl EditorElement {
|
||||||
editor: &mut Editor,
|
editor: &mut Editor,
|
||||||
event: &MouseDownEvent,
|
event: &MouseDownEvent,
|
||||||
position_map: &PositionMap,
|
position_map: &PositionMap,
|
||||||
text_hitbox: &Hitbox,
|
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Editor>,
|
cx: &mut Context<Editor>,
|
||||||
) {
|
) {
|
||||||
if !text_hitbox.is_hovered(window) || window.default_prevented() {
|
if !position_map.text_hitbox.is_hovered(window) || window.default_prevented() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let point_for_position =
|
let point_for_position = position_map.point_for_position(event.position);
|
||||||
position_map.point_for_position(text_hitbox.bounds, event.position);
|
|
||||||
let position = point_for_position.previous_valid;
|
let position = point_for_position.previous_valid;
|
||||||
|
|
||||||
editor.select(
|
editor.select(
|
||||||
|
@ -739,15 +731,11 @@ impl EditorElement {
|
||||||
fn mouse_up(
|
fn mouse_up(
|
||||||
editor: &mut Editor,
|
editor: &mut Editor,
|
||||||
event: &MouseUpEvent,
|
event: &MouseUpEvent,
|
||||||
#[cfg_attr(
|
|
||||||
not(any(target_os = "linux", target_os = "freebsd")),
|
|
||||||
allow(unused_variables)
|
|
||||||
)]
|
|
||||||
position_map: &PositionMap,
|
position_map: &PositionMap,
|
||||||
text_hitbox: &Hitbox,
|
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Editor>,
|
cx: &mut Context<Editor>,
|
||||||
) {
|
) {
|
||||||
|
let text_hitbox = &position_map.text_hitbox;
|
||||||
let end_selection = editor.has_pending_selection();
|
let end_selection = editor.has_pending_selection();
|
||||||
let pending_nonempty_selections = editor.has_pending_nonempty_selection();
|
let pending_nonempty_selections = editor.has_pending_nonempty_selection();
|
||||||
|
|
||||||
|
@ -767,8 +755,7 @@ impl EditorElement {
|
||||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||||
if EditorSettings::get_global(cx).middle_click_paste {
|
if EditorSettings::get_global(cx).middle_click_paste {
|
||||||
if let Some(text) = cx.read_from_primary().and_then(|item| item.text()) {
|
if let Some(text) = cx.read_from_primary().and_then(|item| item.text()) {
|
||||||
let point_for_position =
|
let point_for_position = position_map.point_for_position(event.position);
|
||||||
position_map.point_for_position(text_hitbox.bounds, event.position);
|
|
||||||
let position = point_for_position.previous_valid;
|
let position = point_for_position.previous_valid;
|
||||||
|
|
||||||
editor.select(
|
editor.select(
|
||||||
|
@ -791,10 +778,10 @@ impl EditorElement {
|
||||||
editor: &mut Editor,
|
editor: &mut Editor,
|
||||||
event: &ClickEvent,
|
event: &ClickEvent,
|
||||||
position_map: &PositionMap,
|
position_map: &PositionMap,
|
||||||
text_hitbox: &Hitbox,
|
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Editor>,
|
cx: &mut Context<Editor>,
|
||||||
) {
|
) {
|
||||||
|
let text_hitbox = &position_map.text_hitbox;
|
||||||
let pending_nonempty_selections = editor.has_pending_nonempty_selection();
|
let pending_nonempty_selections = editor.has_pending_nonempty_selection();
|
||||||
|
|
||||||
let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
|
let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
|
||||||
|
@ -804,7 +791,7 @@ impl EditorElement {
|
||||||
};
|
};
|
||||||
|
|
||||||
if !pending_nonempty_selections && multi_cursor_modifier && text_hitbox.is_hovered(window) {
|
if !pending_nonempty_selections && multi_cursor_modifier && text_hitbox.is_hovered(window) {
|
||||||
let point = position_map.point_for_position(text_hitbox.bounds, event.up.position);
|
let point = position_map.point_for_position(event.up.position);
|
||||||
editor.handle_click_hovered_link(point, event.modifiers(), window, cx);
|
editor.handle_click_hovered_link(point, event.modifiers(), window, cx);
|
||||||
|
|
||||||
cx.stop_propagation();
|
cx.stop_propagation();
|
||||||
|
@ -815,7 +802,6 @@ impl EditorElement {
|
||||||
editor: &mut Editor,
|
editor: &mut Editor,
|
||||||
event: &MouseMoveEvent,
|
event: &MouseMoveEvent,
|
||||||
position_map: &PositionMap,
|
position_map: &PositionMap,
|
||||||
text_bounds: Bounds<Pixels>,
|
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Editor>,
|
cx: &mut Context<Editor>,
|
||||||
) {
|
) {
|
||||||
|
@ -823,7 +809,8 @@ impl EditorElement {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let point_for_position = position_map.point_for_position(text_bounds, event.position);
|
let text_bounds = position_map.text_hitbox.bounds;
|
||||||
|
let point_for_position = position_map.point_for_position(event.position);
|
||||||
let mut scroll_delta = gpui::Point::<f32>::default();
|
let mut scroll_delta = gpui::Point::<f32>::default();
|
||||||
let vertical_margin = position_map.line_height.min(text_bounds.size.height / 3.0);
|
let vertical_margin = position_map.line_height.min(text_bounds.size.height / 3.0);
|
||||||
let top = text_bounds.origin.y + vertical_margin;
|
let top = text_bounds.origin.y + vertical_margin;
|
||||||
|
@ -870,19 +857,18 @@ impl EditorElement {
|
||||||
editor: &mut Editor,
|
editor: &mut Editor,
|
||||||
event: &MouseMoveEvent,
|
event: &MouseMoveEvent,
|
||||||
position_map: &PositionMap,
|
position_map: &PositionMap,
|
||||||
text_hitbox: &Hitbox,
|
|
||||||
gutter_hitbox: &Hitbox,
|
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Editor>,
|
cx: &mut Context<Editor>,
|
||||||
) {
|
) {
|
||||||
|
let text_hitbox = &position_map.text_hitbox;
|
||||||
|
let gutter_hitbox = &position_map.gutter_hitbox;
|
||||||
let modifiers = event.modifiers;
|
let modifiers = event.modifiers;
|
||||||
let gutter_hovered = gutter_hitbox.is_hovered(window);
|
let gutter_hovered = gutter_hitbox.is_hovered(window);
|
||||||
editor.set_gutter_hovered(gutter_hovered, cx);
|
editor.set_gutter_hovered(gutter_hovered, cx);
|
||||||
|
|
||||||
// Don't trigger hover popover if mouse is hovering over context menu
|
// Don't trigger hover popover if mouse is hovering over context menu
|
||||||
if text_hitbox.is_hovered(window) {
|
if text_hitbox.is_hovered(window) {
|
||||||
let point_for_position =
|
let point_for_position = position_map.point_for_position(event.position);
|
||||||
position_map.point_for_position(text_hitbox.bounds, event.position);
|
|
||||||
|
|
||||||
editor.update_hovered_link(
|
editor.update_hovered_link(
|
||||||
point_for_position,
|
point_for_position,
|
||||||
|
@ -4107,8 +4093,7 @@ impl EditorElement {
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> Vec<AnyElement> {
|
) -> Vec<AnyElement> {
|
||||||
let point_for_position =
|
let point_for_position = position_map.point_for_position(window.mouse_position());
|
||||||
position_map.point_for_position(text_hitbox.bounds, window.mouse_position());
|
|
||||||
|
|
||||||
let mut controls = vec![];
|
let mut controls = vec![];
|
||||||
|
|
||||||
|
@ -4245,7 +4230,10 @@ impl EditorElement {
|
||||||
let scroll_top = layout.position_map.snapshot.scroll_position().y;
|
let scroll_top = layout.position_map.snapshot.scroll_position().y;
|
||||||
let gutter_bg = cx.theme().colors().editor_gutter_background;
|
let gutter_bg = cx.theme().colors().editor_gutter_background;
|
||||||
window.paint_quad(fill(layout.gutter_hitbox.bounds, gutter_bg));
|
window.paint_quad(fill(layout.gutter_hitbox.bounds, gutter_bg));
|
||||||
window.paint_quad(fill(layout.text_hitbox.bounds, self.style.background));
|
window.paint_quad(fill(
|
||||||
|
layout.position_map.text_hitbox.bounds,
|
||||||
|
self.style.background,
|
||||||
|
));
|
||||||
|
|
||||||
if let EditorMode::Full = layout.mode {
|
if let EditorMode::Full = layout.mode {
|
||||||
let mut active_rows = layout.active_rows.iter().peekable();
|
let mut active_rows = layout.active_rows.iter().peekable();
|
||||||
|
@ -4270,8 +4258,8 @@ impl EditorElement {
|
||||||
end: layout.gutter_hitbox.right(),
|
end: layout.gutter_hitbox.right(),
|
||||||
}),
|
}),
|
||||||
CurrentLineHighlight::Line => Some(Range {
|
CurrentLineHighlight::Line => Some(Range {
|
||||||
start: layout.text_hitbox.bounds.left(),
|
start: layout.position_map.text_hitbox.bounds.left(),
|
||||||
end: layout.text_hitbox.bounds.right(),
|
end: layout.position_map.text_hitbox.bounds.right(),
|
||||||
}),
|
}),
|
||||||
CurrentLineHighlight::All => Some(Range {
|
CurrentLineHighlight::All => Some(Range {
|
||||||
start: layout.hitbox.left(),
|
start: layout.hitbox.left(),
|
||||||
|
@ -4345,7 +4333,7 @@ impl EditorElement {
|
||||||
layout.position_map.snapshot.scroll_position().x * layout.position_map.em_width;
|
layout.position_map.snapshot.scroll_position().x * layout.position_map.em_width;
|
||||||
|
|
||||||
for (wrap_position, active) in layout.wrap_guides.iter() {
|
for (wrap_position, active) in layout.wrap_guides.iter() {
|
||||||
let x = (layout.text_hitbox.origin.x
|
let x = (layout.position_map.text_hitbox.origin.x
|
||||||
+ *wrap_position
|
+ *wrap_position
|
||||||
+ layout.position_map.em_width / 2.)
|
+ layout.position_map.em_width / 2.)
|
||||||
- scroll_left;
|
- scroll_left;
|
||||||
|
@ -4357,7 +4345,7 @@ impl EditorElement {
|
||||||
|| scrollbar_y.as_ref().map_or(false, |sy| sy.visible)
|
|| scrollbar_y.as_ref().map_or(false, |sy| sy.visible)
|
||||||
};
|
};
|
||||||
|
|
||||||
if x < layout.text_hitbox.origin.x
|
if x < layout.position_map.text_hitbox.origin.x
|
||||||
|| (show_scrollbars && x > self.scrollbar_left(&layout.hitbox.bounds))
|
|| (show_scrollbars && x > self.scrollbar_left(&layout.hitbox.bounds))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -4370,8 +4358,8 @@ impl EditorElement {
|
||||||
};
|
};
|
||||||
window.paint_quad(fill(
|
window.paint_quad(fill(
|
||||||
Bounds {
|
Bounds {
|
||||||
origin: point(x, layout.text_hitbox.origin.y),
|
origin: point(x, layout.position_map.text_hitbox.origin.y),
|
||||||
size: size(px(1.), layout.text_hitbox.size.height),
|
size: size(px(1.), layout.position_map.text_hitbox.size.height),
|
||||||
},
|
},
|
||||||
color,
|
color,
|
||||||
));
|
));
|
||||||
|
@ -4746,7 +4734,7 @@ impl EditorElement {
|
||||||
fn paint_text(&mut self, layout: &mut EditorLayout, window: &mut Window, cx: &mut App) {
|
fn paint_text(&mut self, layout: &mut EditorLayout, window: &mut Window, cx: &mut App) {
|
||||||
window.with_content_mask(
|
window.with_content_mask(
|
||||||
Some(ContentMask {
|
Some(ContentMask {
|
||||||
bounds: layout.text_hitbox.bounds,
|
bounds: layout.position_map.text_hitbox.bounds,
|
||||||
}),
|
}),
|
||||||
|window| {
|
|window| {
|
||||||
let cursor_style = if self
|
let cursor_style = if self
|
||||||
|
@ -4760,7 +4748,7 @@ impl EditorElement {
|
||||||
} else {
|
} else {
|
||||||
CursorStyle::IBeam
|
CursorStyle::IBeam
|
||||||
};
|
};
|
||||||
window.set_cursor_style(cursor_style, &layout.text_hitbox);
|
window.set_cursor_style(cursor_style, &layout.position_map.text_hitbox);
|
||||||
|
|
||||||
let invisible_display_ranges = self.paint_highlights(layout, window);
|
let invisible_display_ranges = self.paint_highlights(layout, window);
|
||||||
self.paint_lines(&invisible_display_ranges, layout, window, cx);
|
self.paint_lines(&invisible_display_ranges, layout, window, cx);
|
||||||
|
@ -4782,7 +4770,7 @@ impl EditorElement {
|
||||||
layout: &mut EditorLayout,
|
layout: &mut EditorLayout,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
) -> SmallVec<[Range<DisplayPoint>; 32]> {
|
) -> SmallVec<[Range<DisplayPoint>; 32]> {
|
||||||
window.paint_layer(layout.text_hitbox.bounds, |window| {
|
window.paint_layer(layout.position_map.text_hitbox.bounds, |window| {
|
||||||
let mut invisible_display_ranges = SmallVec::<[Range<DisplayPoint>; 32]>::new();
|
let mut invisible_display_ranges = SmallVec::<[Range<DisplayPoint>; 32]>::new();
|
||||||
let line_end_overshoot = 0.15 * layout.position_map.line_height;
|
let line_end_overshoot = 0.15 * layout.position_map.line_height;
|
||||||
for (range, color) in &layout.highlighted_ranges {
|
for (range, color) in &layout.highlighted_ranges {
|
||||||
|
@ -4861,7 +4849,7 @@ impl EditorElement {
|
||||||
// A softer than perfect black
|
// A softer than perfect black
|
||||||
let redaction_color = gpui::rgb(0x0e1111);
|
let redaction_color = gpui::rgb(0x0e1111);
|
||||||
|
|
||||||
window.paint_layer(layout.text_hitbox.bounds, |window| {
|
window.paint_layer(layout.position_map.text_hitbox.bounds, |window| {
|
||||||
for range in layout.redacted_ranges.iter() {
|
for range in layout.redacted_ranges.iter() {
|
||||||
self.paint_highlighted_range(
|
self.paint_highlighted_range(
|
||||||
range.clone(),
|
range.clone(),
|
||||||
|
@ -5435,13 +5423,13 @@ impl EditorElement {
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
highlighted_range.paint(layout.text_hitbox.bounds, window);
|
highlighted_range.paint(layout.position_map.text_hitbox.bounds, window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_inline_blame(&mut self, layout: &mut EditorLayout, window: &mut Window, cx: &mut App) {
|
fn paint_inline_blame(&mut self, layout: &mut EditorLayout, window: &mut Window, cx: &mut App) {
|
||||||
if let Some(mut inline_blame) = layout.inline_blame.take() {
|
if let Some(mut inline_blame) = layout.inline_blame.take() {
|
||||||
window.paint_layer(layout.text_hitbox.bounds, |window| {
|
window.paint_layer(layout.position_map.text_hitbox.bounds, |window| {
|
||||||
inline_blame.paint(window, cx);
|
inline_blame.paint(window, cx);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -5560,8 +5548,6 @@ impl EditorElement {
|
||||||
window.on_mouse_event({
|
window.on_mouse_event({
|
||||||
let position_map = layout.position_map.clone();
|
let position_map = layout.position_map.clone();
|
||||||
let editor = self.editor.clone();
|
let editor = self.editor.clone();
|
||||||
let text_hitbox = layout.text_hitbox.clone();
|
|
||||||
let gutter_hitbox = layout.gutter_hitbox.clone();
|
|
||||||
let multi_buffer_range =
|
let multi_buffer_range =
|
||||||
layout
|
layout
|
||||||
.display_hunks
|
.display_hunks
|
||||||
|
@ -5600,32 +5586,16 @@ impl EditorElement {
|
||||||
event,
|
event,
|
||||||
multi_buffer_range.clone(),
|
multi_buffer_range.clone(),
|
||||||
&position_map,
|
&position_map,
|
||||||
&text_hitbox,
|
|
||||||
&gutter_hitbox,
|
|
||||||
line_numbers.as_ref(),
|
line_numbers.as_ref(),
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
MouseButton::Right => editor.update(cx, |editor, cx| {
|
MouseButton::Right => editor.update(cx, |editor, cx| {
|
||||||
Self::mouse_right_down(
|
Self::mouse_right_down(editor, event, &position_map, window, cx);
|
||||||
editor,
|
|
||||||
event,
|
|
||||||
&position_map,
|
|
||||||
&text_hitbox,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}),
|
}),
|
||||||
MouseButton::Middle => editor.update(cx, |editor, cx| {
|
MouseButton::Middle => editor.update(cx, |editor, cx| {
|
||||||
Self::mouse_middle_down(
|
Self::mouse_middle_down(editor, event, &position_map, window, cx);
|
||||||
editor,
|
|
||||||
event,
|
|
||||||
&position_map,
|
|
||||||
&text_hitbox,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}),
|
}),
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
@ -5636,12 +5606,11 @@ impl EditorElement {
|
||||||
window.on_mouse_event({
|
window.on_mouse_event({
|
||||||
let editor = self.editor.clone();
|
let editor = self.editor.clone();
|
||||||
let position_map = layout.position_map.clone();
|
let position_map = layout.position_map.clone();
|
||||||
let text_hitbox = layout.text_hitbox.clone();
|
|
||||||
|
|
||||||
move |event: &MouseUpEvent, phase, window, cx| {
|
move |event: &MouseUpEvent, phase, window, cx| {
|
||||||
if phase == DispatchPhase::Bubble {
|
if phase == DispatchPhase::Bubble {
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
Self::mouse_up(editor, event, &position_map, &text_hitbox, window, cx)
|
Self::mouse_up(editor, event, &position_map, window, cx)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5650,8 +5619,6 @@ impl EditorElement {
|
||||||
window.on_mouse_event({
|
window.on_mouse_event({
|
||||||
let editor = self.editor.clone();
|
let editor = self.editor.clone();
|
||||||
let position_map = layout.position_map.clone();
|
let position_map = layout.position_map.clone();
|
||||||
let text_hitbox = layout.text_hitbox.clone();
|
|
||||||
|
|
||||||
let mut captured_mouse_down = None;
|
let mut captured_mouse_down = None;
|
||||||
|
|
||||||
move |event: &MouseUpEvent, phase, window, cx| match phase {
|
move |event: &MouseUpEvent, phase, window, cx| match phase {
|
||||||
|
@ -5665,7 +5632,7 @@ impl EditorElement {
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
let mut pending_mouse_down = pending_mouse_down.borrow_mut();
|
let mut pending_mouse_down = pending_mouse_down.borrow_mut();
|
||||||
if pending_mouse_down.is_some() && text_hitbox.is_hovered(window) {
|
if pending_mouse_down.is_some() && position_map.text_hitbox.is_hovered(window) {
|
||||||
captured_mouse_down = pending_mouse_down.take();
|
captured_mouse_down = pending_mouse_down.take();
|
||||||
window.refresh();
|
window.refresh();
|
||||||
}
|
}
|
||||||
|
@ -5677,7 +5644,7 @@ impl EditorElement {
|
||||||
down: mouse_down,
|
down: mouse_down,
|
||||||
up: event.clone(),
|
up: event.clone(),
|
||||||
};
|
};
|
||||||
Self::click(editor, &event, &position_map, &text_hitbox, window, cx);
|
Self::click(editor, &event, &position_map, window, cx);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -5686,8 +5653,6 @@ impl EditorElement {
|
||||||
window.on_mouse_event({
|
window.on_mouse_event({
|
||||||
let position_map = layout.position_map.clone();
|
let position_map = layout.position_map.clone();
|
||||||
let editor = self.editor.clone();
|
let editor = self.editor.clone();
|
||||||
let text_hitbox = layout.text_hitbox.clone();
|
|
||||||
let gutter_hitbox = layout.gutter_hitbox.clone();
|
|
||||||
|
|
||||||
move |event: &MouseMoveEvent, phase, window, cx| {
|
move |event: &MouseMoveEvent, phase, window, cx| {
|
||||||
if phase == DispatchPhase::Bubble {
|
if phase == DispatchPhase::Bubble {
|
||||||
|
@ -5698,25 +5663,10 @@ impl EditorElement {
|
||||||
if event.pressed_button == Some(MouseButton::Left)
|
if event.pressed_button == Some(MouseButton::Left)
|
||||||
|| event.pressed_button == Some(MouseButton::Middle)
|
|| event.pressed_button == Some(MouseButton::Middle)
|
||||||
{
|
{
|
||||||
Self::mouse_dragged(
|
Self::mouse_dragged(editor, event, &position_map, window, cx)
|
||||||
editor,
|
|
||||||
event,
|
|
||||||
&position_map,
|
|
||||||
text_hitbox.bounds,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::mouse_moved(
|
Self::mouse_moved(editor, event, &position_map, window, cx)
|
||||||
editor,
|
|
||||||
event,
|
|
||||||
&position_map,
|
|
||||||
&text_hitbox,
|
|
||||||
&gutter_hitbox,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7566,6 +7516,12 @@ impl Element for EditorElement {
|
||||||
em_width,
|
em_width,
|
||||||
em_advance,
|
em_advance,
|
||||||
snapshot,
|
snapshot,
|
||||||
|
gutter_hitbox: gutter_hitbox.clone(),
|
||||||
|
text_hitbox: text_hitbox.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
|
self.editor.update(cx, |editor, _| {
|
||||||
|
editor.last_position_map = Some(position_map.clone())
|
||||||
});
|
});
|
||||||
|
|
||||||
let hunk_controls = self.layout_diff_hunk_controls(
|
let hunk_controls = self.layout_diff_hunk_controls(
|
||||||
|
@ -7589,7 +7545,6 @@ impl Element for EditorElement {
|
||||||
wrap_guides,
|
wrap_guides,
|
||||||
indent_guides,
|
indent_guides,
|
||||||
hitbox,
|
hitbox,
|
||||||
text_hitbox,
|
|
||||||
gutter_hitbox,
|
gutter_hitbox,
|
||||||
display_hunks,
|
display_hunks,
|
||||||
content_origin,
|
content_origin,
|
||||||
|
@ -7761,7 +7716,6 @@ impl IntoElement for EditorElement {
|
||||||
pub struct EditorLayout {
|
pub struct EditorLayout {
|
||||||
position_map: Rc<PositionMap>,
|
position_map: Rc<PositionMap>,
|
||||||
hitbox: Hitbox,
|
hitbox: Hitbox,
|
||||||
text_hitbox: Hitbox,
|
|
||||||
gutter_hitbox: Hitbox,
|
gutter_hitbox: Hitbox,
|
||||||
content_origin: gpui::Point<Pixels>,
|
content_origin: gpui::Point<Pixels>,
|
||||||
scrollbars_layout: AxisPair<Option<ScrollbarLayout>>,
|
scrollbars_layout: AxisPair<Option<ScrollbarLayout>>,
|
||||||
|
@ -7941,15 +7895,17 @@ struct CreaseTrailerLayout {
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PositionMap {
|
pub(crate) struct PositionMap {
|
||||||
size: Size<Pixels>,
|
pub size: Size<Pixels>,
|
||||||
line_height: Pixels,
|
pub line_height: Pixels,
|
||||||
scroll_pixel_position: gpui::Point<Pixels>,
|
pub scroll_pixel_position: gpui::Point<Pixels>,
|
||||||
scroll_max: gpui::Point<f32>,
|
pub scroll_max: gpui::Point<f32>,
|
||||||
em_width: Pixels,
|
pub em_width: Pixels,
|
||||||
em_advance: Pixels,
|
pub em_advance: Pixels,
|
||||||
line_layouts: Vec<LineWithInvisibles>,
|
pub line_layouts: Vec<LineWithInvisibles>,
|
||||||
snapshot: EditorSnapshot,
|
pub snapshot: EditorSnapshot,
|
||||||
|
pub text_hitbox: Hitbox,
|
||||||
|
pub gutter_hitbox: Hitbox,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
@ -7971,11 +7927,8 @@ impl PointForPosition {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PositionMap {
|
impl PositionMap {
|
||||||
fn point_for_position(
|
pub(crate) fn point_for_position(&self, position: gpui::Point<Pixels>) -> PointForPosition {
|
||||||
&self,
|
let text_bounds = self.text_hitbox.bounds;
|
||||||
text_bounds: Bounds<Pixels>,
|
|
||||||
position: gpui::Point<Pixels>,
|
|
||||||
) -> PointForPosition {
|
|
||||||
let scroll_position = self.snapshot.scroll_position();
|
let scroll_position = self.snapshot.scroll_position();
|
||||||
let position = position - text_bounds.origin;
|
let position = position - text_bounds.origin;
|
||||||
let y = position.y.max(px(0.)).min(self.size.height);
|
let y = position.y.max(px(0.)).min(self.size.height);
|
||||||
|
|
|
@ -229,9 +229,10 @@ pub fn deploy_context_menu(
|
||||||
cx,
|
cx,
|
||||||
),
|
),
|
||||||
None => {
|
None => {
|
||||||
|
let character_size = editor.character_size(window);
|
||||||
let menu_position = MenuPosition::PinnedToEditor {
|
let menu_position = MenuPosition::PinnedToEditor {
|
||||||
source: source_anchor,
|
source: source_anchor,
|
||||||
offset: editor.character_size(window),
|
offset: gpui::point(character_size.width, character_size.height),
|
||||||
};
|
};
|
||||||
Some(MouseContextMenu::new(
|
Some(MouseContextMenu::new(
|
||||||
menu_position,
|
menu_position,
|
||||||
|
|
|
@ -364,6 +364,20 @@ impl EntityInputHandler for TextInput {
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn character_index_for_point(
|
||||||
|
&mut self,
|
||||||
|
point: gpui::Point<Pixels>,
|
||||||
|
_window: &mut Window,
|
||||||
|
_cx: &mut Context<Self>,
|
||||||
|
) -> Option<usize> {
|
||||||
|
let line_point = self.last_bounds?.localize(&point)?;
|
||||||
|
let last_layout = self.last_layout.as_ref()?;
|
||||||
|
|
||||||
|
assert_eq!(last_layout.text, self.content);
|
||||||
|
let utf8_index = last_layout.index_for_x(point.x - line_point.x)?;
|
||||||
|
Some(self.offset_to_utf16(utf8_index))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TextElement {
|
struct TextElement {
|
||||||
|
|
|
@ -217,6 +217,19 @@ impl Point<Pixels> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Point<T>
|
||||||
|
where
|
||||||
|
T: Sub<T, Output = T> + Debug + Clone + Default,
|
||||||
|
{
|
||||||
|
/// Get the position of this point, relative to the given origin
|
||||||
|
pub fn relative_to(&self, origin: &Point<T>) -> Point<T> {
|
||||||
|
point(
|
||||||
|
self.x.clone() - origin.x.clone(),
|
||||||
|
self.y.clone() - origin.y.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T, Rhs> Mul<Rhs> for Point<T>
|
impl<T, Rhs> Mul<Rhs> for Point<T>
|
||||||
where
|
where
|
||||||
T: Mul<Rhs, Output = T> + Clone + Default + Debug,
|
T: Mul<Rhs, Output = T> + Clone + Default + Debug,
|
||||||
|
@ -376,6 +389,13 @@ pub struct Size<T: Clone + Default + Debug> {
|
||||||
pub height: T,
|
pub height: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + Default + Debug> Size<T> {
|
||||||
|
/// Create a new Size, a synonym for [`size`]
|
||||||
|
pub fn new(width: T, height: T) -> Self {
|
||||||
|
size(width, height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs a new `Size<T>` with the provided width and height.
|
/// Constructs a new `Size<T>` with the provided width and height.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
@ -1456,6 +1476,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Bounds<T>
|
||||||
|
where
|
||||||
|
T: Add<T, Output = T> + PartialOrd + Clone + Default + Debug + Sub<T, Output = T>,
|
||||||
|
{
|
||||||
|
/// Convert a point to the coordinate space defined by this Bounds
|
||||||
|
pub fn localize(&self, point: &Point<T>) -> Option<Point<T>> {
|
||||||
|
self.contains(point)
|
||||||
|
.then(|| point.relative_to(&self.origin))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks if the bounds represent an empty area.
|
/// Checks if the bounds represent an empty area.
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
|
|
|
@ -62,6 +62,14 @@ pub trait EntityInputHandler: 'static + Sized {
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Option<Bounds<Pixels>>;
|
) -> Option<Bounds<Pixels>>;
|
||||||
|
|
||||||
|
/// See [`InputHandler::character_index_for_point`] for details
|
||||||
|
fn character_index_for_point(
|
||||||
|
&mut self,
|
||||||
|
point: crate::Point<Pixels>,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> Option<usize>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The canonical implementation of [`PlatformInputHandler`]. Call [`Window::handle_input`]
|
/// The canonical implementation of [`PlatformInputHandler`]. Call [`Window::handle_input`]
|
||||||
|
@ -158,4 +166,15 @@ impl<V: EntityInputHandler> InputHandler for ElementInputHandler<V> {
|
||||||
view.bounds_for_range(range_utf16, self.element_bounds, window, cx)
|
view.bounds_for_range(range_utf16, self.element_bounds, window, cx)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn character_index_for_point(
|
||||||
|
&mut self,
|
||||||
|
point: crate::Point<Pixels>,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut App,
|
||||||
|
) -> Option<usize> {
|
||||||
|
self.view.update(cx, |view, cx| {
|
||||||
|
view.character_index_for_point(point, window, cx)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -792,6 +792,14 @@ impl PlatformInputHandler {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn character_index_for_point(&mut self, point: Point<Pixels>) -> Option<usize> {
|
||||||
|
self.cx
|
||||||
|
.update(|window, cx| self.handler.character_index_for_point(point, window, cx))
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct representing a selection in a text buffer, in UTF16 characters.
|
/// A struct representing a selection in a text buffer, in UTF16 characters.
|
||||||
|
@ -882,6 +890,16 @@ pub trait InputHandler: 'static {
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> Option<Bounds<Pixels>>;
|
) -> Option<Bounds<Pixels>>;
|
||||||
|
|
||||||
|
/// Get the character offset for the given point in terms of UTF16 characters
|
||||||
|
///
|
||||||
|
/// Corresponds to [characterIndexForPoint:](https://developer.apple.com/documentation/appkit/nstextinputclient/characterindex(for:))
|
||||||
|
fn character_index_for_point(
|
||||||
|
&mut self,
|
||||||
|
point: Point<Pixels>,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut App,
|
||||||
|
) -> Option<usize>;
|
||||||
|
|
||||||
/// Allows a given input context to opt into getting raw key repeats instead of
|
/// Allows a given input context to opt into getting raw key repeats instead of
|
||||||
/// sending these to the platform.
|
/// sending these to the platform.
|
||||||
/// TODO: Ideally we should be able to set ApplePressAndHoldEnabled in NSUserDefaults
|
/// TODO: Ideally we should be able to set ApplePressAndHoldEnabled in NSUserDefaults
|
||||||
|
|
|
@ -17,8 +17,8 @@ use cocoa::{
|
||||||
},
|
},
|
||||||
base::{id, nil},
|
base::{id, nil},
|
||||||
foundation::{
|
foundation::{
|
||||||
NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSPoint, NSRect,
|
NSArray, NSAutoreleasePool, NSDictionary, NSFastEnumeration, NSInteger, NSNotFound,
|
||||||
NSSize, NSString, NSUInteger,
|
NSPoint, NSRect, NSSize, NSString, NSUInteger,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use core_graphics::display::{CGDirectDisplayID, CGPoint, CGRect};
|
use core_graphics::display::{CGDirectDisplayID, CGPoint, CGRect};
|
||||||
|
@ -227,6 +227,11 @@ unsafe fn build_classes() {
|
||||||
accepts_first_mouse as extern "C" fn(&Object, Sel, id) -> BOOL,
|
accepts_first_mouse as extern "C" fn(&Object, Sel, id) -> BOOL,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
decl.add_method(
|
||||||
|
sel!(characterIndexForPoint:),
|
||||||
|
character_index_for_point as extern "C" fn(&Object, Sel, NSPoint) -> u64,
|
||||||
|
);
|
||||||
|
|
||||||
decl.register()
|
decl.register()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1687,17 +1692,7 @@ extern "C" fn first_rect_for_character_range(
|
||||||
range: NSRange,
|
range: NSRange,
|
||||||
_: id,
|
_: id,
|
||||||
) -> NSRect {
|
) -> NSRect {
|
||||||
let frame: NSRect = unsafe {
|
let frame = get_frame(this);
|
||||||
let state = get_window_state(this);
|
|
||||||
let lock = state.lock();
|
|
||||||
let mut frame = NSWindow::frame(lock.native_window);
|
|
||||||
let content_layout_rect: CGRect = msg_send![lock.native_window, contentLayoutRect];
|
|
||||||
let style_mask: NSWindowStyleMask = msg_send![lock.native_window, styleMask];
|
|
||||||
if !style_mask.contains(NSWindowStyleMask::NSFullSizeContentViewWindowMask) {
|
|
||||||
frame.origin.y -= frame.size.height - content_layout_rect.size.height;
|
|
||||||
}
|
|
||||||
frame
|
|
||||||
};
|
|
||||||
with_input_handler(this, |input_handler| {
|
with_input_handler(this, |input_handler| {
|
||||||
input_handler.bounds_for_range(range.to_range()?)
|
input_handler.bounds_for_range(range.to_range()?)
|
||||||
})
|
})
|
||||||
|
@ -1718,6 +1713,20 @@ extern "C" fn first_rect_for_character_range(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_frame(this: &Object) -> NSRect {
|
||||||
|
unsafe {
|
||||||
|
let state = get_window_state(this);
|
||||||
|
let lock = state.lock();
|
||||||
|
let mut frame = NSWindow::frame(lock.native_window);
|
||||||
|
let content_layout_rect: CGRect = msg_send![lock.native_window, contentLayoutRect];
|
||||||
|
let style_mask: NSWindowStyleMask = msg_send![lock.native_window, styleMask];
|
||||||
|
if !style_mask.contains(NSWindowStyleMask::NSFullSizeContentViewWindowMask) {
|
||||||
|
frame.origin.y -= frame.size.height - content_layout_rect.size.height;
|
||||||
|
}
|
||||||
|
frame
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NSRange) {
|
extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NSRange) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let is_attributed_string: BOOL =
|
let is_attributed_string: BOOL =
|
||||||
|
@ -1831,6 +1840,24 @@ extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: id) -> BOOL {
|
||||||
YES
|
YES
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" fn character_index_for_point(this: &Object, _: Sel, position: NSPoint) -> u64 {
|
||||||
|
let position = screen_point_to_gpui_point(this, position);
|
||||||
|
with_input_handler(this, |input_handler| {
|
||||||
|
input_handler.character_index_for_point(position)
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.map(|index| index as u64)
|
||||||
|
.unwrap_or(NSNotFound as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn screen_point_to_gpui_point(this: &Object, position: NSPoint) -> Point<Pixels> {
|
||||||
|
let frame = get_frame(this);
|
||||||
|
let window_x = position.x - frame.origin.x;
|
||||||
|
let window_y = frame.size.height - (position.y - frame.origin.y);
|
||||||
|
let position = point(px(window_x as f32), px(window_y as f32));
|
||||||
|
position
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" fn dragging_entered(this: &Object, _: Sel, dragging_info: id) -> NSDragOperation {
|
extern "C" fn dragging_entered(this: &Object, _: Sel, dragging_info: id) -> NSDragOperation {
|
||||||
let window_state = unsafe { get_window_state(this) };
|
let window_state = unsafe { get_window_state(this) };
|
||||||
let position = drag_event_position(&window_state, dragging_info);
|
let position = drag_event_position(&window_state, dragging_info);
|
||||||
|
|
|
@ -1073,6 +1073,15 @@ impl InputHandler for TerminalInputHandler {
|
||||||
fn apple_press_and_hold_enabled(&mut self) -> bool {
|
fn apple_press_and_hold_enabled(&mut self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn character_index_for_point(
|
||||||
|
&mut self,
|
||||||
|
_point: Point<Pixels>,
|
||||||
|
_window: &mut Window,
|
||||||
|
_cx: &mut App,
|
||||||
|
) -> Option<usize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_blank(cell: &IndexedCell) -> bool {
|
pub fn is_blank(cell: &IndexedCell) -> bool {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue