input: Fix position cursor in multi-line mode. (#583)
Close #581 Ref https://github.com/zed-industries/zed/pull/23668 https://github.com/user-attachments/assets/c69d098e-d2cb-4053-b739-6c7dd666e769
This commit is contained in:
parent
852ce923ae
commit
71de5dd882
2 changed files with 60 additions and 11 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -474,7 +474,7 @@ dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"cexpr",
|
"cexpr",
|
||||||
"clang-sys",
|
"clang-sys",
|
||||||
"itertools 0.11.0",
|
"itertools 0.13.0",
|
||||||
"log",
|
"log",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|
|
||||||
|
|
@ -929,6 +929,61 @@ impl TextInput {
|
||||||
line.unwrapped_layout.len
|
line.unwrapped_layout.len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the closest index for position
|
||||||
|
///
|
||||||
|
/// Fork:
|
||||||
|
/// https://github.com/zed-industries/zed/blob/1c322c0f2daa50f46644832a6a1cdf15bcf921ea/crates/gpui/src/text_system/line_layout.rs#L272
|
||||||
|
///
|
||||||
|
/// Wait PR https://github.com/zed-industries/zed/pull/23668
|
||||||
|
pub fn closest_index_for_position(
|
||||||
|
&self,
|
||||||
|
line: &WrappedLine,
|
||||||
|
position: Point<Pixels>,
|
||||||
|
line_height: Pixels,
|
||||||
|
) -> Result<usize, usize> {
|
||||||
|
let wrapped_line_ix = (position.y / line_height) as usize;
|
||||||
|
|
||||||
|
let wrapped_line_start_index;
|
||||||
|
let wrapped_line_start_x;
|
||||||
|
if wrapped_line_ix > 0 {
|
||||||
|
let Some(line_start_boundary) = line.wrap_boundaries.get(wrapped_line_ix - 1) else {
|
||||||
|
return Err(0);
|
||||||
|
};
|
||||||
|
let run = &line.unwrapped_layout.runs[line_start_boundary.run_ix];
|
||||||
|
let glyph = &run.glyphs[line_start_boundary.glyph_ix];
|
||||||
|
wrapped_line_start_index = glyph.index;
|
||||||
|
wrapped_line_start_x = glyph.position.x;
|
||||||
|
} else {
|
||||||
|
wrapped_line_start_index = 0;
|
||||||
|
wrapped_line_start_x = Pixels::ZERO;
|
||||||
|
};
|
||||||
|
|
||||||
|
let wrapped_line_end_index;
|
||||||
|
let wrapped_line_end_x;
|
||||||
|
if wrapped_line_ix < line.wrap_boundaries.len() {
|
||||||
|
let next_wrap_boundary_ix = wrapped_line_ix;
|
||||||
|
let next_wrap_boundary = line.wrap_boundaries[next_wrap_boundary_ix];
|
||||||
|
let run = &line.unwrapped_layout.runs[next_wrap_boundary.run_ix];
|
||||||
|
let glyph = &run.glyphs[next_wrap_boundary.glyph_ix];
|
||||||
|
wrapped_line_end_index = glyph.index;
|
||||||
|
wrapped_line_end_x = glyph.position.x;
|
||||||
|
} else {
|
||||||
|
wrapped_line_end_index = line.unwrapped_layout.len;
|
||||||
|
wrapped_line_end_x = line.unwrapped_layout.width;
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut position_in_unwrapped_line = position;
|
||||||
|
position_in_unwrapped_line.x += wrapped_line_start_x;
|
||||||
|
if position_in_unwrapped_line.x < wrapped_line_start_x {
|
||||||
|
Err(wrapped_line_start_index)
|
||||||
|
} else if position_in_unwrapped_line.x >= wrapped_line_end_x {
|
||||||
|
Err(wrapped_line_end_index)
|
||||||
|
} else {
|
||||||
|
// HOTFIX
|
||||||
|
Ok(self.closest_index_for_x(&line, position_in_unwrapped_line.x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn index_for_mouse_position(&self, position: Point<Pixels>, _: &WindowContext) -> usize {
|
fn index_for_mouse_position(&self, position: Point<Pixels>, _: &WindowContext) -> usize {
|
||||||
// If the text is empty, always return 0
|
// If the text is empty, always return 0
|
||||||
if self.text.is_empty() {
|
if self.text.is_empty() {
|
||||||
|
|
@ -967,22 +1022,15 @@ impl TextInput {
|
||||||
return closest_index;
|
return closest_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
let index_result = line.index_for_position(pos, line_height);
|
let index_result = self.closest_index_for_position(line, pos, line_height);
|
||||||
if let Ok(v) = index_result {
|
if let Ok(v) = index_result {
|
||||||
// FIXME: If the line have soft wrap, only first line can get correct position (closest_index is correct).
|
index += v;
|
||||||
// The second line or more, the position is always at offset +1,
|
|
||||||
// but if we mouse down on left half or character, we expect the cursor is at offset.
|
|
||||||
// We need find a way to improve.
|
|
||||||
if pos.y > line_height / 2. {
|
|
||||||
index += v + 1;
|
|
||||||
} else {
|
|
||||||
index += closest_index;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
} else if let Ok(_) = line.index_for_position(point(px(0.), pos.y), line_height) {
|
} else if let Ok(_) = line.index_for_position(point(px(0.), pos.y), line_height) {
|
||||||
// Click in the this line but not in the text, move cursor to the end of the line.
|
// Click in the this line but not in the text, move cursor to the end of the line.
|
||||||
// The fallback index is saved in Err from `index_for_position` method.
|
// The fallback index is saved in Err from `index_for_position` method.
|
||||||
index += index_result.unwrap_err();
|
index += index_result.unwrap_err();
|
||||||
|
println!("------------------ 2");
|
||||||
break;
|
break;
|
||||||
} else if line.len() == 0 {
|
} else if line.len() == 0 {
|
||||||
// empty line
|
// empty line
|
||||||
|
|
@ -995,6 +1043,7 @@ impl TextInput {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
println!("------------------ 3 {}", line.len());
|
||||||
index += line.len();
|
index += line.len();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue