From 43638fb0c17f6d4adbe2f3a3d23789a10aa921ab Mon Sep 17 00:00:00 2001 From: jnyfah Date: Wed, 18 Jun 2025 02:25:33 +0100 Subject: [PATCH 1/5] format function --- crates/ide/src/inlay_hints/adjustment.rs | 111 ++++++++++++++------ crates/ide/src/inlay_hints/closing_brace.rs | 102 ++++++++++++++++-- 2 files changed, 169 insertions(+), 44 deletions(-) diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index f2844a2eaa61..e3743daec496 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -109,50 +109,90 @@ pub(super) fn hints( } has_adjustments = true; - // FIXME: Add some nicer tooltips to each of these - let (text, coercion) = match kind { + let (text, coercion, detailed_tooltip) = match kind { Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => { allow_edit = false; - ("", "never to any") - } - Adjust::Deref(None) => ("*", "dereference"), - Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => { - ("*", "`Deref` dereference") - } - Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => { - ("*", "`DerefMut` dereference") - } - Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => ("&", "borrow"), - Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => ("&mut ", "unique borrow"), - Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => { - ("&raw const ", "const pointer borrow") - } - Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => { - ("&raw mut ", "mut pointer borrow") + ( + "", + "never to any", + "Coerces the never type `!` into any other type. This happens in code paths that never return, like after `panic!()` or `return`.", + ) } + Adjust::Deref(None) => ( + "*", + "dereference", + "Built-in dereference of a reference to access the underlying value. The compiler inserts `*` to get the value from `&T`.", + ), + Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => ( + "*", + "`Deref` dereference", + "Dereference via the `Deref` trait. Used for types like `Box` or `Rc` so they act like plain `T`.", + ), + Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => ( + "*", + "`DerefMut` dereference", + "Mutable dereference using the `DerefMut` trait. Enables smart pointers to give mutable access to their inner values.", + ), + Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => ( + "&", + "shared borrow", + "Inserts `&` to create a shared reference. Lets you use a value without moving or cloning it.", + ), + Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => ( + "&mut ", + "mutable borrow", + "Inserts `&mut` to create a unique, mutable reference. Lets you modify a value without taking ownership.", + ), + Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => ( + "&raw const ", + "const raw pointer", + "Converts a reference to a raw const pointer `*const T`. Often used when working with FFI or unsafe code.", + ), + Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => ( + "&raw mut ", + "mut raw pointer", + "Converts a mutable reference to a raw mutable pointer `*mut T`. Allows mutation in unsafe contexts.", + ), // some of these could be represented via `as` casts, but that's not too nice and // handling everything as a prefix expr makes the `(` and `)` insertion easier Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => { allow_edit = false; match cast { - PointerCast::ReifyFnPointer => { - ("", "fn item to fn pointer") - } + PointerCast::ReifyFnPointer => ( + "", + "fn item to fn pointer", + "Converts a named function to a function pointer `fn()`. Useful when passing functions as values." + ), PointerCast::UnsafeFnPointer => ( "", "safe fn pointer to unsafe fn pointer", + "Coerces a safe function pointer to an unsafe one. Allows calling it in an unsafe context." + ), + PointerCast::ClosureFnPointer(Safety::Unsafe) => ( + "", + "closure to unsafe fn pointer", + "Converts a non-capturing closure to an unsafe function pointer. Required for use in `extern` or unsafe APIs." + ), + PointerCast::ClosureFnPointer(Safety::Safe) => ( + "", + "closure to fn pointer", + "Converts a non-capturing closure to a function pointer. Lets closures behave like plain functions." + ), + PointerCast::MutToConstPointer => ( + "", + "mut ptr to const ptr", + "Coerces `*mut T` to `*const T`. Safe because const pointers restrict what you can do." + ), + PointerCast::ArrayToPointer => ( + "", + "array to pointer", + "Converts an array to a pointer to its first element. Similar to how arrays decay to pointers in C." + ), + PointerCast::Unsize => ( + "", + "unsize coercion", + "Converts a sized type to an unsized one. Used for things like turning arrays into slices or concrete types into trait objects." ), - PointerCast::ClosureFnPointer(Safety::Unsafe) => { - ("", "closure to unsafe fn pointer") - } - PointerCast::ClosureFnPointer(Safety::Safe) => { - ("", "closure to fn pointer") - } - PointerCast::MutToConstPointer => { - ("", "mut ptr to const ptr") - } - PointerCast::ArrayToPointer => ("", ""), - PointerCast::Unsize => ("", "unsize"), } } _ => continue, @@ -162,9 +202,12 @@ pub(super) fn hints( linked_location: None, tooltip: Some(config.lazy_tooltip(|| { InlayTooltip::Markdown(format!( - "`{}` → `{}` ({coercion} coercion)", + "`{}` → `{}`\n\n**{}**\n\n{}", source.display(sema.db, display_target), target.display(sema.db, display_target), + coercion.chars().next().unwrap().to_uppercase().collect::() + + &coercion[1..], + detailed_tooltip )) })), }; @@ -175,7 +218,7 @@ pub(super) fn hints( } if !postfix && needs_inner_parens { - pre.label.append_str("("); + (&mut pre.label).append_str("("); } if needs_outer_parens || (!postfix && needs_inner_parens) { post.label.append_str(")"); diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs index ca3a982760f1..b2ee254701ff 100644 --- a/crates/ide/src/inlay_hints/closing_brace.rs +++ b/crates/ide/src/inlay_hints/closing_brace.rs @@ -91,9 +91,9 @@ pub(super) fn hints( match_ast! { match parent { ast::Fn(it) => { - // FIXME: this could include parameters, but `HirDisplay` prints too much info - // and doesn't respect the max length either, so the hints end up way too long - (format!("fn {}", it.name()?), it.name().map(name)) + let hint_text = format_function_hint(&it, config.max_length?) + .unwrap_or_else(|| format!("fn {}", it.name().map(|n| n.to_string()).unwrap_or_default())); + (hint_text, it.name().map(name)) }, ast::Static(it) => (format!("static {}", it.name()?), it.name().map(name)), ast::Const(it) => { @@ -156,6 +156,47 @@ pub(super) fn hints( None } +fn format_function_hint(func: &ast::Fn, max_length: usize) -> Option { + let name = func.name()?; + let name_str = name.to_string(); + + let params = if let Some(param_list) = func.param_list() { + let mut param_parts = Vec::new(); + let mut total_len = 0; + let max_param_len = max_length.saturating_sub(name_str.len() + 4); + + for param in param_list.params() { + let param_text = if let Some(pat) = param.pat() { + if let Some(ty) = param.ty() { format!("{}: {}", pat, ty) } else { pat.to_string() } + } else if let Some(ty) = param.ty() { + format!("_: {}", ty) + } else { + let param_source = param.syntax().text().to_string(); + if param_source.trim() == "..." { "...".to_string() } else { "_".to_string() } + }; + + let param_len = param_text.len() + if param_parts.is_empty() { 0 } else { 2 }; + if total_len + param_len > max_param_len { + param_parts.push("...".to_string()); + break; + } + + total_len += param_len; + param_parts.push(param_text); + } + + if param_parts.is_empty() { + "()".to_string() + } else { + format!("({})", param_parts.join(", ")) + } + } else { + "()".to_string() + }; + + Some(format!("fn {}{}", name_str, params)) +} + #[cfg(test)] mod tests { use crate::{ @@ -166,7 +207,11 @@ mod tests { #[test] fn hints_closing_brace() { check_with_config( - InlayHintsConfig { closing_brace_hints_min_lines: Some(2), ..DISABLED_CONFIG }, + InlayHintsConfig { + closing_brace_hints_min_lines: Some(2), + max_length: Some(30), + ..DISABLED_CONFIG + }, r#" fn a() {} @@ -175,17 +220,17 @@ fn f() { fn g() { } -//^ fn g +//^ fn g() fn h(with: T, arguments: u8, ...) { } -//^ fn h +//^ fn h(with: T, arguments: u8, ...) trait Tr { fn f(); fn g() { } - //^ fn g + //^ fn g() } //^ trait Tr impl Tr for () { @@ -222,7 +267,7 @@ fn f() { let v = vec![ ]; } -//^ fn f +//^ fn f() "#, ); } @@ -230,7 +275,11 @@ fn f() { #[test] fn hints_closing_brace_for_block_expr() { check_with_config( - InlayHintsConfig { closing_brace_hints_min_lines: Some(2), ..DISABLED_CONFIG }, + InlayHintsConfig { + closing_brace_hints_min_lines: Some(2), + max_length: Some(10), + ..DISABLED_CONFIG + }, r#" fn test() { 'end: { @@ -258,7 +307,40 @@ fn test() { //^ 'a } -//^ fn test +//^ fn test() +"#, + ); + } + + #[test] + fn hints_closing_brace_function_parameters() { + check_with_config( + InlayHintsConfig { + closing_brace_hints_min_lines: Some(1), + max_length: Some(50), + ..DISABLED_CONFIG + }, + r#" +fn simple() { + let v = vec![ + ]; + } +//^ fn simple() + +fn with_params(x: i32, y: String) { + + } +//^ fn with_params(x: i32, y: String) + +fn long_params(very_long_parameter_name: ComplexType, another: AnotherType) { + + } +//^ fn long_params(...) + +fn many_params(a: i32, b: i32, c: i32, d: i32, e: i32) { + + } +//^ fn many_params(a: i32, b: i32, c: i32, d: i32, ...) "#, ); } From e417ae2b710b49582112896785b9177de5f64b13 Mon Sep 17 00:00:00 2001 From: jnyfah Date: Wed, 18 Jun 2025 02:46:46 +0100 Subject: [PATCH 2/5] fix format --- crates/ide/src/inlay_hints/adjustment.rs | 14 +++++++------- crates/ide/src/inlay_hints/closing_brace.rs | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index e3743daec496..f5960c12568e 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -161,37 +161,37 @@ pub(super) fn hints( PointerCast::ReifyFnPointer => ( "", "fn item to fn pointer", - "Converts a named function to a function pointer `fn()`. Useful when passing functions as values." + "Converts a named function to a function pointer `fn()`. Useful when passing functions as values.", ), PointerCast::UnsafeFnPointer => ( "", "safe fn pointer to unsafe fn pointer", - "Coerces a safe function pointer to an unsafe one. Allows calling it in an unsafe context." + "Coerces a safe function pointer to an unsafe one. Allows calling it in an unsafe context.", ), PointerCast::ClosureFnPointer(Safety::Unsafe) => ( "", "closure to unsafe fn pointer", - "Converts a non-capturing closure to an unsafe function pointer. Required for use in `extern` or unsafe APIs." + "Converts a non-capturing closure to an unsafe function pointer. Required for use in `extern` or unsafe APIs.", ), PointerCast::ClosureFnPointer(Safety::Safe) => ( "", "closure to fn pointer", - "Converts a non-capturing closure to a function pointer. Lets closures behave like plain functions." + "Converts a non-capturing closure to a function pointer. Lets closures behave like plain functions.", ), PointerCast::MutToConstPointer => ( "", "mut ptr to const ptr", - "Coerces `*mut T` to `*const T`. Safe because const pointers restrict what you can do." + "Coerces `*mut T` to `*const T`. Safe because const pointers restrict what you can do.", ), PointerCast::ArrayToPointer => ( "", "array to pointer", - "Converts an array to a pointer to its first element. Similar to how arrays decay to pointers in C." + "Converts an array to a pointer to its first element. Similar to how arrays decay to pointers in C.", ), PointerCast::Unsize => ( "", "unsize coercion", - "Converts a sized type to an unsized one. Used for things like turning arrays into slices or concrete types into trait objects." + "Converts a sized type to an unsized one. Used for things like turning arrays into slices or concrete types into trait objects.", ), } } diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs index b2ee254701ff..4d7650f9e130 100644 --- a/crates/ide/src/inlay_hints/closing_brace.rs +++ b/crates/ide/src/inlay_hints/closing_brace.rs @@ -172,12 +172,12 @@ fn format_function_hint(func: &ast::Fn, max_length: usize) -> Option { format!("_: {}", ty) } else { let param_source = param.syntax().text().to_string(); - if param_source.trim() == "..." { "...".to_string() } else { "_".to_string() } + if param_source.trim() == "..." { "...".to_owned() } else { "_".to_owned() } }; let param_len = param_text.len() + if param_parts.is_empty() { 0 } else { 2 }; if total_len + param_len > max_param_len { - param_parts.push("...".to_string()); + param_parts.push("...".to_owned()); break; } @@ -186,12 +186,12 @@ fn format_function_hint(func: &ast::Fn, max_length: usize) -> Option { } if param_parts.is_empty() { - "()".to_string() + "()".to_owned() } else { format!("({})", param_parts.join(", ")) } } else { - "()".to_string() + "()".to_owned() }; Some(format!("fn {}{}", name_str, params)) From 8818e0140d370985025f97c151a9d7c2dab4f17a Mon Sep 17 00:00:00 2001 From: jnyfah Date: Wed, 18 Jun 2025 02:57:53 +0100 Subject: [PATCH 3/5] undo --- crates/ide/src/inlay_hints/adjustment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index f5960c12568e..7965e1f22377 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -218,7 +218,7 @@ pub(super) fn hints( } if !postfix && needs_inner_parens { - (&mut pre.label).append_str("("); + pre.label.append_str("("); } if needs_outer_parens || (!postfix && needs_inner_parens) { post.label.append_str(")"); From 3c3bb0712f61a41cb8bc402760bee05901c9f163 Mon Sep 17 00:00:00 2001 From: jnyfah Date: Sat, 21 Jun 2025 00:18:32 +0100 Subject: [PATCH 4/5] revert changes --- crates/ide/src/inlay_hints/adjustment.rs | 3 +- crates/ide/src/inlay_hints/closing_brace.rs | 102 ++------------------ 2 files changed, 10 insertions(+), 95 deletions(-) diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index 7965e1f22377..49b43fc37f24 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -205,8 +205,7 @@ pub(super) fn hints( "`{}` → `{}`\n\n**{}**\n\n{}", source.display(sema.db, display_target), target.display(sema.db, display_target), - coercion.chars().next().unwrap().to_uppercase().collect::() - + &coercion[1..], + coercion, detailed_tooltip )) })), diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs index 4d7650f9e130..1136015f145d 100644 --- a/crates/ide/src/inlay_hints/closing_brace.rs +++ b/crates/ide/src/inlay_hints/closing_brace.rs @@ -91,9 +91,7 @@ pub(super) fn hints( match_ast! { match parent { ast::Fn(it) => { - let hint_text = format_function_hint(&it, config.max_length?) - .unwrap_or_else(|| format!("fn {}", it.name().map(|n| n.to_string()).unwrap_or_default())); - (hint_text, it.name().map(name)) + (format!("fn {}", it.name()?), it.name().map(name)) }, ast::Static(it) => (format!("static {}", it.name()?), it.name().map(name)), ast::Const(it) => { @@ -156,47 +154,6 @@ pub(super) fn hints( None } -fn format_function_hint(func: &ast::Fn, max_length: usize) -> Option { - let name = func.name()?; - let name_str = name.to_string(); - - let params = if let Some(param_list) = func.param_list() { - let mut param_parts = Vec::new(); - let mut total_len = 0; - let max_param_len = max_length.saturating_sub(name_str.len() + 4); - - for param in param_list.params() { - let param_text = if let Some(pat) = param.pat() { - if let Some(ty) = param.ty() { format!("{}: {}", pat, ty) } else { pat.to_string() } - } else if let Some(ty) = param.ty() { - format!("_: {}", ty) - } else { - let param_source = param.syntax().text().to_string(); - if param_source.trim() == "..." { "...".to_owned() } else { "_".to_owned() } - }; - - let param_len = param_text.len() + if param_parts.is_empty() { 0 } else { 2 }; - if total_len + param_len > max_param_len { - param_parts.push("...".to_owned()); - break; - } - - total_len += param_len; - param_parts.push(param_text); - } - - if param_parts.is_empty() { - "()".to_owned() - } else { - format!("({})", param_parts.join(", ")) - } - } else { - "()".to_owned() - }; - - Some(format!("fn {}{}", name_str, params)) -} - #[cfg(test)] mod tests { use crate::{ @@ -207,11 +164,7 @@ mod tests { #[test] fn hints_closing_brace() { check_with_config( - InlayHintsConfig { - closing_brace_hints_min_lines: Some(2), - max_length: Some(30), - ..DISABLED_CONFIG - }, + InlayHintsConfig { closing_brace_hints_min_lines: Some(2), ..DISABLED_CONFIG }, r#" fn a() {} @@ -220,17 +173,17 @@ fn f() { fn g() { } -//^ fn g() +//^ fn g fn h(with: T, arguments: u8, ...) { } -//^ fn h(with: T, arguments: u8, ...) +//^ fn h trait Tr { fn f(); fn g() { } - //^ fn g() + //^ fn g } //^ trait Tr impl Tr for () { @@ -267,7 +220,7 @@ fn f() { let v = vec![ ]; } -//^ fn f() +//^ fn f "#, ); } @@ -275,11 +228,7 @@ fn f() { #[test] fn hints_closing_brace_for_block_expr() { check_with_config( - InlayHintsConfig { - closing_brace_hints_min_lines: Some(2), - max_length: Some(10), - ..DISABLED_CONFIG - }, + InlayHintsConfig { closing_brace_hints_min_lines: Some(2), ..DISABLED_CONFIG }, r#" fn test() { 'end: { @@ -307,41 +256,8 @@ fn test() { //^ 'a } -//^ fn test() -"#, - ); - } - - #[test] - fn hints_closing_brace_function_parameters() { - check_with_config( - InlayHintsConfig { - closing_brace_hints_min_lines: Some(1), - max_length: Some(50), - ..DISABLED_CONFIG - }, - r#" -fn simple() { - let v = vec![ - ]; - } -//^ fn simple() - -fn with_params(x: i32, y: String) { - - } -//^ fn with_params(x: i32, y: String) - -fn long_params(very_long_parameter_name: ComplexType, another: AnotherType) { - - } -//^ fn long_params(...) - -fn many_params(a: i32, b: i32, c: i32, d: i32, e: i32) { - - } -//^ fn many_params(a: i32, b: i32, c: i32, d: i32, ...) +//^ fn test "#, ); } -} +} \ No newline at end of file From a7619a310abbadea3949ab8da7709ebb81dda88d Mon Sep 17 00:00:00 2001 From: jnyfah Date: Sat, 21 Jun 2025 00:20:39 +0100 Subject: [PATCH 5/5] format --- crates/ide/src/inlay_hints/closing_brace.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs index 1136015f145d..14008b5e5bb1 100644 --- a/crates/ide/src/inlay_hints/closing_brace.rs +++ b/crates/ide/src/inlay_hints/closing_brace.rs @@ -260,4 +260,4 @@ fn test() { "#, ); } -} \ No newline at end of file +}