Add hover

This commit is contained in:
Ayaz Hafiz 2022-08-20 16:24:11 -05:00
parent 9d365a8a57
commit 0db1cd9c28
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
6 changed files with 193 additions and 19 deletions

View file

@ -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,

View file

@ -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)
}
}

View file

@ -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]