Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 104 additions & 45 deletions crates/ty_ide/src/inlay_hints.rs
Original file line number Diff line number Diff line change
@@ -1,62 +1,128 @@
use std::{fmt, vec};

use crate::Db;
use ruff_db::files::File;
use ruff_db::parsed::parsed_module;
use ruff_python_ast::visitor::source_order::{self, SourceOrderVisitor, TraversalSignal};
use ruff_python_ast::{AnyNodeRef, Expr, Stmt};
use ruff_text_size::{Ranged, TextRange, TextSize};
use std::fmt;
use std::fmt::Formatter;
use ty_python_semantic::types::{Type, inlay_hint_function_argument_details};
use ty_python_semantic::{HasType, SemanticModel};

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct InlayHint<'db> {
#[derive(Debug, Clone)]
pub struct InlayHint {
pub position: TextSize,
pub content: InlayHintContent<'db>,
pub kind: InlayHintKind,
pub label: InlayHintLabel,
}

impl<'db> InlayHint<'db> {
pub const fn display(&self, db: &'db dyn Db) -> DisplayInlayHint<'_, 'db> {
self.content.display(db)
impl InlayHint {
fn variable_type(position: TextSize, ty: Type, db: &dyn Db) -> Self {
let label_parts = vec![
": ".into(),
InlayHintLabelPart::new(ty.display(db).to_string()),
];

Self {
position,
kind: InlayHintKind::Type,
label: InlayHintLabel { parts: label_parts },
}
}

fn call_argument_name(position: TextSize, name: &str) -> Self {
let label_parts = vec![InlayHintLabelPart::new(name), "=".into()];

Self {
position,
kind: InlayHintKind::CallArgumentName,
label: InlayHintLabel { parts: label_parts },
}
}

pub fn display(&self) -> InlayHintDisplay<'_> {
InlayHintDisplay { inlay_hint: self }
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum InlayHintContent<'db> {
Type(Type<'db>),
CallArgumentName(String),
#[derive(Debug, Clone)]
pub enum InlayHintKind {
Type,
CallArgumentName,
}

#[derive(Debug, Clone)]
pub struct InlayHintLabel {
parts: Vec<InlayHintLabelPart>,
}

impl<'db> InlayHintContent<'db> {
pub const fn display(&self, db: &'db dyn Db) -> DisplayInlayHint<'_, 'db> {
DisplayInlayHint { db, hint: self }
impl InlayHintLabel {
pub fn parts(&self) -> &[InlayHintLabelPart] {
&self.parts
}
}

pub struct DisplayInlayHint<'a, 'db> {
db: &'db dyn Db,
hint: &'a InlayHintContent<'db>,
pub struct InlayHintDisplay<'a> {
inlay_hint: &'a InlayHint,
}

impl fmt::Display for DisplayInlayHint<'_, '_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self.hint {
InlayHintContent::Type(ty) => {
write!(f, ": {}", ty.display(self.db))
}
InlayHintContent::CallArgumentName(name) => {
write!(f, "{name}=")
}
impl fmt::Display for InlayHintDisplay<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
for part in &self.inlay_hint.label.parts {
write!(f, "{}", part.text)?;
}
Ok(())
}
}

pub fn inlay_hints<'db>(
db: &'db dyn Db,
#[derive(Default, Debug, Clone)]
pub struct InlayHintLabelPart {
text: String,

target: Option<crate::NavigationTarget>,
}

impl InlayHintLabelPart {
pub fn new(text: impl Into<String>) -> Self {
Self {
text: text.into(),
target: None,
}
}

pub fn text(&self) -> &str {
&self.text
}

pub fn target(&self) -> Option<&crate::NavigationTarget> {
self.target.as_ref()
}
}

impl From<String> for InlayHintLabelPart {
fn from(s: String) -> Self {
Self {
text: s,
target: None,
}
}
}

impl From<&str> for InlayHintLabelPart {
fn from(s: &str) -> Self {
Self {
text: s.to_string(),
target: None,
}
}
}

pub fn inlay_hints(
db: &dyn Db,
file: File,
range: TextRange,
settings: &InlayHintSettings,
) -> Vec<InlayHint<'db>> {
) -> Vec<InlayHint> {
let mut visitor = InlayHintVisitor::new(db, file, range, settings);

let ast = parsed_module(db, file).load(db);
Expand Down Expand Up @@ -106,7 +172,7 @@ impl Default for InlayHintSettings {
struct InlayHintVisitor<'a, 'db> {
db: &'db dyn Db,
model: SemanticModel<'db>,
hints: Vec<InlayHint<'db>>,
hints: Vec<InlayHint>,
in_assignment: bool,
range: TextRange,
settings: &'a InlayHintSettings,
Expand All @@ -128,13 +194,11 @@ impl<'a, 'db> InlayHintVisitor<'a, 'db> {
if !self.settings.variable_types {
return;
}
self.hints.push(InlayHint {
position,
content: InlayHintContent::Type(ty),
});
self.hints
.push(InlayHint::variable_type(position, ty, self.db));
}

fn add_call_argument_name(&mut self, position: TextSize, name: String) {
fn add_call_argument_name(&mut self, position: TextSize, name: &str) {
if !self.settings.call_argument_names {
return;
}
Expand All @@ -143,10 +207,8 @@ impl<'a, 'db> InlayHintVisitor<'a, 'db> {
return;
}

self.hints.push(InlayHint {
position,
content: InlayHintContent::CallArgumentName(name),
});
self.hints
.push(InlayHint::call_argument_name(position, name));
}
}

Expand Down Expand Up @@ -212,10 +274,7 @@ impl SourceOrderVisitor<'_> for InlayHintVisitor<'_, '_> {

for (index, arg_or_keyword) in call.arguments.arguments_source_order().enumerate() {
if let Some(name) = argument_names.get(&index) {
self.add_call_argument_name(
arg_or_keyword.range().start(),
name.to_string(),
);
self.add_call_argument_name(arg_or_keyword.range().start(), name);
}
self.visit_expr(arg_or_keyword.value());
}
Expand Down Expand Up @@ -322,7 +381,7 @@ mod tests {

for hint in hints {
let end_position = (hint.position.to_u32() as usize) + offset;
let hint_str = format!("[{}]", hint.display(&self.db));
let hint_str = format!("[{}]", hint.display());
buf.insert_str(end_position, &hint_str);
offset += hint_str.len();
}
Expand Down
2 changes: 1 addition & 1 deletion crates/ty_ide/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub use document_symbols::{document_symbols, document_symbols_with_options};
pub use goto::{goto_declaration, goto_definition, goto_type_definition};
pub use goto_references::goto_references;
pub use hover::hover;
pub use inlay_hints::{InlayHintContent, InlayHintSettings, inlay_hints};
pub use inlay_hints::{InlayHintKind, InlayHintLabel, InlayHintSettings, inlay_hints};
pub use markup::MarkupKind;
pub use references::ReferencesMode;
pub use rename::{can_rename, rename};
Expand Down
27 changes: 20 additions & 7 deletions crates/ty_server/src/server/api/requests/inlay_hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::session::client::Client;
use lsp_types::request::InlayHintRequest;
use lsp_types::{InlayHintParams, Url};
use ruff_db::source::{line_index, source_text};
use ty_ide::{InlayHintContent, inlay_hints};
use ty_ide::{InlayHintKind, InlayHintLabel, inlay_hints};
use ty_project::ProjectDatabase;

pub(crate) struct InlayHintRequestHandler;
Expand Down Expand Up @@ -55,8 +55,8 @@ impl BackgroundDocumentRequestHandler for InlayHintRequestHandler {
position: hint
.position
.to_position(&source, &index, snapshot.encoding()),
label: lsp_types::InlayHintLabel::String(hint.display(db).to_string()),
kind: Some(inlay_hint_kind(&hint.content)),
label: inlay_hint_label(&hint.label),
kind: Some(inlay_hint_kind(&hint.kind)),
tooltip: None,
padding_left: None,
padding_right: None,
Expand All @@ -71,9 +71,22 @@ impl BackgroundDocumentRequestHandler for InlayHintRequestHandler {

impl RetriableRequestHandler for InlayHintRequestHandler {}

fn inlay_hint_kind(inlay_hint_content: &InlayHintContent) -> lsp_types::InlayHintKind {
match inlay_hint_content {
InlayHintContent::Type(_) => lsp_types::InlayHintKind::TYPE,
InlayHintContent::CallArgumentName(_) => lsp_types::InlayHintKind::PARAMETER,
fn inlay_hint_kind(inlay_hint_kind: &InlayHintKind) -> lsp_types::InlayHintKind {
match inlay_hint_kind {
InlayHintKind::Type => lsp_types::InlayHintKind::TYPE,
InlayHintKind::CallArgumentName => lsp_types::InlayHintKind::PARAMETER,
}
}

fn inlay_hint_label(inlay_hint_label: &InlayHintLabel) -> lsp_types::InlayHintLabel {
let mut label_parts = Vec::new();
for part in inlay_hint_label.parts() {
label_parts.push(lsp_types::InlayHintLabelPart {
value: part.text().into(),
location: None,
tooltip: None,
command: None,
});
}
lsp_types::InlayHintLabel::LabelParts(label_parts)
}
18 changes: 16 additions & 2 deletions crates/ty_server/tests/e2e/inlay_hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,29 @@ foo(1)
"line": 0,
"character": 1
},
"label": ": Literal[1]",
"label": [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These change because we now use InlayHintLabel::LabelParts instead of InlayHintLabel::String

{
"value": ": "
},
{
"value": "Literal[1]"
}
],
"kind": 1
},
{
"position": {
"line": 5,
"character": 4
},
"label": "a=",
"label": [
{
"value": "a"
},
{
"value": "="
}
],
"kind": 2
}
]
Expand Down
12 changes: 6 additions & 6 deletions crates/ty_wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,14 +448,14 @@ impl Workspace {
Ok(result
.into_iter()
.map(|hint| InlayHint {
markdown: hint.display(&self.db).to_string(),
markdown: hint.display().to_string(),
position: Position::from_text_size(
hint.position,
&index,
&source,
self.position_encoding,
),
kind: hint.content.into(),
kind: hint.kind.into(),
})
.collect())
}
Expand Down Expand Up @@ -985,11 +985,11 @@ pub enum InlayHintKind {
Parameter,
}

impl From<ty_ide::InlayHintContent<'_>> for InlayHintKind {
fn from(kind: ty_ide::InlayHintContent) -> Self {
impl From<ty_ide::InlayHintKind> for InlayHintKind {
fn from(kind: ty_ide::InlayHintKind) -> Self {
match kind {
ty_ide::InlayHintContent::Type(_) => Self::Type,
ty_ide::InlayHintContent::CallArgumentName(_) => Self::Parameter,
ty_ide::InlayHintKind::Type => Self::Type,
ty_ide::InlayHintKind::CallArgumentName => Self::Parameter,
}
}
}
Expand Down
Loading