commit
8dc0b18e35
6 changed files with 215 additions and 1039 deletions
|
@ -582,4 +582,98 @@ impl Client {
|
||||||
|
|
||||||
Ok(response.unwrap_or_default())
|
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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ use once_cell::sync::Lazy;
|
||||||
use crate::compositor::Compositor;
|
use crate::compositor::Compositor;
|
||||||
use crate::ui::{self, Popup, Prompt, PromptEvent};
|
use crate::ui::{self, Popup, Prompt, PromptEvent};
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use helix_view::{
|
use helix_view::{
|
||||||
document::Mode,
|
document::Mode,
|
||||||
view::{View, PADDING},
|
view::{View, PADDING},
|
||||||
|
@ -21,6 +23,8 @@ use helix_view::{
|
||||||
|
|
||||||
use crossterm::event::{KeyCode, KeyEvent};
|
use crossterm::event::{KeyCode, KeyEvent};
|
||||||
|
|
||||||
|
use helix_lsp::lsp;
|
||||||
|
|
||||||
pub struct Context<'a> {
|
pub struct Context<'a> {
|
||||||
pub count: usize,
|
pub count: usize,
|
||||||
pub editor: &'a mut Editor,
|
pub editor: &'a mut Editor,
|
||||||
|
@ -846,6 +850,108 @@ pub fn exit_select_mode(cx: &mut Context) {
|
||||||
cx.doc().mode = Mode::Normal;
|
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.
|
// NOTE: Transactions in this module get appended to history when we switch back to normal mode.
|
||||||
pub mod insert {
|
pub mod insert {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -311,8 +311,12 @@ pub fn default() -> Keymaps {
|
||||||
code: KeyCode::Esc,
|
code: KeyCode::Esc,
|
||||||
modifiers: Modifiers::NONE
|
modifiers: Modifiers::NONE
|
||||||
} => commands::normal_mode as Command,
|
} => commands::normal_mode as Command,
|
||||||
key!('g') => commands::move_file_start as Command,
|
key!('g') => commands::move_file_start,
|
||||||
key!('e') => commands::move_file_end as Command,
|
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,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
1000
helix-term/test.txt
1000
helix-term/test.txt
File diff suppressed because it is too large
Load diff
|
@ -33,7 +33,15 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(&mut self, path: PathBuf, executor: &smol::Executor) -> Result<(), Error> {
|
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())?;
|
let mut doc = Document::load(path, self.theme.scopes())?;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue