
This PR revives zed-industries/zed#27818 and aims to complete the partially implemented overloaded signature help feature. The first commit is a rebase of zed-industries/zed#27818, and the subsequent commit addresses all review feedback from the original PR. Now the overloaded signature help works like https://github.com/user-attachments/assets/e253c9a0-e3a5-4bfe-8003-eb75de41f672 Closes #21493 Release Notes: - Implemented signature help for overloaded items. Additionally, added a support for rendering signature help documentation. --------- Co-authored-by: Fernando Tagawa <tagawafernando@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Kirill Bulatov <mail4score@gmail.com> Co-authored-by: Kirill Bulatov <kirill@zed.dev>
739 lines
30 KiB
Rust
739 lines
30 KiB
Rust
use std::{ops::Range, sync::Arc};
|
|
|
|
use gpui::{App, AppContext, Entity, FontWeight, HighlightStyle, SharedString};
|
|
use language::LanguageRegistry;
|
|
use markdown::Markdown;
|
|
use rpc::proto::{self, documentation};
|
|
|
|
#[derive(Debug)]
|
|
pub struct SignatureHelp {
|
|
pub active_signature: usize,
|
|
pub signatures: Vec<SignatureHelpData>,
|
|
pub(super) original_data: lsp::SignatureHelp,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct SignatureHelpData {
|
|
pub label: SharedString,
|
|
pub documentation: Option<Entity<Markdown>>,
|
|
pub highlights: Vec<(Range<usize>, HighlightStyle)>,
|
|
pub active_parameter: Option<usize>,
|
|
pub parameters: Vec<ParameterInfo>,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct ParameterInfo {
|
|
pub label_range: Option<Range<usize>>,
|
|
pub documentation: Option<Entity<Markdown>>,
|
|
}
|
|
|
|
impl SignatureHelp {
|
|
pub fn new(
|
|
help: lsp::SignatureHelp,
|
|
language_registry: Option<Arc<LanguageRegistry>>,
|
|
cx: &mut App,
|
|
) -> Option<Self> {
|
|
if help.signatures.is_empty() {
|
|
return None;
|
|
}
|
|
let active_signature = help.active_signature.unwrap_or(0) as usize;
|
|
let mut signatures = Vec::<SignatureHelpData>::with_capacity(help.signatures.capacity());
|
|
for signature in &help.signatures {
|
|
let active_parameter = signature
|
|
.active_parameter
|
|
.unwrap_or_else(|| help.active_parameter.unwrap_or(0))
|
|
as usize;
|
|
let mut highlights = Vec::new();
|
|
let mut parameter_infos = Vec::new();
|
|
|
|
if let Some(parameters) = &signature.parameters {
|
|
for (index, parameter) in parameters.iter().enumerate() {
|
|
let label_range = match ¶meter.label {
|
|
lsp::ParameterLabel::LabelOffsets(parameter_label_offsets) => {
|
|
let range = *parameter_label_offsets.get(0)? as usize
|
|
..*parameter_label_offsets.get(1)? as usize;
|
|
if index == active_parameter {
|
|
highlights.push((
|
|
range.clone(),
|
|
HighlightStyle {
|
|
font_weight: Some(FontWeight::EXTRA_BOLD),
|
|
..HighlightStyle::default()
|
|
},
|
|
));
|
|
}
|
|
Some(range)
|
|
}
|
|
lsp::ParameterLabel::Simple(parameter_label) => {
|
|
if let Some(start) = signature.label.find(parameter_label) {
|
|
let range = start..start + parameter_label.len();
|
|
if index == active_parameter {
|
|
highlights.push((
|
|
range.clone(),
|
|
HighlightStyle {
|
|
font_weight: Some(FontWeight::EXTRA_BOLD),
|
|
..HighlightStyle::default()
|
|
},
|
|
));
|
|
}
|
|
Some(range)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
};
|
|
|
|
let documentation = parameter
|
|
.documentation
|
|
.as_ref()
|
|
.map(|doc| documentation_to_markdown(doc, language_registry.clone(), cx));
|
|
|
|
parameter_infos.push(ParameterInfo {
|
|
label_range,
|
|
documentation,
|
|
});
|
|
}
|
|
}
|
|
|
|
let label = SharedString::from(signature.label.clone());
|
|
let documentation = signature
|
|
.documentation
|
|
.as_ref()
|
|
.map(|doc| documentation_to_markdown(doc, language_registry.clone(), cx));
|
|
|
|
signatures.push(SignatureHelpData {
|
|
label,
|
|
documentation,
|
|
highlights,
|
|
active_parameter: Some(active_parameter),
|
|
parameters: parameter_infos,
|
|
});
|
|
}
|
|
Some(Self {
|
|
signatures,
|
|
active_signature,
|
|
original_data: help,
|
|
})
|
|
}
|
|
}
|
|
|
|
fn documentation_to_markdown(
|
|
documentation: &lsp::Documentation,
|
|
language_registry: Option<Arc<LanguageRegistry>>,
|
|
cx: &mut App,
|
|
) -> Entity<Markdown> {
|
|
match documentation {
|
|
lsp::Documentation::String(string) => {
|
|
cx.new(|cx| Markdown::new_text(SharedString::from(string), cx))
|
|
}
|
|
lsp::Documentation::MarkupContent(markup) => match markup.kind {
|
|
lsp::MarkupKind::PlainText => {
|
|
cx.new(|cx| Markdown::new_text(SharedString::from(&markup.value), cx))
|
|
}
|
|
lsp::MarkupKind::Markdown => cx.new(|cx| {
|
|
Markdown::new(
|
|
SharedString::from(&markup.value),
|
|
language_registry,
|
|
None,
|
|
cx,
|
|
)
|
|
}),
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn lsp_to_proto_signature(lsp_help: lsp::SignatureHelp) -> proto::SignatureHelp {
|
|
proto::SignatureHelp {
|
|
signatures: lsp_help
|
|
.signatures
|
|
.into_iter()
|
|
.map(|signature| proto::SignatureInformation {
|
|
label: signature.label,
|
|
documentation: signature.documentation.map(lsp_to_proto_documentation),
|
|
parameters: signature
|
|
.parameters
|
|
.unwrap_or_default()
|
|
.into_iter()
|
|
.map(|parameter_info| proto::ParameterInformation {
|
|
label: Some(match parameter_info.label {
|
|
lsp::ParameterLabel::Simple(label) => {
|
|
proto::parameter_information::Label::Simple(label)
|
|
}
|
|
lsp::ParameterLabel::LabelOffsets(offsets) => {
|
|
proto::parameter_information::Label::LabelOffsets(
|
|
proto::LabelOffsets {
|
|
start: offsets[0],
|
|
end: offsets[1],
|
|
},
|
|
)
|
|
}
|
|
}),
|
|
documentation: parameter_info.documentation.map(lsp_to_proto_documentation),
|
|
})
|
|
.collect(),
|
|
active_parameter: signature.active_parameter,
|
|
})
|
|
.collect(),
|
|
active_signature: lsp_help.active_signature,
|
|
active_parameter: lsp_help.active_parameter,
|
|
}
|
|
}
|
|
|
|
fn lsp_to_proto_documentation(documentation: lsp::Documentation) -> proto::Documentation {
|
|
proto::Documentation {
|
|
content: Some(match documentation {
|
|
lsp::Documentation::String(string) => proto::documentation::Content::Value(string),
|
|
lsp::Documentation::MarkupContent(content) => {
|
|
proto::documentation::Content::MarkupContent(proto::MarkupContent {
|
|
is_markdown: matches!(content.kind, lsp::MarkupKind::Markdown),
|
|
value: content.value,
|
|
})
|
|
}
|
|
}),
|
|
}
|
|
}
|
|
|
|
pub fn proto_to_lsp_signature(proto_help: proto::SignatureHelp) -> lsp::SignatureHelp {
|
|
lsp::SignatureHelp {
|
|
signatures: proto_help
|
|
.signatures
|
|
.into_iter()
|
|
.map(|signature| lsp::SignatureInformation {
|
|
label: signature.label,
|
|
documentation: signature.documentation.and_then(proto_to_lsp_documentation),
|
|
parameters: Some(
|
|
signature
|
|
.parameters
|
|
.into_iter()
|
|
.filter_map(|parameter_info| {
|
|
Some(lsp::ParameterInformation {
|
|
label: match parameter_info.label? {
|
|
proto::parameter_information::Label::Simple(string) => {
|
|
lsp::ParameterLabel::Simple(string)
|
|
}
|
|
proto::parameter_information::Label::LabelOffsets(offsets) => {
|
|
lsp::ParameterLabel::LabelOffsets([
|
|
offsets.start,
|
|
offsets.end,
|
|
])
|
|
}
|
|
},
|
|
documentation: parameter_info
|
|
.documentation
|
|
.and_then(proto_to_lsp_documentation),
|
|
})
|
|
})
|
|
.collect(),
|
|
),
|
|
active_parameter: signature.active_parameter,
|
|
})
|
|
.collect(),
|
|
active_signature: proto_help.active_signature,
|
|
active_parameter: proto_help.active_parameter,
|
|
}
|
|
}
|
|
|
|
fn proto_to_lsp_documentation(documentation: proto::Documentation) -> Option<lsp::Documentation> {
|
|
{
|
|
Some(match documentation.content? {
|
|
documentation::Content::Value(string) => lsp::Documentation::String(string),
|
|
documentation::Content::MarkupContent(markup) => {
|
|
lsp::Documentation::MarkupContent(if markup.is_markdown {
|
|
lsp::MarkupContent {
|
|
kind: lsp::MarkupKind::Markdown,
|
|
value: markup.value,
|
|
}
|
|
} else {
|
|
lsp::MarkupContent {
|
|
kind: lsp::MarkupKind::PlainText,
|
|
value: markup.value,
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use gpui::{FontWeight, HighlightStyle, SharedString, TestAppContext};
|
|
use lsp::{Documentation, MarkupContent, MarkupKind};
|
|
|
|
use crate::lsp_command::signature_help::SignatureHelp;
|
|
|
|
fn current_parameter() -> HighlightStyle {
|
|
HighlightStyle {
|
|
font_weight: Some(FontWeight::EXTRA_BOLD),
|
|
..Default::default()
|
|
}
|
|
}
|
|
|
|
#[gpui::test]
|
|
fn test_create_signature_help_markdown_string_1(cx: &mut TestAppContext) {
|
|
let signature_help = lsp::SignatureHelp {
|
|
signatures: vec![lsp::SignatureInformation {
|
|
label: "fn test(foo: u8, bar: &str)".to_string(),
|
|
documentation: Some(Documentation::String(
|
|
"This is a test documentation".to_string(),
|
|
)),
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("foo: u8".to_string()),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("bar: &str".to_string()),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
}],
|
|
active_signature: Some(0),
|
|
active_parameter: Some(0),
|
|
};
|
|
let maybe_markdown = cx.update(|cx| SignatureHelp::new(signature_help, None, cx));
|
|
assert!(maybe_markdown.is_some());
|
|
|
|
let markdown = maybe_markdown.unwrap();
|
|
let signature = markdown.signatures[markdown.active_signature].clone();
|
|
let markdown = (signature.label, signature.highlights);
|
|
assert_eq!(
|
|
markdown,
|
|
(
|
|
SharedString::new("fn test(foo: u8, bar: &str)"),
|
|
vec![(8..15, current_parameter())]
|
|
)
|
|
);
|
|
assert_eq!(
|
|
signature
|
|
.documentation
|
|
.unwrap()
|
|
.update(cx, |documentation, _| documentation.source().to_owned()),
|
|
"This is a test documentation",
|
|
)
|
|
}
|
|
|
|
#[gpui::test]
|
|
fn test_create_signature_help_markdown_string_2(cx: &mut TestAppContext) {
|
|
let signature_help = lsp::SignatureHelp {
|
|
signatures: vec![lsp::SignatureInformation {
|
|
label: "fn test(foo: u8, bar: &str)".to_string(),
|
|
documentation: Some(Documentation::MarkupContent(MarkupContent {
|
|
kind: MarkupKind::Markdown,
|
|
value: "This is a test documentation".to_string(),
|
|
})),
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("foo: u8".to_string()),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("bar: &str".to_string()),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
}],
|
|
active_signature: Some(0),
|
|
active_parameter: Some(1),
|
|
};
|
|
let maybe_markdown = cx.update(|cx| SignatureHelp::new(signature_help, None, cx));
|
|
assert!(maybe_markdown.is_some());
|
|
|
|
let markdown = maybe_markdown.unwrap();
|
|
let signature = markdown.signatures[markdown.active_signature].clone();
|
|
let markdown = (signature.label, signature.highlights);
|
|
assert_eq!(
|
|
markdown,
|
|
(
|
|
SharedString::new("fn test(foo: u8, bar: &str)"),
|
|
vec![(17..26, current_parameter())]
|
|
)
|
|
);
|
|
assert_eq!(
|
|
signature
|
|
.documentation
|
|
.unwrap()
|
|
.update(cx, |documentation, _| documentation.source().to_owned()),
|
|
"This is a test documentation",
|
|
)
|
|
}
|
|
|
|
#[gpui::test]
|
|
fn test_create_signature_help_markdown_string_3(cx: &mut TestAppContext) {
|
|
let signature_help = lsp::SignatureHelp {
|
|
signatures: vec![
|
|
lsp::SignatureInformation {
|
|
label: "fn test1(foo: u8, bar: &str)".to_string(),
|
|
documentation: None,
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("foo: u8".to_string()),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("bar: &str".to_string()),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
},
|
|
lsp::SignatureInformation {
|
|
label: "fn test2(hoge: String, fuga: bool)".to_string(),
|
|
documentation: None,
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("hoge: String".to_string()),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("fuga: bool".to_string()),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
},
|
|
],
|
|
active_signature: Some(0),
|
|
active_parameter: Some(0),
|
|
};
|
|
let maybe_markdown = cx.update(|cx| SignatureHelp::new(signature_help, None, cx));
|
|
assert!(maybe_markdown.is_some());
|
|
|
|
let markdown = maybe_markdown.unwrap();
|
|
let signature = markdown.signatures[markdown.active_signature].clone();
|
|
let markdown = (signature.label, signature.highlights);
|
|
assert_eq!(
|
|
markdown,
|
|
(
|
|
SharedString::new("fn test1(foo: u8, bar: &str)"),
|
|
vec![(9..16, current_parameter())]
|
|
)
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
fn test_create_signature_help_markdown_string_4(cx: &mut TestAppContext) {
|
|
let signature_help = lsp::SignatureHelp {
|
|
signatures: vec![
|
|
lsp::SignatureInformation {
|
|
label: "fn test1(foo: u8, bar: &str)".to_string(),
|
|
documentation: None,
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("foo: u8".to_string()),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("bar: &str".to_string()),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
},
|
|
lsp::SignatureInformation {
|
|
label: "fn test2(hoge: String, fuga: bool)".to_string(),
|
|
documentation: None,
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("hoge: String".to_string()),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("fuga: bool".to_string()),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
},
|
|
],
|
|
active_signature: Some(1),
|
|
active_parameter: Some(0),
|
|
};
|
|
let maybe_markdown = cx.update(|cx| SignatureHelp::new(signature_help, None, cx));
|
|
assert!(maybe_markdown.is_some());
|
|
|
|
let markdown = maybe_markdown.unwrap();
|
|
let signature = markdown.signatures[markdown.active_signature].clone();
|
|
let markdown = (signature.label, signature.highlights);
|
|
assert_eq!(
|
|
markdown,
|
|
(
|
|
SharedString::new("fn test2(hoge: String, fuga: bool)"),
|
|
vec![(9..21, current_parameter())]
|
|
)
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
fn test_create_signature_help_markdown_string_5(cx: &mut TestAppContext) {
|
|
let signature_help = lsp::SignatureHelp {
|
|
signatures: vec![
|
|
lsp::SignatureInformation {
|
|
label: "fn test1(foo: u8, bar: &str)".to_string(),
|
|
documentation: None,
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("foo: u8".to_string()),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("bar: &str".to_string()),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
},
|
|
lsp::SignatureInformation {
|
|
label: "fn test2(hoge: String, fuga: bool)".to_string(),
|
|
documentation: None,
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("hoge: String".to_string()),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("fuga: bool".to_string()),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
},
|
|
],
|
|
active_signature: Some(1),
|
|
active_parameter: Some(1),
|
|
};
|
|
let maybe_markdown = cx.update(|cx| SignatureHelp::new(signature_help, None, cx));
|
|
assert!(maybe_markdown.is_some());
|
|
|
|
let markdown = maybe_markdown.unwrap();
|
|
let signature = markdown.signatures[markdown.active_signature].clone();
|
|
let markdown = (signature.label, signature.highlights);
|
|
assert_eq!(
|
|
markdown,
|
|
(
|
|
SharedString::new("fn test2(hoge: String, fuga: bool)"),
|
|
vec![(23..33, current_parameter())]
|
|
)
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
fn test_create_signature_help_markdown_string_6(cx: &mut TestAppContext) {
|
|
let signature_help = lsp::SignatureHelp {
|
|
signatures: vec![
|
|
lsp::SignatureInformation {
|
|
label: "fn test1(foo: u8, bar: &str)".to_string(),
|
|
documentation: None,
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("foo: u8".to_string()),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("bar: &str".to_string()),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
},
|
|
lsp::SignatureInformation {
|
|
label: "fn test2(hoge: String, fuga: bool)".to_string(),
|
|
documentation: None,
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("hoge: String".to_string()),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("fuga: bool".to_string()),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
},
|
|
],
|
|
active_signature: Some(1),
|
|
active_parameter: None,
|
|
};
|
|
let maybe_markdown = cx.update(|cx| SignatureHelp::new(signature_help, None, cx));
|
|
assert!(maybe_markdown.is_some());
|
|
|
|
let markdown = maybe_markdown.unwrap();
|
|
let signature = markdown.signatures[markdown.active_signature].clone();
|
|
let markdown = (signature.label, signature.highlights);
|
|
assert_eq!(
|
|
markdown,
|
|
(
|
|
SharedString::new("fn test2(hoge: String, fuga: bool)"),
|
|
vec![(9..21, current_parameter())]
|
|
)
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
fn test_create_signature_help_markdown_string_7(cx: &mut TestAppContext) {
|
|
let signature_help = lsp::SignatureHelp {
|
|
signatures: vec![
|
|
lsp::SignatureInformation {
|
|
label: "fn test1(foo: u8, bar: &str)".to_string(),
|
|
documentation: None,
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("foo: u8".to_string()),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("bar: &str".to_string()),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
},
|
|
lsp::SignatureInformation {
|
|
label: "fn test2(hoge: String, fuga: bool)".to_string(),
|
|
documentation: None,
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("hoge: String".to_string()),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("fuga: bool".to_string()),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
},
|
|
lsp::SignatureInformation {
|
|
label: "fn test3(one: usize, two: u32)".to_string(),
|
|
documentation: None,
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("one: usize".to_string()),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("two: u32".to_string()),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
},
|
|
],
|
|
active_signature: Some(2),
|
|
active_parameter: Some(1),
|
|
};
|
|
let maybe_markdown = cx.update(|cx| SignatureHelp::new(signature_help, None, cx));
|
|
assert!(maybe_markdown.is_some());
|
|
|
|
let markdown = maybe_markdown.unwrap();
|
|
let signature = markdown.signatures[markdown.active_signature].clone();
|
|
let markdown = (signature.label, signature.highlights);
|
|
assert_eq!(
|
|
markdown,
|
|
(
|
|
SharedString::new("fn test3(one: usize, two: u32)"),
|
|
vec![(21..29, current_parameter())]
|
|
)
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
fn test_create_signature_help_markdown_string_8(cx: &mut TestAppContext) {
|
|
let signature_help = lsp::SignatureHelp {
|
|
signatures: vec![],
|
|
active_signature: None,
|
|
active_parameter: None,
|
|
};
|
|
let maybe_markdown = cx.update(|cx| SignatureHelp::new(signature_help, None, cx));
|
|
assert!(maybe_markdown.is_none());
|
|
}
|
|
|
|
#[gpui::test]
|
|
fn test_create_signature_help_markdown_string_9(cx: &mut TestAppContext) {
|
|
let signature_help = lsp::SignatureHelp {
|
|
signatures: vec![lsp::SignatureInformation {
|
|
label: "fn test(foo: u8, bar: &str)".to_string(),
|
|
documentation: None,
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::LabelOffsets([8, 15]),
|
|
documentation: None,
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::LabelOffsets([17, 26]),
|
|
documentation: None,
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
}],
|
|
active_signature: Some(0),
|
|
active_parameter: Some(0),
|
|
};
|
|
let maybe_markdown = cx.update(|cx| SignatureHelp::new(signature_help, None, cx));
|
|
assert!(maybe_markdown.is_some());
|
|
|
|
let markdown = maybe_markdown.unwrap();
|
|
let signature = markdown.signatures[markdown.active_signature].clone();
|
|
let markdown = (signature.label, signature.highlights);
|
|
assert_eq!(
|
|
markdown,
|
|
(
|
|
SharedString::new("fn test(foo: u8, bar: &str)"),
|
|
vec![(8..15, current_parameter())]
|
|
)
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
fn test_parameter_documentation(cx: &mut TestAppContext) {
|
|
let signature_help = lsp::SignatureHelp {
|
|
signatures: vec![lsp::SignatureInformation {
|
|
label: "fn test(foo: u8, bar: &str)".to_string(),
|
|
documentation: Some(Documentation::String(
|
|
"This is a test documentation".to_string(),
|
|
)),
|
|
parameters: Some(vec![
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("foo: u8".to_string()),
|
|
documentation: Some(Documentation::String("The foo parameter".to_string())),
|
|
},
|
|
lsp::ParameterInformation {
|
|
label: lsp::ParameterLabel::Simple("bar: &str".to_string()),
|
|
documentation: Some(Documentation::String("The bar parameter".to_string())),
|
|
},
|
|
]),
|
|
active_parameter: None,
|
|
}],
|
|
active_signature: Some(0),
|
|
active_parameter: Some(0),
|
|
};
|
|
let maybe_signature_help = cx.update(|cx| SignatureHelp::new(signature_help, None, cx));
|
|
assert!(maybe_signature_help.is_some());
|
|
|
|
let signature_help = maybe_signature_help.unwrap();
|
|
let signature = &signature_help.signatures[signature_help.active_signature];
|
|
|
|
// Check that parameter documentation is extracted
|
|
assert_eq!(signature.parameters.len(), 2);
|
|
assert_eq!(
|
|
signature.parameters[0]
|
|
.documentation
|
|
.as_ref()
|
|
.unwrap()
|
|
.update(cx, |documentation, _| documentation.source().to_owned()),
|
|
"The foo parameter",
|
|
);
|
|
assert_eq!(
|
|
signature.parameters[1]
|
|
.documentation
|
|
.as_ref()
|
|
.unwrap()
|
|
.update(cx, |documentation, _| documentation.source().to_owned()),
|
|
"The bar parameter",
|
|
);
|
|
|
|
// Check that the active parameter is correct
|
|
assert_eq!(signature.active_parameter, Some(0));
|
|
}
|
|
}
|