Syntax highlighting working. Getting started on markdown support

This commit is contained in:
Keith Simmons 2022-05-31 22:49:47 -07:00
parent 863a3b1886
commit b014352740
7 changed files with 102 additions and 44 deletions

12
Cargo.lock generated
View File

@ -3419,6 +3419,7 @@ dependencies = [
"lsp", "lsp",
"parking_lot", "parking_lot",
"postage", "postage",
"pulldown-cmark",
"rand 0.8.3", "rand 0.8.3",
"regex", "regex",
"rocksdb", "rocksdb",
@ -3555,6 +3556,17 @@ dependencies = [
"prost 0.9.0", "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]] [[package]]
name = "quote" name = "quote"
version = "1.0.9" version = "1.0.9"

View File

@ -39,7 +39,7 @@ pub use multi_buffer::{
Anchor, AnchorRangeExt, ExcerptId, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint, Anchor, AnchorRangeExt, ExcerptId, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint,
}; };
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use project::{Project, ProjectTransaction}; use project::{HoverContents, Project, ProjectTransaction};
use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection}; use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use settings::Settings; use settings::Settings;
@ -891,20 +891,28 @@ impl CodeActionsMenu {
} }
} }
#[derive(Clone)]
struct HoverPopover { struct HoverPopover {
pub point: DisplayPoint, pub point: DisplayPoint,
pub text: String, pub contents: Vec<HoverContents>,
pub runs: Vec<(Range<usize>, HighlightStyle)>,
} }
impl HoverPopover { impl HoverPopover {
fn render(&self, style: EditorStyle) -> (DisplayPoint, ElementBox) { fn render(&self, style: EditorStyle) -> (DisplayPoint, ElementBox) {
let contents = self.contents.first().unwrap();
( (
self.point, self.point,
Text::new(self.text.clone(), style.text.clone()) Text::new(contents.text.clone(), style.text.clone())
.with_soft_wrap(false) .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() .contained()
.with_style(style.hover_popover) .with_style(style.hover_popover)
.boxed(), .boxed(),
@ -2458,7 +2466,6 @@ impl Editor {
} }
fn hover(&mut self, action: &Hover, cx: &mut ViewContext<Self>) { fn hover(&mut self, action: &Hover, cx: &mut ViewContext<Self>) {
// dbg!("hover");
if let Some(point) = action.point { if let Some(point) = action.point {
self.show_hover(&ShowHover(point), cx); self.show_hover(&ShowHover(point), cx);
} else { } else {
@ -2520,7 +2527,7 @@ impl Editor {
let task = cx.spawn_weak(|this, mut cx| { let task = cx.spawn_weak(|this, mut cx| {
async move { async move {
// TODO: what to show while LSP is loading? // TODO: what to show while LSP is loading?
let mut text = None; let mut contents = None;
let hover = match hover.await { let hover = match hover.await {
Ok(hover) => hover, Ok(hover) => hover,
@ -2528,37 +2535,27 @@ impl Editor {
}; };
if let Some(hover) = hover { if let Some(hover) = hover {
text = Some(match hover.contents { if hover.contents.is_empty() {
lsp::HoverContents::Scalar(marked_string) => match marked_string { contents = None;
lsp::MarkedString::String(string) => string, } else {
lsp::MarkedString::LanguageString(string) => string.value, contents = Some(hover.contents);
},
lsp::HoverContents::Array(marked_strings) => {
// TODO: what to do?
todo!()
}
lsp::HoverContents::Markup(markup) => markup.value,
});
if let Some(range) = hover.range { if let Some(range) = hover.range {
let offset_range = range.to_offset(&buffer_snapshot); let offset_range = range.to_offset(&buffer_snapshot);
if offset_range if offset_range
.contains(&point.to_offset(&snapshot.display_snapshot, Bias::Left)) .contains(&point.to_offset(&snapshot.display_snapshot, Bias::Left))
{ {
point = offset_range point = offset_range
.start .start
.to_display_point(&snapshot.display_snapshot); .to_display_point(&snapshot.display_snapshot);
} else { } else {
text = None; contents = None;
}
} }
} }
}; };
let hover_popover = text.map(|text| HoverPopover { let hover_popover = contents.map(|contents| HoverPopover { point, contents });
point,
text,
runs: Vec::new(),
});
if let Some(this) = this.upgrade(&cx) { if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {

View File

@ -236,7 +236,7 @@ impl LanguageRegistry {
self.languages self.languages
.read() .read()
.iter() .iter()
.find(|language| language.name().as_ref() == name) .find(|language| language.name().to_lowercase() == name.to_lowercase())
.cloned() .cloned()
} }

View File

@ -296,6 +296,10 @@ impl LanguageServer {
prepare_support: Some(true), prepare_support: Some(true),
..Default::default() ..Default::default()
}), }),
hover: Some(HoverClientCapabilities {
content_format: Some(vec![MarkupKind::Markdown]),
..Default::default()
}),
..Default::default() ..Default::default()
}), }),
experimental: Some(json!({ experimental: Some(json!({

View File

@ -38,6 +38,7 @@ libc = "0.2"
log = { version = "0.4.16", features = ["kv_unstable_serde"] } log = { version = "0.4.16", features = ["kv_unstable_serde"] }
parking_lot = "0.11.1" parking_lot = "0.11.1"
postage = { version = "0.4.1", features = ["futures-traits"] } postage = { version = "0.4.1", features = ["futures-traits"] }
pulldown-cmark = { version = "0.9.1", default-features = false }
rand = "0.8.3" rand = "0.8.3"
regex = "1.5" regex = "1.5"
serde = { version = "1.0", features = ["derive", "rc"] } serde = { version = "1.0", features = ["derive", "rc"] }

View File

@ -1,4 +1,4 @@
use crate::{DocumentHighlight, Hover, Location, Project, ProjectTransaction}; use crate::{DocumentHighlight, Hover, HoverContents, Location, Project, ProjectTransaction};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use async_trait::async_trait; use async_trait::async_trait;
use client::{proto, PeerId}; use client::{proto, PeerId};
@ -835,10 +835,48 @@ impl LspCommand for GetHover {
}) })
}); });
Hover { fn highlight(lsp_marked_string: lsp::MarkedString, project: &Project) -> HoverContents {
contents: hover.contents, match lsp_marked_string {
range, 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( async fn from_proto(
message: Self::ProtoRequest, message: Self::ProtoRequest,
project: ModelHandle<Project>, _: ModelHandle<Project>,
buffer: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
mut cx: AsyncAppContext, mut cx: AsyncAppContext,
) -> Result<Self> { ) -> Result<Self> {

View File

@ -19,9 +19,9 @@ use language::{
point_to_lsp, point_to_lsp,
proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version}, proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CodeAction, CodeLabel, Completion, range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CodeAction, CodeLabel, Completion,
Diagnostic, DiagnosticEntry, DiagnosticSet, Event as BufferEvent, File as _, Language, Diagnostic, DiagnosticEntry, DiagnosticSet, Event as BufferEvent, File as _, HighlightId,
LanguageRegistry, LanguageServerName, LocalFile, LspAdapter, OffsetRangeExt, Operation, Patch, Language, LanguageRegistry, LanguageServerName, LocalFile, LspAdapter, OffsetRangeExt,
PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction, Operation, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction,
}; };
use lsp::{DiagnosticSeverity, DiagnosticTag, DocumentHighlightKind, LanguageServer}; use lsp::{DiagnosticSeverity, DiagnosticTag, DocumentHighlightKind, LanguageServer};
use lsp_command::*; use lsp_command::*;
@ -216,9 +216,15 @@ pub struct Symbol {
pub signature: [u8; 32], pub signature: [u8; 32],
} }
#[derive(Debug)]
pub struct HoverContents {
pub text: String,
pub runs: Vec<(Range<usize>, HighlightId)>,
}
#[derive(Debug)] #[derive(Debug)]
pub struct Hover { pub struct Hover {
pub contents: lsp::HoverContents, pub contents: Vec<HoverContents>,
pub range: Option<Range<language::Anchor>>, pub range: Option<Range<language::Anchor>>,
} }