Merge pull request #8 from helix-editor/gd

Goto
This commit is contained in:
Blaž Hrastnik 2021-03-16 23:09:04 +09:00 committed by GitHub
commit 8dc0b18e35
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 215 additions and 1039 deletions

View file

@ -582,4 +582,98 @@ impl Client {
Ok(response.unwrap_or_default())
}
async fn goto_request<
T: lsp::request::Request<
Params = lsp::GotoDefinitionParams,
Result = Option<lsp::GotoDefinitionResponse>,
>,
>(
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
) -> anyhow::Result<Vec<lsp::Location>> {
let params = lsp::GotoDefinitionParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document,
position,
},
work_done_progress_params: lsp::WorkDoneProgressParams {
work_done_token: None,
},
partial_result_params: lsp::PartialResultParams {
partial_result_token: None,
},
};
let response = self.request::<T>(params).await?;
let items = match response {
Some(lsp::GotoDefinitionResponse::Scalar(location)) => vec![location],
Some(lsp::GotoDefinitionResponse::Array(locations)) => locations,
Some(lsp::GotoDefinitionResponse::Link(locations)) => locations
.into_iter()
.map(|location_link| lsp::Location {
uri: location_link.target_uri,
range: location_link.target_range,
})
.collect(),
None => Vec::new(),
};
Ok(items)
}
pub async fn goto_definition(
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
) -> anyhow::Result<Vec<lsp::Location>> {
self.goto_request::<lsp::request::GotoDefinition>(text_document, position)
.await
}
pub async fn goto_type_definition(
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
) -> anyhow::Result<Vec<lsp::Location>> {
self.goto_request::<lsp::request::GotoTypeDefinition>(text_document, position)
.await
}
pub async fn goto_implementation(
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
) -> anyhow::Result<Vec<lsp::Location>> {
self.goto_request::<lsp::request::GotoImplementation>(text_document, position)
.await
}
pub async fn goto_reference(
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
) -> anyhow::Result<Vec<lsp::Location>> {
let params = lsp::ReferenceParams {
text_document_position: lsp::TextDocumentPositionParams {
text_document,
position,
},
context: lsp::ReferenceContext {
include_declaration: true,
},
work_done_progress_params: lsp::WorkDoneProgressParams {
work_done_token: None,
},
partial_result_params: lsp::PartialResultParams {
partial_result_token: None,
},
};
let response = self.request::<lsp::request::References>(params).await?;
Ok(response.unwrap_or_default())
}
}

View file

