Fix some issues found when testing Elixir-LS (#2583)

Closes
https://linear.app/zed-industries/issue/Z-2209/popovers-dont-always-have-syntax-highlighted-code
Closes
https://linear.app/zed-industries/issue/Z-2206/highlight-syntax-in-hover-docs

* Fix a ton of errors in our logs due to us not recognizing that
`elixir-ls` does not support code actions.
* Syntax-highlight elixir code blocks in hover popovers
This commit is contained in:
Max Brunsfeld 2023-06-07 12:21:48 -07:00 committed by GitHub
commit 351e4863cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 50 deletions

View File

@ -221,6 +221,7 @@ fn show_hover(
project: project.clone(), project: project.clone(),
symbol_range: range, symbol_range: range,
blocks: hover_result.contents, blocks: hover_result.contents,
language: hover_result.language,
rendered_content: None, rendered_content: None,
}) })
}); });
@ -253,6 +254,7 @@ fn render_blocks(
theme_id: usize, theme_id: usize,
blocks: &[HoverBlock], blocks: &[HoverBlock],
language_registry: &Arc<LanguageRegistry>, language_registry: &Arc<LanguageRegistry>,
language: Option<&Arc<Language>>,
style: &EditorStyle, style: &EditorStyle,
) -> RenderedInfo { ) -> RenderedInfo {
let mut text = String::new(); let mut text = String::new();
@ -351,11 +353,13 @@ fn render_blocks(
} }
Tag::CodeBlock(kind) => { Tag::CodeBlock(kind) => {
new_paragraph(&mut text, &mut list_stack); new_paragraph(&mut text, &mut list_stack);
if let CodeBlockKind::Fenced(language) = kind { current_language = if let CodeBlockKind::Fenced(language) = kind {
current_language = language_registry language_registry
.language_for_name(language.as_ref()) .language_for_name(language.as_ref())
.now_or_never() .now_or_never()
.and_then(Result::ok); .and_then(Result::ok)
} else {
language.cloned()
} }
} }
Tag::Emphasis => italic_depth += 1, Tag::Emphasis => italic_depth += 1,
@ -414,10 +418,6 @@ fn render_blocks(
} }
} }
if !text.is_empty() && !text.ends_with('\n') {
text.push('\n');
}
RenderedInfo { RenderedInfo {
theme_id, theme_id,
text, text,
@ -524,6 +524,7 @@ pub struct InfoPopover {
pub project: ModelHandle<Project>, pub project: ModelHandle<Project>,
pub symbol_range: Range<Anchor>, pub symbol_range: Range<Anchor>,
pub blocks: Vec<HoverBlock>, pub blocks: Vec<HoverBlock>,
language: Option<Arc<Language>>,
rendered_content: Option<RenderedInfo>, rendered_content: Option<RenderedInfo>,
} }
@ -559,6 +560,7 @@ impl InfoPopover {
style.theme_id, style.theme_id,
&self.blocks, &self.blocks,
self.project.read(cx).languages(), self.project.read(cx).languages(),
self.language.as_ref(),
style, style,
) )
}); });
@ -588,10 +590,7 @@ impl InfoPopover {
MouseRegion::new::<Self>(view_id, region_id, bounds) MouseRegion::new::<Self>(view_id, region_id, bounds)
.on_click::<Editor, _>( .on_click::<Editor, _>(
MouseButton::Left, MouseButton::Left,
move |_, _, cx| { move |_, _, cx| cx.platform().open_url(&url),
println!("clicked link {url}");
cx.platform().open_url(&url);
},
), ),
); );
} }
@ -906,7 +905,7 @@ mod tests {
text: "one **two** three".to_string(), text: "one **two** three".to_string(),
kind: HoverBlockKind::Markdown, kind: HoverBlockKind::Markdown,
}], }],
expected_marked_text: "one «two» three\n".to_string(), expected_marked_text: "one «two» three".to_string(),
expected_styles: vec![HighlightStyle { expected_styles: vec![HighlightStyle {
weight: Some(Weight::BOLD), weight: Some(Weight::BOLD),
..Default::default() ..Default::default()
@ -918,7 +917,7 @@ mod tests {
text: "one [two](the-url) three".to_string(), text: "one [two](the-url) three".to_string(),
kind: HoverBlockKind::Markdown, kind: HoverBlockKind::Markdown,
}], }],
expected_marked_text: "one «two» three\n".to_string(), expected_marked_text: "one «two» three".to_string(),
expected_styles: vec![HighlightStyle { expected_styles: vec![HighlightStyle {
underline: Some(Underline { underline: Some(Underline {
thickness: 1.0.into(), thickness: 1.0.into(),
@ -937,8 +936,7 @@ mod tests {
- b - b
* two * two
- [c](the-url) - [c](the-url)
- d - d"
"
.unindent(), .unindent(),
kind: HoverBlockKind::Markdown, kind: HoverBlockKind::Markdown,
}], }],
@ -949,8 +947,7 @@ mod tests {
- b - b
- two - two
- «c» - «c»
- d - d"
"
.unindent(), .unindent(),
expected_styles: vec![HighlightStyle { expected_styles: vec![HighlightStyle {
underline: Some(Underline { underline: Some(Underline {
@ -973,8 +970,7 @@ mod tests {
nine nine
* ten * ten
* six * six"
"
.unindent(), .unindent(),
kind: HoverBlockKind::Markdown, kind: HoverBlockKind::Markdown,
}], }],
@ -985,8 +981,7 @@ mod tests {
nine nine
- ten - ten
- six - six"
"
.unindent(), .unindent(),
expected_styles: vec![HighlightStyle { expected_styles: vec![HighlightStyle {
underline: Some(Underline { underline: Some(Underline {
@ -1004,7 +999,7 @@ mod tests {
expected_styles, expected_styles,
} in &rows[0..] } in &rows[0..]
{ {
let rendered = render_blocks(0, &blocks, &Default::default(), &style); let rendered = render_blocks(0, &blocks, &Default::default(), None, &style);
let (expected_text, ranges) = marked_text_ranges(expected_marked_text, false); let (expected_text, ranges) = marked_text_ranges(expected_marked_text, false);
let expected_highlights = ranges let expected_highlights = ranges

View File

@ -260,9 +260,10 @@ impl LanguageServer {
buffer.clear(); buffer.clear();
stdout.read_until(b'\n', &mut buffer).await?; stdout.read_until(b'\n', &mut buffer).await?;
stdout.read_until(b'\n', &mut buffer).await?; stdout.read_until(b'\n', &mut buffer).await?;
let message_len: usize = std::str::from_utf8(&buffer)? let header = std::str::from_utf8(&buffer)?;
let message_len: usize = header
.strip_prefix(CONTENT_LEN_HEADER) .strip_prefix(CONTENT_LEN_HEADER)
.ok_or_else(|| anyhow!("invalid header"))? .ok_or_else(|| anyhow!("invalid LSP message header {header:?}"))?
.trim_end() .trim_end()
.parse()?; .parse()?;
@ -301,7 +302,7 @@ impl LanguageServer {
} }
} else { } else {
warn!( warn!(
"Failed to deserialize message:\n{}", "failed to deserialize LSP message:\n{}",
std::str::from_utf8(&buffer)? std::str::from_utf8(&buffer)?
); );
} }

View File

@ -1111,14 +1111,18 @@ impl LspCommand for GetHover {
cx: AsyncAppContext, cx: AsyncAppContext,
) -> Result<Self::Response> { ) -> Result<Self::Response> {
Ok(message.and_then(|hover| { Ok(message.and_then(|hover| {
let range = hover.range.map(|range| { let (language, range) = cx.read(|cx| {
cx.read(|cx| {
let buffer = buffer.read(cx); let buffer = buffer.read(cx);
(
buffer.language().cloned(),
hover.range.map(|range| {
let token_start = let token_start =
buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left); buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
let token_end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left); let token_end =
buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
buffer.anchor_after(token_start)..buffer.anchor_before(token_end) buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
}) }),
)
}); });
fn hover_blocks_from_marked_string( fn hover_blocks_from_marked_string(
@ -1163,7 +1167,11 @@ impl LspCommand for GetHover {
}], }],
}); });
Some(Hover { contents, range }) Some(Hover {
contents,
range,
language,
})
})) }))
} }
@ -1247,16 +1255,9 @@ impl LspCommand for GetHover {
self, self,
message: proto::GetHoverResponse, message: proto::GetHoverResponse,
_: ModelHandle<Project>, _: ModelHandle<Project>,
_: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
_: AsyncAppContext, cx: AsyncAppContext,
) -> Result<Self::Response> { ) -> Result<Self::Response> {
let range = if let (Some(start), Some(end)) = (message.start, message.end) {
language::proto::deserialize_anchor(start)
.and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
} else {
None
};
let contents: Vec<_> = message let contents: Vec<_> = message
.contents .contents
.into_iter() .into_iter()
@ -1271,12 +1272,23 @@ impl LspCommand for GetHover {
}, },
}) })
.collect(); .collect();
if contents.is_empty() {
return Ok(None);
}
Ok(if contents.is_empty() { let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned());
None let range = if let (Some(start), Some(end)) = (message.start, message.end) {
language::proto::deserialize_anchor(start)
.and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
} else { } else {
Some(Hover { contents, range }) None
}) };
Ok(Some(Hover {
contents,
range,
language,
}))
} }
fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64 { fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64 {
@ -1499,7 +1511,11 @@ impl LspCommand for GetCodeActions {
type ProtoRequest = proto::GetCodeActions; type ProtoRequest = proto::GetCodeActions;
fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool { fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
capabilities.code_action_provider.is_some() match &capabilities.code_action_provider {
None => false,
Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
_ => true,
}
} }
fn to_lsp( fn to_lsp(

View File

@ -359,6 +359,7 @@ pub enum HoverBlockKind {
pub struct Hover { pub struct Hover {
pub contents: Vec<HoverBlock>, pub contents: Vec<HoverBlock>,
pub range: Option<Range<language::Anchor>>, pub range: Option<Range<language::Anchor>>,
pub language: Option<Arc<Language>>,
} }
#[derive(Default)] #[derive(Default)]