From b014352740e4645e08260990c5896a565bdf108f Mon Sep 17 00:00:00 2001 From: Keith Simmons Date: Tue, 31 May 2022 22:49:47 -0700 Subject: [PATCH] Syntax highlighting working. Getting started on markdown support --- Cargo.lock | 12 ++++++ crates/editor/src/editor.rs | 65 +++++++++++++++---------------- crates/language/src/language.rs | 2 +- crates/lsp/src/lsp.rs | 4 ++ crates/project/Cargo.toml | 1 + crates/project/src/lsp_command.rs | 48 ++++++++++++++++++++--- crates/project/src/project.rs | 14 +++++-- 7 files changed, 102 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94fa1d8473..0a4474b1e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 0cb8cace92..a7cfba7813 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -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, HighlightStyle)>, + pub contents: Vec, } 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) { - // 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 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 { - text = None; + 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| { diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index f13088f997..fbc8182d30 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -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() } diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index d5af202516..d22a59e48f 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -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!({ diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 1fb989ee9c..04597c0a3a 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -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"] } diff --git a/crates/project/src/lsp_command.rs b/crates/project/src/lsp_command.rs index a779c01d75..4fefc80c28 100644 --- a/crates/project/src/lsp_command.rs +++ b/crates/project/src/lsp_command.rs @@ -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, + _: ModelHandle, buffer: ModelHandle, mut cx: AsyncAppContext, ) -> Result { diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 07157c65f7..12f4e0a06f 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -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, HighlightId)>, +} + #[derive(Debug)] pub struct Hover { - pub contents: lsp::HoverContents, + pub contents: Vec, pub range: Option>, }