Some LSP improvements regarding hovering

- Resolve module select properly
  - Add some type annotations to _some patterns_ such as assignments
This commit is contained in:
KtorZ 2023-10-19 20:04:10 +02:00
parent a08405c607
commit 41e26b216b
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
4 changed files with 91 additions and 26 deletions

View File

@ -404,8 +404,8 @@ impl TypedDefinition {
}) })
| Definition::Test(Function { body, .. }) = self | Definition::Test(Function { body, .. }) = self
{ {
if let Some(expression) = body.find_node(byte_index) { if let Some(located) = body.find_node(byte_index) {
return Some(Located::Expression(expression)); return Some(located);
} }
} }
@ -420,6 +420,7 @@ impl TypedDefinition {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Located<'a> { pub enum Located<'a> {
Expression(&'a TypedExpr), Expression(&'a TypedExpr),
Pattern(&'a TypedPattern, &'a TypedExpr),
Definition(&'a TypedDefinition), Definition(&'a TypedDefinition),
} }
@ -427,6 +428,10 @@ impl<'a> Located<'a> {
pub fn definition_location(&self) -> Option<DefinitionLocation<'_>> { pub fn definition_location(&self) -> Option<DefinitionLocation<'_>> {
match self { match self {
Self::Expression(expression) => expression.definition_location(), Self::Expression(expression) => expression.definition_location(),
// TODO: Revise definition location semantic for 'Pattern'
// e.g. for constructors, we might want to show the type definition
// for that constructor.
Self::Pattern(_, _) => None,
Self::Definition(definition) => Some(DefinitionLocation { Self::Definition(definition) => Some(DefinitionLocation {
module: None, module: None,
span: definition.location(), span: definition.location(),
@ -499,7 +504,7 @@ impl CallArg<UntypedExpr> {
} }
impl TypedCallArg { impl TypedCallArg {
pub fn find_node(&self, byte_index: usize) -> Option<&TypedExpr> { pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
self.value.find_node(byte_index) self.value.find_node(byte_index)
} }
} }
@ -918,6 +923,45 @@ impl<A, B> Pattern<A, B> {
} }
} }
impl TypedPattern {
pub fn find_node<'a>(&'a self, byte_index: usize, value: &'a TypedExpr) -> Option<Located<'a>> {
if !self.location().contains(byte_index) {
return None;
}
match self {
Pattern::Int { .. }
| Pattern::Var { .. }
| Pattern::Assign { .. }
| Pattern::Discard { .. } => Some(Located::Pattern(self, value)),
Pattern::List { elements, .. }
| Pattern::Tuple {
elems: elements, ..
} => elements
.iter()
.find_map(|e| e.find_node(byte_index, value))
.or(Some(Located::Pattern(self, value))),
Pattern::Constructor { arguments, .. } => arguments
.iter()
.find_map(|e| e.value.find_node(byte_index, value))
.or(Some(Located::Pattern(self, value))),
}
}
pub fn tipo(&self, value: &TypedExpr) -> Option<Rc<Type>> {
match self {
Pattern::Int { .. } => Some(builtins::int()),
Pattern::Constructor { tipo, .. } => Some(tipo.clone()),
Pattern::Var { .. } | Pattern::Assign { .. } | Pattern::Discard { .. } => {
Some(value.tipo())
}
Pattern::List { .. } | Pattern::Tuple { .. } => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Copy)] #[derive(Debug, Clone, PartialEq, Eq, Copy)]
pub enum ByteArrayFormatPreference { pub enum ByteArrayFormatPreference {
HexadecimalString, HexadecimalString,
@ -977,7 +1021,7 @@ impl TypedClause {
} }
} }
pub fn find_node(&self, byte_index: usize) -> Option<&TypedExpr> { pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
self.then.find_node(byte_index) self.then.find_node(byte_index)
} }
} }
@ -1119,7 +1163,7 @@ pub struct TypedRecordUpdateArg {
} }
impl TypedRecordUpdateArg { impl TypedRecordUpdateArg {
pub fn find_node(&self, byte_index: usize) -> Option<&TypedExpr> { pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
self.value.find_node(byte_index) self.value.find_node(byte_index)
} }
} }

View File

@ -5,7 +5,7 @@ use vec1::Vec1;
use crate::{ use crate::{
ast::{ ast::{
self, Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg, self, Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg,
DefinitionLocation, IfBranch, LogicalOpChainKind, ParsedCallArg, Pattern, DefinitionLocation, IfBranch, Located, LogicalOpChainKind, ParsedCallArg, Pattern,
RecordUpdateSpread, Span, TraceKind, TypedClause, TypedRecordUpdateArg, UnOp, RecordUpdateSpread, Span, TraceKind, TypedClause, TypedRecordUpdateArg, UnOp,
UntypedClause, UntypedRecordUpdateArg, UntypedClause, UntypedRecordUpdateArg,
}, },
@ -312,7 +312,7 @@ impl TypedExpr {
// This could be optimised in places to exit early if the first of a series // This could be optimised in places to exit early if the first of a series
// of expressions is after the byte index. // of expressions is after the byte index.
pub fn find_node(&self, byte_index: usize) -> Option<&Self> { pub fn find_node(&self, byte_index: usize) -> Option<Located<'_>> {
if !self.location().contains(byte_index) { if !self.location().contains(byte_index) {
return None; return None;
} }
@ -323,18 +323,20 @@ impl TypedExpr {
| TypedExpr::UInt { .. } | TypedExpr::UInt { .. }
| TypedExpr::String { .. } | TypedExpr::String { .. }
| TypedExpr::ByteArray { .. } | TypedExpr::ByteArray { .. }
| TypedExpr::ModuleSelect { .. } => Some(self), | TypedExpr::ModuleSelect { .. } => Some(Located::Expression(self)),
TypedExpr::Trace { text, then, .. } => text TypedExpr::Trace { text, then, .. } => text
.find_node(byte_index) .find_node(byte_index)
.or_else(|| then.find_node(byte_index)) .or_else(|| then.find_node(byte_index))
.or(Some(self)), .or(Some(Located::Expression(self))),
TypedExpr::Pipeline { expressions, .. } | TypedExpr::Sequence { expressions, .. } => { TypedExpr::Pipeline { expressions, .. } | TypedExpr::Sequence { expressions, .. } => {
expressions.iter().find_map(|e| e.find_node(byte_index)) expressions.iter().find_map(|e| e.find_node(byte_index))
} }
TypedExpr::Fn { body, .. } => body.find_node(byte_index).or(Some(self)), TypedExpr::Fn { body, .. } => body
.find_node(byte_index)
.or(Some(Located::Expression(self))),
TypedExpr::Tuple { TypedExpr::Tuple {
elems: elements, .. elems: elements, ..
@ -342,19 +344,21 @@ impl TypedExpr {
| TypedExpr::List { elements, .. } => elements | TypedExpr::List { elements, .. } => elements
.iter() .iter()
.find_map(|e| e.find_node(byte_index)) .find_map(|e| e.find_node(byte_index))
.or(Some(self)), .or(Some(Located::Expression(self))),
TypedExpr::Call { fun, args, .. } => args TypedExpr::Call { fun, args, .. } => args
.iter() .iter()
.find_map(|arg| arg.find_node(byte_index)) .find_map(|arg| arg.find_node(byte_index))
.or_else(|| fun.find_node(byte_index)) .or_else(|| fun.find_node(byte_index))
.or(Some(self)), .or(Some(Located::Expression(self))),
TypedExpr::BinOp { left, right, .. } => left TypedExpr::BinOp { left, right, .. } => left
.find_node(byte_index) .find_node(byte_index)
.or_else(|| right.find_node(byte_index)), .or_else(|| right.find_node(byte_index)),
TypedExpr::Assignment { value, .. } => value.find_node(byte_index), TypedExpr::Assignment { value, pattern, .. } => pattern
.find_node(byte_index, value)
.or_else(|| value.find_node(byte_index)),
TypedExpr::When { TypedExpr::When {
subject, clauses, .. subject, clauses, ..
@ -365,20 +369,22 @@ impl TypedExpr {
.iter() .iter()
.find_map(|clause| clause.find_node(byte_index)) .find_map(|clause| clause.find_node(byte_index))
}) })
.or(Some(self)), .or(Some(Located::Expression(self))),
TypedExpr::RecordAccess { TypedExpr::RecordAccess {
record: expression, .. record: expression, ..
} }
| TypedExpr::TupleIndex { | TypedExpr::TupleIndex {
tuple: expression, .. tuple: expression, ..
} => expression.find_node(byte_index).or(Some(self)), } => expression
.find_node(byte_index)
.or(Some(Located::Expression(self))),
TypedExpr::RecordUpdate { spread, args, .. } => args TypedExpr::RecordUpdate { spread, args, .. } => args
.iter() .iter()
.find_map(|arg| arg.find_node(byte_index)) .find_map(|arg| arg.find_node(byte_index))
.or_else(|| spread.find_node(byte_index)) .or_else(|| spread.find_node(byte_index))
.or(Some(self)), .or(Some(Located::Expression(self))),
TypedExpr::If { TypedExpr::If {
branches, branches,
@ -393,9 +399,11 @@ impl TypedExpr {
.or_else(|| branch.body.find_node(byte_index)) .or_else(|| branch.body.find_node(byte_index))
}) })
.or_else(|| final_else.find_node(byte_index)) .or_else(|| final_else.find_node(byte_index))
.or(Some(self)), .or(Some(Located::Expression(self))),
TypedExpr::UnOp { value, .. } => value.find_node(byte_index).or(Some(self)), TypedExpr::UnOp { value, .. } => value
.find_node(byte_index)
.or(Some(Located::Expression(self))),
} }
} }
} }

View File

@ -582,6 +582,9 @@ impl ValueConstructor {
ValueConstructorVariant::Record { ValueConstructorVariant::Record {
module, location, .. module, location, ..
} }
| ValueConstructorVariant::ModuleFn {
module, location, ..
}
| ValueConstructorVariant::ModuleConstant { | ValueConstructorVariant::ModuleConstant {
location, module, .. location, module, ..
} => DefinitionLocation { } => DefinitionLocation {
@ -589,8 +592,7 @@ impl ValueConstructor {
span: *location, span: *location,
}, },
ValueConstructorVariant::ModuleFn { location, .. } ValueConstructorVariant::LocalVariable { location } => DefinitionLocation {
| ValueConstructorVariant::LocalVariable { location } => DefinitionLocation {
module: None, module: None,
span: *location, span: *location,
}, },

View File

@ -344,6 +344,9 @@ impl Server {
self.completion_for_import() self.completion_for_import()
} }
// TODO: autocompletion for patterns
Some(Located::Pattern(_pattern, _value)) => None,
// TODO: autocompletion for other definitions // TODO: autocompletion for other definitions
Some(Located::Definition(_expression)) => None, Some(Located::Definition(_expression)) => None,
@ -458,13 +461,17 @@ impl Server {
None => return Ok(None), None => return Ok(None),
}; };
let expression = match found { let (location, definition_location, tipo) = match found {
Located::Expression(expression) => expression, Located::Expression(expression) => (
expression.location(),
expression.definition_location(),
Some(expression.tipo()),
),
Located::Pattern(pattern, value) => (pattern.location(), None, pattern.tipo(value)),
Located::Definition(_) => return Ok(None), Located::Definition(_) => return Ok(None),
}; };
let doc = expression let doc = definition_location
.definition_location()
.and_then(|loc| loc.module.map(|m| (m, loc.span))) .and_then(|loc| loc.module.map(|m| (m, loc.span)))
.and_then(|(m, span)| { .and_then(|(m, span)| {
self.compiler self.compiler
@ -475,12 +482,16 @@ impl Server {
.and_then(|(checked_module, span)| checked_module.ast.find_node(span.start)) .and_then(|(checked_module, span)| checked_module.ast.find_node(span.start))
.and_then(|node| match node { .and_then(|node| match node {
Located::Expression(_) => None, Located::Expression(_) => None,
Located::Pattern(_, _) => None,
Located::Definition(def) => def.doc(), Located::Definition(def) => def.doc(),
}) })
.unwrap_or_default(); .unwrap_or_default();
// Show the type of the hovered node to the user // Show the type of the hovered node to the user
let type_ = Printer::new().pretty_print(expression.tipo().as_ref(), 0); let type_ = match tipo {
Some(t) => Printer::new().pretty_print(t.as_ref(), 0),
None => "?".to_string(),
};
let contents = formatdoc! {r#" let contents = formatdoc! {r#"
```aiken ```aiken
@ -491,7 +502,7 @@ impl Server {
Ok(Some(lsp_types::Hover { Ok(Some(lsp_types::Hover {
contents: lsp_types::HoverContents::Scalar(lsp_types::MarkedString::String(contents)), contents: lsp_types::HoverContents::Scalar(lsp_types::MarkedString::String(contents)),
range: Some(span_to_lsp_range(expression.location(), &line_numbers)), range: Some(span_to_lsp_range(location, &line_numbers)),
})) }))
} }