Detailed changes
@@ -3419,6 +3419,7 @@ dependencies = [
"lsp",
"parking_lot",
"postage",
+ "pulldown-cmark",
"rand 0.8.3",
"regex",
"rocksdb",
@@ -3555,6 +3556,17 @@ dependencies = [
"prost 0.9.0",
]
+[[package]]
+name = "pulldown-cmark"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
+dependencies = [
+ "bitflags",
+ "memchr",
+ "unicase",
+]
+
[[package]]
name = "quote"
version = "1.0.9"
@@ -39,7 +39,7 @@ pub use multi_buffer::{
Anchor, AnchorRangeExt, ExcerptId, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint,
};
use ordered_float::OrderedFloat;
-use project::{Project, ProjectTransaction};
+use project::{HoverContents, Project, ProjectTransaction};
use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
use serde::{Deserialize, Serialize};
use settings::Settings;
@@ -891,20 +891,28 @@ impl CodeActionsMenu {
}
}
-#[derive(Clone)]
struct HoverPopover {
pub point: DisplayPoint,
- pub text: String,
- pub runs: Vec<(Range<usize>, HighlightStyle)>,
+ pub contents: Vec<HoverContents>,
}
impl HoverPopover {
fn render(&self, style: EditorStyle) -> (DisplayPoint, ElementBox) {
+ let contents = self.contents.first().unwrap();
(
self.point,
- Text::new(self.text.clone(), style.text.clone())
+ Text::new(contents.text.clone(), style.text.clone())
.with_soft_wrap(false)
- .with_highlights(self.runs.clone())
+ .with_highlights(
+ contents
+ .runs
+ .iter()
+ .filter_map(|(range, id)| {
+ id.style(style.theme.syntax.as_ref())
+ .map(|style| (range.clone(), style))
+ })
+ .collect(),
+ )
.contained()
.with_style(style.hover_popover)
.boxed(),
@@ -2458,7 +2466,6 @@ impl Editor {
}
fn hover(&mut self, action: &Hover, cx: &mut ViewContext<Self>) {
- // dbg!("hover");
if let Some(point) = action.point {
self.show_hover(&ShowHover(point), cx);
} else {
@@ -2520,7 +2527,7 @@ impl Editor {
let task = cx.spawn_weak(|this, mut cx| {
async move {
// TODO: what to show while LSP is loading?
- let mut text = None;
+ let mut contents = None;
let hover = match hover.await {
Ok(hover) => hover,
@@ -2528,37 +2535,27 @@ impl Editor {
};
if let Some(hover) = hover {
- text = Some(match hover.contents {
- lsp::HoverContents::Scalar(marked_string) => match marked_string {
- lsp::MarkedString::String(string) => string,
- lsp::MarkedString::LanguageString(string) => string.value,
- },
- lsp::HoverContents::Array(marked_strings) => {
- // TODO: what to do?
- todo!()
- }
- lsp::HoverContents::Markup(markup) => markup.value,
- });
-
- if let Some(range) = hover.range {
- let offset_range = range.to_offset(&buffer_snapshot);
- if offset_range
- .contains(&point.to_offset(&snapshot.display_snapshot, Bias::Left))
- {
- point = offset_range
- .start
- .to_display_point(&snapshot.display_snapshot);
- } else {
- text = None;
+ if hover.contents.is_empty() {
+ contents = None;
+ } else {
+ contents = Some(hover.contents);
+
+ if let Some(range) = hover.range {
+ let offset_range = range.to_offset(&buffer_snapshot);
+ if offset_range
+ .contains(&point.to_offset(&snapshot.display_snapshot, Bias::Left))
+ {
+ point = offset_range
+ .start
+ .to_display_point(&snapshot.display_snapshot);
+ } else {
+ contents = None;
+ }
}
}
};
- let hover_popover = text.map(|text| HoverPopover {
- point,
- text,
- runs: Vec::new(),
- });
+ let hover_popover = contents.map(|contents| HoverPopover { point, contents });
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| {
@@ -236,7 +236,7 @@ impl LanguageRegistry {
self.languages
.read()
.iter()
- .find(|language| language.name().as_ref() == name)
+ .find(|language| language.name().to_lowercase() == name.to_lowercase())
.cloned()
}
@@ -296,6 +296,10 @@ impl LanguageServer {
prepare_support: Some(true),
..Default::default()
}),
+ hover: Some(HoverClientCapabilities {
+ content_format: Some(vec![MarkupKind::Markdown]),
+ ..Default::default()
+ }),
..Default::default()
}),
experimental: Some(json!({
@@ -38,6 +38,7 @@ libc = "0.2"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
parking_lot = "0.11.1"
postage = { version = "0.4.1", features = ["futures-traits"] }
+pulldown-cmark = { version = "0.9.1", default-features = false }
rand = "0.8.3"
regex = "1.5"
serde = { version = "1.0", features = ["derive", "rc"] }
@@ -1,4 +1,4 @@
-use crate::{DocumentHighlight, Hover, Location, Project, ProjectTransaction};
+use crate::{DocumentHighlight, Hover, HoverContents, Location, Project, ProjectTransaction};
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use client::{proto, PeerId};
@@ -835,10 +835,48 @@ impl LspCommand for GetHover {
})
});
- Hover {
- contents: hover.contents,
- range,
+ fn highlight(lsp_marked_string: lsp::MarkedString, project: &Project) -> HoverContents {
+ match lsp_marked_string {
+ lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
+ if let Some(language) = project.languages().get_language(&language) {
+ let runs =
+ language.highlight_text(&value.as_str().into(), 0..value.len());
+ HoverContents { text: value, runs }
+ } else {
+ HoverContents {
+ text: value,
+ runs: Vec::new(),
+ }
+ }
+ }
+ lsp::MarkedString::String(text) => HoverContents {
+ text,
+ runs: Vec::new(),
+ },
+ }
}
+
+ let contents = cx.read(|cx| {
+ let project = project.read(cx);
+ match dbg!(hover.contents) {
+ lsp::HoverContents::Scalar(marked_string) => {
+ vec![highlight(marked_string, project)]
+ }
+ lsp::HoverContents::Array(marked_strings) => marked_strings
+ .into_iter()
+ .map(|marked_string| highlight(marked_string, project))
+ .collect(),
+ lsp::HoverContents::Markup(markup_content) => {
+ // TODO: handle markdown
+ vec![HoverContents {
+ text: markup_content.value,
+ runs: Vec::new(),
+ }]
+ }
+ }
+ });
+
+ Hover { contents, range }
}))
}
@@ -855,7 +893,7 @@ impl LspCommand for GetHover {
async fn from_proto(
message: Self::ProtoRequest,
- project: ModelHandle<Project>,
+ _: ModelHandle<Project>,
buffer: ModelHandle<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Self> {
@@ -19,9 +19,9 @@ use language::{
point_to_lsp,
proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CodeAction, CodeLabel, Completion,
- Diagnostic, DiagnosticEntry, DiagnosticSet, Event as BufferEvent, File as _, Language,
- LanguageRegistry, LanguageServerName, LocalFile, LspAdapter, OffsetRangeExt, Operation, Patch,
- PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction,
+ Diagnostic, DiagnosticEntry, DiagnosticSet, Event as BufferEvent, File as _, HighlightId,
+ Language, LanguageRegistry, LanguageServerName, LocalFile, LspAdapter, OffsetRangeExt,
+ Operation, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction,
};
use lsp::{DiagnosticSeverity, DiagnosticTag, DocumentHighlightKind, LanguageServer};
use lsp_command::*;
@@ -216,9 +216,15 @@ pub struct Symbol {
pub signature: [u8; 32],
}
+#[derive(Debug)]
+pub struct HoverContents {
+ pub text: String,
+ pub runs: Vec<(Range<usize>, HighlightId)>,
+}
+
#[derive(Debug)]
pub struct Hover {
- pub contents: lsp::HoverContents,
+ pub contents: Vec<HoverContents>,
pub range: Option<Range<language::Anchor>>,
}