@@ -13,6 +13,8 @@ use once_cell::sync::Lazy;
1313use crate::compositor::Compositor;
1414use crate::ui::{self, Popup, Prompt, PromptEvent};
1515
16+use std::path::PathBuf;
17+
1618use helix_view::{
1719 document::Mode,
1820 view::{View, PADDING},
@@ -21,6 +23,8 @@ use helix_view::{
2123
2224use crossterm::event::{KeyCode, KeyEvent};
2325
26+use helix_lsp::lsp;
27+
2428pub struct Context<'a> {
2529 pub count: usize,
2630 pub editor: &'a mut Editor,
@@ -846,6 +850,108 @@ pub fn exit_select_mode(cx: &mut Context) {
846850 cx.doc().mode = Mode::Normal;
847851}
848852
853+fn goto(cx: &mut Context, locations: Vec<lsp::Location>) {
854+ let executor = cx.executor;
855+ let doc = cx.doc();
856+
857+ doc.mode = Mode::Normal;
858+
859+ match locations.as_slice() {
860+ [location] => {
861+ cx.editor
862+ .open(PathBuf::from(location.uri.path()), cx.executor);
863+ let doc = cx.doc();
864+ let definition_pos = location.range.start;
865+ let new_pos = helix_lsp::util::lsp_pos_to_pos(doc.text().slice(..), definition_pos);
866+ doc.set_selection(Selection::point(new_pos));
867+ }
868+ [] => (), // maybe show user message that no definition was found?
869+ _locations => {
870+ let mut picker = ui::Picker::new(
871+ locations,
872+ |item| {
873+ let file = item.uri.as_str();
874+ let line = item.range.start.line;
875+ format!("{}:{}", file, line).into()
876+ },
877+ move |editor: &mut Editor, item| {
878+ editor.open(PathBuf::from(item.uri.path()), &executor);
879+ let mut doc = &mut editor.view_mut().doc;
880+ let definition_pos = item.range.start;
881+ let new_pos =
882+ helix_lsp::util::lsp_pos_to_pos(doc.text().slice(..), definition_pos);
883+ doc.set_selection(Selection::point(new_pos));
884+ },
885+ );
886+ cx.push_layer(Box::new(picker));
887+ }
888+ }
889+}
890+
891+pub fn goto_definition(cx: &mut Context) {
892+ let doc = cx.doc();
893+ let language_server = match doc.language_server.as_ref() {
894+ Some(language_server) => language_server,
895+ None => return,
896+ };
897+
898+ // TODO: blocking here is not ideal
899+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
900+
901+ // TODO: handle fails
902+ let res =
903+ smol::block_on(language_server.goto_definition(doc.identifier(), pos)).unwrap_or_default();
904+ goto(cx, res);
905+}
906+
907+pub fn goto_type_definition(cx: &mut Context) {
908+ let doc = cx.doc();
909+ let language_server = match doc.language_server.as_ref() {
910+ Some(language_server) => language_server,
911+ None => return,
912+ };
913+
914+ // TODO: blocking here is not ideal
915+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
916+
917+ // TODO: handle fails
918+ let res = smol::block_on(language_server.goto_type_definition(doc.identifier(), pos))
919+ .unwrap_or_default();
920+ goto(cx, res);
921+}
922+
923+pub fn goto_implementation(cx: &mut Context) {
924+ let doc = cx.doc();
925+ let language_server = match doc.language_server.as_ref() {
926+ Some(language_server) => language_server,
927+ None => return,
928+ };
929+
930+ // TODO: blocking here is not ideal
931+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
932+
933+ // TODO: handle fails
934+ let res = smol::block_on(language_server.goto_implementation(doc.identifier(), pos))
935+ .unwrap_or_default();
936+ goto(cx, res);
937+}
938+
939+pub fn goto_reference(cx: &mut Context) {
940+ let doc = cx.doc();
941+ let language_server = match doc.language_server.as_ref() {
942+ Some(language_server) => language_server,
943+ None => return,
944+ };
945+
946+ // TODO: blocking here is not ideal
947+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
948+
949+ // TODO: handle fails
950+ let res =
951+ smol::block_on(language_server.goto_reference(doc.identifier(), pos)).unwrap_or_default();
952+ goto(cx, res);
953+}
954+
849955// NOTE: Transactions in this module get appended to history when we switch back to normal mode.
850956pub mod insert {
851957 use super::*;