Skip to content
Open
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
14 changes: 7 additions & 7 deletions crates/editor/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3133,16 +3133,16 @@ impl Editor {
self.cursor_offset_on_selection = set_cursor_offset_on_selection;
}

/// Returns the anchor to use as the rename target for a selection.
/// Returns the anchor to use as the target of symbol operations (rename,
/// go to definition, find references, hover, etc.) for a selection.
///
/// In selection-based modes, like vim's visual mode and helix, the rendered
/// block cursor sits one position to the left of the selection's head,
/// since the head is the exclusive end of a forward selection. Using the
/// head
/// directly would place the rename one character past the symbol, for
/// head directly would target one character past the symbol, for
/// example, trailing whitespace, so for a non-empty forward selection we
/// shift one point left to land back on the symbol under the cursor.
fn rename_target_anchor(&self, selection: &Selection<Anchor>, cx: &mut App) -> Anchor {
fn symbol_target_anchor(&self, selection: &Selection<Anchor>, cx: &mut App) -> Anchor {
let head = selection.head();

if self.cursor_offset_on_selection
Expand Down Expand Up @@ -3500,9 +3500,9 @@ impl Editor {
}

let provider = self.semantics_provider.clone()?;
let buffer = self.buffer.read(cx);
let newest_selection = self.selections.newest_anchor().clone();
let cursor_position = newest_selection.head();
let cursor_position = self.symbol_target_anchor(&newest_selection, cx);
let buffer = self.buffer.read(cx);
let (cursor_buffer, cursor_buffer_position) =
buffer.text_anchor_for_position(cursor_position, cx)?;
let (tail_buffer, tail_buffer_position) =
Expand Down Expand Up @@ -7709,7 +7709,7 @@ impl Editor {
}
let provider = self.semantics_provider.clone()?;
let selection = self.selections.newest_anchor().clone();
let cursor = self.rename_target_anchor(&selection, cx);
let cursor = self.symbol_target_anchor(&selection, cx);
let (cursor_buffer, cursor_buffer_position) =
self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
let (tail_buffer, cursor_buffer_position_end) = self
Expand Down
3 changes: 2 additions & 1 deletion crates/editor/src/hover_popover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ pub const HOVER_POPOVER_GAP: Pixels = px(10.);

/// Bindable action which uses the most recent selection head to trigger a hover
pub fn hover(editor: &mut Editor, _: &Hover, window: &mut Window, cx: &mut Context<Editor>) {
let head = editor.selections.newest_anchor().head();
let selection = editor.selections.newest_anchor().clone();
let head = editor.symbol_target_anchor(&selection, cx);
show_hover(editor, head, true, window, cx);
}

Expand Down
15 changes: 7 additions & 8 deletions crates/editor/src/navigation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1142,8 +1142,8 @@ impl Editor {
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<Task<Result<()>>> {
let selection = self.selections.newest_anchor();
let head = selection.head();
let selection = self.selections.newest_anchor().clone();
let head = self.symbol_target_anchor(&selection, cx);

let multi_buffer = self.buffer.read(cx);

Expand Down Expand Up @@ -1243,12 +1243,13 @@ impl Editor {
cx: &mut Context<Self>,
) -> Option<Task<Result<Navigated>>> {
let always_open_multibuffer = action.always_open_multibuffer;
let selection = self.selections.newest_anchor();
let selection = self.selections.newest_anchor().clone();
let target = self.symbol_target_anchor(&selection, cx);
let multi_buffer = self.buffer.read(cx);
let multi_buffer_snapshot = multi_buffer.snapshot(cx);
let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
let head = selection_offset.head();
let head = target.to_offset(&multi_buffer_snapshot);

let head_anchor = multi_buffer_snapshot.anchor_at(
head,
Expand Down Expand Up @@ -2234,10 +2235,8 @@ impl Editor {
let Some(provider) = self.semantics_provider.clone() else {
return Task::ready(Ok(Navigated::No));
};
let head = self
.selections
.newest::<MultiBufferOffset>(&self.display_snapshot(cx))
.head();
let selection = self.selections.newest_anchor().clone();
let head = self.symbol_target_anchor(&selection, cx);
let buffer = self.buffer.read(cx);
let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
return Task::ready(Ok(Navigated::No));
Expand Down
39 changes: 39 additions & 0 deletions crates/vim/src/helix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4379,4 +4379,43 @@ mod test {

cx.assert_state("const after = 2; console.log(afterˇ)", Mode::HelixNormal);
}

#[gpui::test]
async fn test_helix_go_to_definition_uses_visible_cursor_position(
cx: &mut gpui::TestAppContext,
) {
let mut cx = VimTestContext::new_typescript(cx).await;
cx.enable_helix();

cx.set_state(
"const before = 2; console.log(«beforeˇ»)",
Mode::HelixNormal,
);

let expected_position = cx.to_lsp(MultiBufferOffset(
"const before = 2; console.log(befor".len(),
));
let def_range = cx.lsp_range("const «beforeˇ» = 2; console.log(before)");
let mut definition_request = cx.set_request_handler::<lsp::request::GotoDefinition, _, _>(
move |url, params, _| async move {
assert_eq!(
params.text_document_position_params.position,
expected_position
);
Ok(Some(lsp::GotoDefinitionResponse::Scalar(lsp::Location {
uri: url,
range: def_range,
})))
},
);

cx.simulate_keystrokes("g d");
definition_request.next().await.unwrap();
cx.run_until_parked();

cx.assert_state(
"const «beforeˇ» = 2; console.log(before)",
Mode::HelixNormal,
);
}
}
Loading