@ -13,6 +13,8 @@ use once_cell::sync::Lazy;
use crate::compositor::Compositor;
use crate::ui::{self, Popup, Prompt, PromptEvent};
use std::path::PathBuf;
use helix_view::{
document::Mode,
view::{View, PADDING},
@ -21,6 +23,8 @@ use helix_view::{
use crossterm::event::{KeyCode, KeyEvent};
use helix_lsp::lsp;
pub struct Context<'a> {
pub count: usize,
pub editor: &'a mut Editor,
@ -846,6 +850,108 @@ pub fn exit_select_mode(cx: &mut Context) {
cx.doc().mode = Mode::Normal;
}
fn goto(cx: &mut Context, locations: Vec<lsp::Location>) {
let executor = cx.executor;
let doc = cx.doc();
doc.mode = Mode::Normal;
match locations.as_slice() {
[location] => {
cx.editor
.open(PathBuf::from(location.uri.path()), cx.executor);
let doc = cx.doc();
let definition_pos = location.range.start;
let new_pos = helix_lsp::util::lsp_pos_to_pos(doc.text().slice(..), definition_pos);
doc.set_selection(Selection::point(new_pos));
}
[] => (), // maybe show user message that no definition was found?
_locations => {
let mut picker = ui::Picker::new(
locations,
|item| {
let file = item.uri.as_str();
let line = item.range.start.line;
format!("{}:{}", file, line).into()
},
move |editor: &mut Editor, item| {
editor.open(PathBuf::from(item.uri.path()), &executor);
let mut doc = &mut editor.view_mut().doc;
let definition_pos = item.range.start;
let new_pos =
helix_lsp::util::lsp_pos_to_pos(doc.text().slice(..), definition_pos);
doc.set_selection(Selection::point(new_pos));
},
);
cx.push_layer(Box::new(picker));
}
}
}
pub fn goto_definition(cx: &mut Context) {
let doc = cx.doc();
let language_server = match doc.language_server.as_ref() {
Some(language_server) => language_server,
None => return,
};
// TODO: blocking here is not ideal
let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
// TODO: handle fails
let res =
smol::block_on(language_server.goto_definition(doc.identifier(), pos)).unwrap_or_default();
goto(cx, res);
}
pub fn goto_type_definition(cx: &mut Context) {
let doc = cx.doc();
let language_server = match doc.language_server.as_ref() {
Some(language_server) => language_server,
None => return,
};
// TODO: blocking here is not ideal
let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
// TODO: handle fails
let res = smol::block_on(language_server.goto_type_definition(doc.identifier(), pos))
.unwrap_or_default();
goto(cx, res);
}
pub fn goto_implementation(cx: &mut Context) {
let doc = cx.doc();
let language_server = match doc.language_server.as_ref() {
Some(language_server) => language_server,
None => return,
};
// TODO: blocking here is not ideal
let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
// TODO: handle fails
let res = smol::block_on(language_server.goto_implementation(doc.identifier(), pos))
.unwrap_or_default();
goto(cx, res);
}
pub fn goto_reference(cx: &mut Context) {
let doc = cx.doc();
let language_server = match doc.language_server.as_ref() {
Some(language_server) => language_server,
None => return,
};
// TODO: blocking here is not ideal
let pos = helix_lsp::util::pos_to_lsp_pos(doc.text().slice(..), doc.selection().cursor());
// TODO: handle fails
let res =
smol::block_on(language_server.goto_reference(doc.identifier(), pos)).unwrap_or_default();
goto(cx, res);
}
// NOTE: Transactions in this module get appended to history when we switch back to normal mode.
pub mod insert {
use super::*;

View file

@ -311,8 +311,12 @@ pub fn default() -> Keymaps {
code: KeyCode::Esc,
modifiers: Modifiers::NONE
} => commands::normal_mode as Command,
key!('g') => commands::move_file_start as Command,
key!('e') => commands::move_file_end as Command,
key!('g') => commands::move_file_start,
key!('e') => commands::move_file_end,
key!('d') => commands::goto_definition,
key!('t') => commands::goto_type_definition,
key!('r') => commands::goto_reference,
key!('i') => commands::goto_implementation,
),
)
}

View file

@ -1,36 +0,0 @@
pub struct TextArea {
properties: Properties,
frame: Rect,
}
impl Component for TextArea {
type Message = ();
type Properties = Properties;
fn create(properties: Self::Properties, frame: Rect, _link: ComponentLink<Self>) -> Self {
TextArea { properties, frame }
}
fn change<'a>(&'a mut self, properties: Self::Properties) -> ShouldRender {
let a: &'static str = "ase";
let q = 2u8;
let q = 2 as u16;
Some(0);
true;
self.properties = properties;
ShouldRender::Yes
}
fn resize(&mut self, frame: Rect) -> ShouldRender {
println!("hello world! \" test");
self.frame = frame;
ShouldRender::Yes
}
fn view(&self) -> Layout {
let mut canvas = Canvas::new(self.frame.size);
canvas.clear(self.properties.theme.text);
self.draw_text(&mut canvas);
canvas.into()
}
}

File diff suppressed because it is too large Load diff

View file

@ -33,7 +33,15 @@ impl Editor {
}
pub fn open(&mut self, path: PathBuf, executor: &smol::Executor) -> Result<(), Error> {
// TODO: try to find an open view/buffer first
let existing_view = self
.tree
.views()
.find(|(view, _)| view.doc.path() == Some(&path));
if let Some((view, _)) = existing_view {
self.tree.focus = view.id;
return Ok(());
}
let mut doc = Document::load(path, self.theme.scopes())?;