Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions crates/ui/src/input/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2127,8 +2127,25 @@ impl Element for TextElement {
cx,
);

// When the mode shows line numbers, set the mouse cursor to
// Arrow over the gutter so it does not read as the editor's
// text-insertion area.
let has_line_numbers = self.state.read(cx).mode.line_number();
if has_line_numbers {
window.set_cursor_style(
gpui::CursorStyle::Arrow,
&prepaint.fold_icon_layout.line_number_hitbox,
);
}

let line_number_hitbox = if has_line_numbers {
Some(prepaint.fold_icon_layout.line_number_hitbox.clone())
} else {
None
};
self.state.update(cx, |state, cx| {
state.last_layout = Some(prepaint.last_layout.clone());
state.line_number_hitbox = line_number_hitbox;
state.last_bounds = Some(bounds);
state.last_cursor = Some(state.cursor());
state.set_input_bounds(input_bounds, cx);
Expand Down
40 changes: 40 additions & 0 deletions crates/ui/src/input/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,12 @@ pub struct InputState {
/// The marked range is the temporary insert text on IME typing.
pub(super) ime_marked_range: Option<Selection>,
pub(super) last_layout: Option<LastLayout>,
/// The hitbox covering the line-number gutter region from the last
/// paint (Sub-epic E P4). Available whenever the mode shows line
/// numbers; consumed via [`InputState::line_number_hitbox`] so
/// downstream click routing can map mouse events back to gutter
/// rows without re-reading the layout.
pub(super) line_number_hitbox: Option<gpui::Hitbox>,
pub(super) last_cursor: Option<usize>,
/// The input container bounds
pub(super) input_bounds: Bounds<Pixels>,
Expand Down Expand Up @@ -492,6 +498,7 @@ impl InputState {
validate: None,
mode: InputMode::default(),
last_layout: None,
line_number_hitbox: None,
last_bounds: None,
last_selected_range: None,
last_cursor: None,
Expand Down Expand Up @@ -706,6 +713,39 @@ impl InputState {
self.mode.diagnostics_mut()
}

/// Hitbox covering the gutter (line-number column) from the most
/// recent paint. Provided as a primitive for consumer-side
/// click routing. Returns `None` until at least one frame has
/// painted or when the mode does not show line numbers.
#[inline]
pub fn line_number_hitbox(&self) -> Option<&gpui::Hitbox> {
self.line_number_hitbox.as_ref()
}

/// Bounds, in window coordinates, of buffer line `row` from the
/// most recent paint. Useful for placing pop-ups or hitboxes
/// against a specific line without re-reading the layout. Returns
/// `None` when `row` is outside the visible range, when the layout
/// has no entry for the row (folded), or when no paint has run yet.
pub fn visible_line_bounds(&self, row: u32) -> Option<Bounds<Pixels>> {
let layout = self.last_layout.as_ref()?;
let row = row as usize;

let mut offset_y = layout.visible_top;
for (line, &buffer_line) in layout.lines.iter().zip(layout.visible_buffer_lines.iter()) {
let height = layout.line_height * line.wrapped_lines.len() as f32;
if buffer_line == row {
let last_bounds = self.last_bounds?;
return Some(Bounds::new(
last_bounds.origin + point(px(0.), offset_y),
gpui::size(last_bounds.size.width, height),
));
}
offset_y += height;
}
None
}

/// Set placeholder
pub fn set_placeholder(
&mut self,
Expand Down
Loading