mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 23:31:12 +00:00
Add hover
This commit is contained in:
parent
9d365a8a57
commit
0db1cd9c28
6 changed files with 193 additions and 19 deletions
|
@ -1,17 +1,70 @@
|
|||
use roc_region::all::{LineColumnRegion, LineInfo, Region};
|
||||
use roc_region::all::{LineColumn, LineColumnRegion, LineInfo, Region};
|
||||
use tower_lsp::lsp_types::{Position, Range};
|
||||
|
||||
fn range_of_region(line_info: &LineInfo, region: Region) -> Range {
|
||||
let LineColumnRegion { start, end } = line_info.convert_region(region);
|
||||
Range {
|
||||
start: Position {
|
||||
line: start.line,
|
||||
character: start.column,
|
||||
},
|
||||
end: Position {
|
||||
line: end.line,
|
||||
character: end.column,
|
||||
},
|
||||
pub(crate) trait ToRange {
|
||||
type Feed;
|
||||
|
||||
fn to_range(&self, feed: &Self::Feed) -> Range;
|
||||
}
|
||||
|
||||
impl ToRange for Region {
|
||||
type Feed = LineInfo;
|
||||
|
||||
fn to_range(&self, line_info: &LineInfo) -> Range {
|
||||
let LineColumnRegion { start, end } = line_info.convert_region(*self);
|
||||
Range {
|
||||
start: Position {
|
||||
line: start.line,
|
||||
character: start.column,
|
||||
},
|
||||
end: Position {
|
||||
line: end.line,
|
||||
character: end.column,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait ToRegion {
|
||||
type Feed;
|
||||
|
||||
fn to_region(&self, feed: &Self::Feed) -> Region;
|
||||
}
|
||||
|
||||
impl ToRegion for Range {
|
||||
type Feed = LineInfo;
|
||||
|
||||
fn to_region(&self, line_info: &LineInfo) -> Region {
|
||||
let lc_region = LineColumnRegion {
|
||||
start: LineColumn {
|
||||
line: self.start.line,
|
||||
column: self.start.character,
|
||||
},
|
||||
end: LineColumn {
|
||||
line: self.end.line,
|
||||
column: self.end.line,
|
||||
},
|
||||
};
|
||||
|
||||
line_info.convert_line_column_region(lc_region)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait ToRocPosition {
|
||||
type Feed;
|
||||
|
||||
fn to_roc_position(&self, feed: &Self::Feed) -> roc_region::all::Position;
|
||||
}
|
||||
|
||||
impl ToRocPosition for tower_lsp::lsp_types::Position {
|
||||
type Feed = LineInfo;
|
||||
|
||||
fn to_roc_position(&self, line_info: &LineInfo) -> roc_region::all::Position {
|
||||
let lc = LineColumn {
|
||||
line: self.line,
|
||||
column: self.character,
|
||||
};
|
||||
line_info.convert_line_column(lc)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +78,7 @@ pub(crate) mod diag {
|
|||
use roc_reporting::report::{RocDocAllocator, Severity};
|
||||
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range};
|
||||
|
||||
use super::range_of_region;
|
||||
use super::ToRange;
|
||||
|
||||
pub trait IntoLspSeverity {
|
||||
fn into_lsp_severity(self) -> DiagnosticSeverity;
|
||||
|
@ -114,7 +167,7 @@ pub(crate) mod diag {
|
|||
type Feed = ProblemFmt<'a>;
|
||||
|
||||
fn into_lsp_diagnostic(self, fmt: &'a ProblemFmt<'a>) -> Option<Diagnostic> {
|
||||
let range = range_of_region(fmt.line_info, self.region());
|
||||
let range = self.region().to_range(fmt.line_info);
|
||||
|
||||
let report = roc_reporting::report::can_problem(
|
||||
&fmt.alloc,
|
||||
|
@ -146,7 +199,7 @@ pub(crate) mod diag {
|
|||
type Feed = ProblemFmt<'a>;
|
||||
|
||||
fn into_lsp_diagnostic(self, fmt: &'a ProblemFmt<'a>) -> Option<Diagnostic> {
|
||||
let range = range_of_region(fmt.line_info, self.region());
|
||||
let range = self.region().to_range(fmt.line_info);
|
||||
|
||||
let report = roc_reporting::report::type_problem(
|
||||
&fmt.alloc,
|
||||
|
|
|
@ -4,9 +4,12 @@ use bumpalo::Bump;
|
|||
use roc_load::{LoadedModule, LoadingProblem};
|
||||
use roc_region::all::LineInfo;
|
||||
use roc_reporting::report::RocDocAllocator;
|
||||
use tower_lsp::lsp_types::{Diagnostic, Url};
|
||||
use tower_lsp::lsp_types::{Diagnostic, Hover, HoverContents, MarkedString, Position, Url};
|
||||
|
||||
use crate::convert::diag::{IntoLspDiagnostic, ProblemFmt};
|
||||
use crate::convert::{
|
||||
diag::{IntoLspDiagnostic, ProblemFmt},
|
||||
ToRange, ToRocPosition,
|
||||
};
|
||||
|
||||
pub(crate) enum DocumentChange {
|
||||
Modified(Url, String),
|
||||
|
@ -21,6 +24,7 @@ struct Document {
|
|||
arena: Bump,
|
||||
|
||||
// Incrementally updated module, diagnostis, etc.
|
||||
line_info: Option<LineInfo>,
|
||||
module: Option<Result<LoadedModule, ()>>,
|
||||
diagnostics: Option<Vec<Diagnostic>>,
|
||||
}
|
||||
|
@ -32,6 +36,7 @@ impl Document {
|
|||
source,
|
||||
arena: Bump::new(),
|
||||
|
||||
line_info: None,
|
||||
module: None,
|
||||
diagnostics: None,
|
||||
}
|
||||
|
@ -43,6 +48,16 @@ impl Document {
|
|||
self.diagnostics = None;
|
||||
}
|
||||
|
||||
fn prime_line_info(&mut self) {
|
||||
if self.line_info.is_none() {
|
||||
self.line_info = Some(LineInfo::new(&self.source));
|
||||
}
|
||||
}
|
||||
|
||||
fn line_info(&self) -> &LineInfo {
|
||||
&self.line_info.as_ref().unwrap()
|
||||
}
|
||||
|
||||
fn module(&mut self) -> Result<&mut LoadedModule, LoadingProblem<'_>> {
|
||||
if let Some(Ok(module)) = &mut self.module {
|
||||
// Safety: returning for time self is alive
|
||||
|
@ -84,8 +99,11 @@ impl Document {
|
|||
|
||||
let diagnostics = match loaded {
|
||||
Ok(module) => {
|
||||
let line_info = {
|
||||
self.prime_line_info();
|
||||
self.line_info()
|
||||
};
|
||||
let lines: Vec<_> = self.source.lines().collect();
|
||||
let line_info = LineInfo::new(&self.source);
|
||||
|
||||
let alloc = RocDocAllocator::new(&lines, module.module_id, &module.interns);
|
||||
|
||||
|
@ -129,6 +147,41 @@ impl Document {
|
|||
self.diagnostics = Some(diagnostics);
|
||||
self.diagnostics.as_ref().unwrap().clone()
|
||||
}
|
||||
|
||||
fn hover(&mut self, position: Position) -> Option<Hover> {
|
||||
let line_info = {
|
||||
self.prime_line_info();
|
||||
self.line_info()
|
||||
};
|
||||
|
||||
let position = position.to_roc_position(line_info);
|
||||
|
||||
let module = match self.module() {
|
||||
Ok(module) => module,
|
||||
Err(_) => return None,
|
||||
};
|
||||
|
||||
let decls = module.declarations_by_id.get(&module.module_id).unwrap();
|
||||
let (region, var) = roc_can::traverse::find_closest_type_at(position, decls)?;
|
||||
|
||||
let subs = module.solved.inner_mut();
|
||||
let snapshot = subs.snapshot();
|
||||
let type_str = roc_types::pretty_print::name_and_print_var(
|
||||
var,
|
||||
subs,
|
||||
module.module_id,
|
||||
&module.interns,
|
||||
roc_types::pretty_print::DebugPrint::NOTHING,
|
||||
);
|
||||
subs.rollback_to(snapshot);
|
||||
|
||||
let range = region.to_range(self.line_info());
|
||||
|
||||
Some(Hover {
|
||||
contents: HoverContents::Scalar(MarkedString::String(type_str)),
|
||||
range: Some(range),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -155,4 +208,8 @@ impl Registry {
|
|||
pub fn diagnostics(&mut self, document: &Url) -> Vec<Diagnostic> {
|
||||
self.documents.get_mut(document).unwrap().diagnostics()
|
||||
}
|
||||
|
||||
pub fn hover(&mut self, document: &Url, position: Position) -> Option<Hover> {
|
||||
self.documents.get_mut(document).unwrap().hover(position)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,6 +100,20 @@ impl LanguageServer for RocLs {
|
|||
async fn shutdown(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn hover(&self, params: HoverParams) -> Result<Option<Hover>> {
|
||||
let HoverParams {
|
||||
text_document_position_params:
|
||||
TextDocumentPositionParams {
|
||||
text_document,
|
||||
position,
|
||||
},
|
||||
work_done_progress_params: _,
|
||||
} = params;
|
||||
|
||||
let hover = self.registry().hover(&text_document.uri, position);
|
||||
Ok(hover)
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue