-
-
Notifications
You must be signed in to change notification settings - Fork 884
Lsp/inlay hints on pipes and functions #3290
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
549f676
5e06b1e
9ba6858
f588273
bdd704c
d02c23e
aed76cc
57fd956
14cc5d4
488f222
bc9f5ef
889670b
2e37a23
b0b7bd5
d3de0d3
99897b1
c6a4ad1
7d30794
72977e6
4376e9b
a5dac94
1aeaf02
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| use serde::Deserialize; | ||
| use std::sync::{Arc, RwLock}; | ||
|
|
||
| pub type SharedConfig = Arc<RwLock<Configuration>>; | ||
|
||
|
|
||
| #[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq)] | ||
| #[serde(default)] | ||
| #[serde(rename_all = "camelCase")] | ||
| pub struct Configuration { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is called configuration here but "user config" elsewhere. Is there a canonical name for this sort of configuration in the protocol? |
||
| pub inlay_hints: InlayHintsConfig, | ||
| } | ||
|
|
||
| #[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq)] | ||
| #[serde(default)] | ||
| #[serde(rename_all = "camelCase")] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. snake_case please, we never use camelCase There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. update: I noticed that for a better integration with vscode, it's better to use camelCase instead There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This still needs to be done. |
||
| pub struct InlayHintsConfig { | ||
| /// Whether to show type inlay hints of multiline pipelines | ||
| pub pipelines: bool, | ||
|
|
||
| /// Whether to show type inlay hints of function parameters | ||
| pub parameter_types: bool, | ||
|
||
|
|
||
| /// Whether to show type inlay hints of return types of functions | ||
| pub return_types: bool, | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,221 @@ | ||||||
| use lsp_types::{InlayHint, InlayHintKind, InlayHintLabel}; | ||||||
|
|
||||||
| use crate::{ | ||||||
| ast::{ | ||||||
| PipelineAssignmentKind, SrcSpan, TypeAst, TypedExpr, TypedModule, TypedPipelineAssignment, | ||||||
| visit::Visit, | ||||||
| }, | ||||||
| line_numbers::LineNumbers, | ||||||
| type_::{self, Type}, | ||||||
| }; | ||||||
|
|
||||||
| use super::{configuration::InlayHintsConfig, src_offset_to_lsp_position}; | ||||||
|
|
||||||
| struct InlayHintsVisitor<'a> { | ||||||
| config: InlayHintsConfig, | ||||||
| module_names: &'a type_::printer::Names, | ||||||
| current_declaration_printer: type_::printer::Printer<'a>, | ||||||
|
|
||||||
| hints: Vec<InlayHint>, | ||||||
| line_numbers: &'a LineNumbers, | ||||||
| } | ||||||
|
|
||||||
| fn default_inlay_hint(line_numbers: &LineNumbers, offset: u32, label: String) -> InlayHint { | ||||||
| let position = src_offset_to_lsp_position(offset, line_numbers); | ||||||
|
|
||||||
| InlayHint { | ||||||
| position, | ||||||
| label: InlayHintLabel::String(label), | ||||||
| kind: Some(InlayHintKind::TYPE), | ||||||
| text_edits: None, | ||||||
| tooltip: None, | ||||||
| padding_left: Some(true), | ||||||
| padding_right: None, | ||||||
| data: None, | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| impl InlayHintsVisitor<'_> { | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document these two push_*_annotation functions please. |
||||||
| pub fn push_binding_annotation( | ||||||
| &mut self, | ||||||
| type_: &Type, | ||||||
| type_annotation_ast: Option<&TypeAst>, | ||||||
| span: &SrcSpan, | ||||||
| ) { | ||||||
| if type_annotation_ast.is_some() { | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| let label = format!(": {}", self.current_declaration_printer.print_type(type_)); | ||||||
|
|
||||||
| let mut hint = default_inlay_hint(self.line_numbers, span.end, label); | ||||||
| hint.padding_left = Some(false); | ||||||
|
|
||||||
| self.hints.push(hint); | ||||||
| } | ||||||
|
|
||||||
| pub fn push_return_annotation( | ||||||
| &mut self, | ||||||
| type_: &Type, | ||||||
| type_annotation_ast: Option<&TypeAst>, | ||||||
| span: &SrcSpan, | ||||||
| ) { | ||||||
| if type_annotation_ast.is_some() { | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| let label = format!("-> {}", self.current_declaration_printer.print_type(type_)); | ||||||
|
|
||||||
| let hint = default_inlay_hint(self.line_numbers, span.end, label); | ||||||
|
|
||||||
| self.hints.push(hint); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| impl<'ast> Visit<'ast> for InlayHintsVisitor<'_> { | ||||||
| fn visit_typed_function(&mut self, fun: &'ast crate::ast::TypedFunction) { | ||||||
| // This must be reset on every statement | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be inside the loop of statements? Here it's being reset for every module function definition rather than every statement. |
||||||
| self.current_declaration_printer = type_::printer::Printer::new(self.module_names); | ||||||
|
|
||||||
| for st in &fun.body { | ||||||
ascandone marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| self.visit_typed_statement(st); | ||||||
| } | ||||||
|
|
||||||
| if self.config.parameter_types { | ||||||
| for arg in &fun.arguments { | ||||||
| self.push_binding_annotation(&arg.type_, arg.annotation.as_ref(), &arg.location); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| if self.config.return_types { | ||||||
| self.push_return_annotation( | ||||||
| &fun.return_type, | ||||||
| fun.return_annotation.as_ref(), | ||||||
| &fun.location, | ||||||
| ); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| fn visit_typed_expr_fn( | ||||||
| &mut self, | ||||||
| _location: &'ast SrcSpan, | ||||||
| type_: &'ast std::sync::Arc<Type>, | ||||||
| kind: &'ast crate::ast::FunctionLiteralKind, | ||||||
| args: &'ast [crate::ast::TypedArg], | ||||||
| body: &'ast vec1::Vec1<crate::ast::TypedStatement>, | ||||||
| return_annotation: &'ast Option<TypeAst>, | ||||||
| ) { | ||||||
| for st in body { | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| self.visit_typed_statement(st); | ||||||
| } | ||||||
|
|
||||||
| let crate::ast::FunctionLiteralKind::Anonymous { head } = kind else { | ||||||
| return; | ||||||
| }; | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document why this is please |
||||||
|
|
||||||
| if self.config.parameter_types { | ||||||
| for arg in args { | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| self.push_binding_annotation(&arg.type_, arg.annotation.as_ref(), &arg.location); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| if self.config.return_types { | ||||||
| if let Some((_args, ret_type)) = type_.fn_types() { | ||||||
|
||||||
| if let Some((_args, ret_type)) = type_.fn_types() { | |
| if let Some((_arguments, return_type)) = type_.fn_types() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Document the logic and intent in this function please 🙏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's a simple lit?
This documentation seems to be for some other part of the codebase rather than being generic to all uses of the types AST. Perhaps it belongs elsewhere, or the documentation needs to be updated.